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());
104 cfg.id = this.id || Roo.id();
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;
129 this.el = ct.createChild(cfg, position);
132 this.tooltipEl().attr('tooltip', this.tooltip);
135 if(this.tabIndex !== undefined){
136 this.el.dom.setAttribute('tabIndex', this.tabIndex);
143 * Fetch the element to add children to
144 * @return {Roo.Element} defaults to this.el
146 getChildContainer : function()
151 * Fetch the element to display the tooltip on.
152 * @return {Roo.Element} defaults to this.el
154 tooltipEl : function()
159 addxtype : function(tree,cntr)
163 cn = Roo.factory(tree);
165 cn.parentType = this.xtype; //??
166 cn.parentId = this.id;
168 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
169 if (typeof(cn.container_method) == 'string') {
170 cntr = cn.container_method;
174 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
176 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
178 var build_from_html = Roo.XComponent.build_from_html;
180 var is_body = (tree.xtype == 'Body') ;
182 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
184 var self_cntr_el = Roo.get(this[cntr](false));
186 // do not try and build conditional elements
187 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
191 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
192 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
193 return this.addxtypeChild(tree,cntr);
196 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
199 return this.addxtypeChild(Roo.apply({}, tree),cntr);
202 Roo.log('skipping render');
208 if (!build_from_html) {
212 // this i think handles overlaying multiple children of the same type
213 // with the sam eelement.. - which might be buggy..
215 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
221 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
225 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
230 addxtypeChild : function (tree, cntr)
232 Roo.debug && Roo.log('addxtypeChild:' + cntr);
234 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
237 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
238 (typeof(tree['flexy:foreach']) != 'undefined');
242 skip_children = false;
243 // render the element if it's not BODY.
244 if (tree.xtype != 'Body') {
246 cn = Roo.factory(tree);
248 cn.parentType = this.xtype; //??
249 cn.parentId = this.id;
251 var build_from_html = Roo.XComponent.build_from_html;
254 // does the container contain child eleemnts with 'xtype' attributes.
255 // that match this xtype..
256 // note - when we render we create these as well..
257 // so we should check to see if body has xtype set.
258 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
260 var self_cntr_el = Roo.get(this[cntr](false));
261 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
263 //Roo.log(Roo.XComponent.build_from_html);
264 //Roo.log("got echild:");
267 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
268 // and are not displayed -this causes this to use up the wrong element when matching.
269 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
272 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
273 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
279 //echild.dom.removeAttribute('xtype');
281 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
282 Roo.debug && Roo.log(self_cntr_el);
283 Roo.debug && Roo.log(echild);
284 Roo.debug && Roo.log(cn);
290 // if object has flexy:if - then it may or may not be rendered.
291 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
292 // skip a flexy if element.
293 Roo.debug && Roo.log('skipping render');
294 Roo.debug && Roo.log(tree);
296 Roo.debug && Roo.log('skipping all children');
297 skip_children = true;
302 // actually if flexy:foreach is found, we really want to create
303 // multiple copies here...
305 //Roo.log(this[cntr]());
306 cn.render(this[cntr](true));
308 // then add the element..
316 if (typeof (tree.menu) != 'undefined') {
317 tree.menu.parentType = cn.xtype;
318 tree.menu.triggerEl = cn.el;
319 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
323 if (!tree.items || !tree.items.length) {
327 var items = tree.items;
330 //Roo.log(items.length);
332 if (!skip_children) {
333 for(var i =0;i < items.length;i++) {
334 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
340 this.fireEvent('childrenrendered', this);
345 * Show a component - removes 'hidden' class
349 this.el.removeClass('hidden');
352 * Hide a component - adds 'hidden' class
356 if (!this.el.hasClass('hidden')) {
357 this.el.addClass('hidden');
371 * @class Roo.bootstrap.Body
372 * @extends Roo.bootstrap.Component
373 * Bootstrap Body class
377 * @param {Object} config The config object
380 Roo.bootstrap.Body = function(config){
381 Roo.bootstrap.Body.superclass.constructor.call(this, config);
382 this.el = Roo.get(document.body);
383 if (this.cls && this.cls.length) {
384 Roo.get(document.body).addClass(this.cls);
388 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
393 onRender : function(ct, position)
395 /* Roo.log("Roo.bootstrap.Body - onRender");
396 if (this.cls && this.cls.length) {
397 Roo.get(document.body).addClass(this.cls);
417 * @class Roo.bootstrap.ButtonGroup
418 * @extends Roo.bootstrap.Component
419 * Bootstrap ButtonGroup class
420 * @cfg {String} size lg | sm | xs (default empty normal)
421 * @cfg {String} align vertical | justified (default none)
422 * @cfg {String} direction up | down (default down)
423 * @cfg {Boolean} toolbar false | true
424 * @cfg {Boolean} btn true | false
429 * @param {Object} config The config object
432 Roo.bootstrap.ButtonGroup = function(config){
433 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
436 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
444 getAutoCreate : function(){
450 cfg.html = this.html || cfg.html;
461 if (['vertical','justified'].indexOf(this.align)!==-1) {
462 cfg.cls = 'btn-group-' + this.align;
464 if (this.align == 'justified') {
465 console.log(this.items);
469 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
470 cfg.cls += ' btn-group-' + this.size;
473 if (this.direction == 'up') {
474 cfg.cls += ' dropup' ;
490 * @class Roo.bootstrap.Button
491 * @extends Roo.bootstrap.Component
492 * Bootstrap Button class
493 * @cfg {String} html The button content
494 * @cfg {String} weight ( primary | success | info | warning | danger | link ) default
495 * @cfg {String} size ( lg | sm | xs)
496 * @cfg {String} tag ( a | input | submit)
497 * @cfg {String} href empty or href
498 * @cfg {Boolean} disabled default false;
499 * @cfg {Boolean} isClose default false;
500 * @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)
501 * @cfg {String} badge text for badge
502 * @cfg {String} theme default
503 * @cfg {Boolean} inverse
504 * @cfg {Boolean} toggle
505 * @cfg {String} ontext text for on toggle state
506 * @cfg {String} offtext text for off toggle state
507 * @cfg {Boolean} defaulton
508 * @cfg {Boolean} preventDefault default true
509 * @cfg {Boolean} removeClass remove the standard class..
510 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
513 * Create a new button
514 * @param {Object} config The config object
518 Roo.bootstrap.Button = function(config){
519 Roo.bootstrap.Button.superclass.constructor.call(this, config);
524 * When a butotn is pressed
525 * @param {Roo.bootstrap.Button} this
526 * @param {Roo.EventObject} e
531 * After the button has been toggles
532 * @param {Roo.EventObject} e
533 * @param {boolean} pressed (also available as button.pressed)
539 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
557 preventDefault: true,
566 getAutoCreate : function(){
574 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
575 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
580 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
582 if (this.toggle == true) {
585 cls: 'slider-frame roo-button',
590 'data-off-text':'OFF',
591 cls: 'slider-button',
597 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
598 cfg.cls += ' '+this.weight;
607 cfg["aria-hidden"] = true;
609 cfg.html = "×";
615 if (this.theme==='default') {
616 cfg.cls = 'btn roo-button';
618 //if (this.parentType != 'Navbar') {
619 this.weight = this.weight.length ? this.weight : 'default';
621 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
623 cfg.cls += ' btn-' + this.weight;
625 } else if (this.theme==='glow') {
628 cfg.cls = 'btn-glow roo-button';
630 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
632 cfg.cls += ' ' + this.weight;
638 this.cls += ' inverse';
643 cfg.cls += ' active';
647 cfg.disabled = 'disabled';
651 Roo.log('changing to ul' );
653 this.glyphicon = 'caret';
656 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
658 //gsRoo.log(this.parentType);
659 if (this.parentType === 'Navbar' && !this.parent().bar) {
660 Roo.log('changing to li?');
669 href : this.href || '#'
672 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
673 cfg.cls += ' dropdown';
680 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
682 if (this.glyphicon) {
683 cfg.html = ' ' + cfg.html;
688 cls: 'glyphicon glyphicon-' + this.glyphicon
698 // cfg.cls='btn roo-button';
702 var value = cfg.html;
707 cls: 'glyphicon glyphicon-' + this.glyphicon,
726 cfg.cls += ' dropdown';
727 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
730 if (cfg.tag !== 'a' && this.href !== '') {
731 throw "Tag must be a to set href.";
732 } else if (this.href.length > 0) {
733 cfg.href = this.href;
736 if(this.removeClass){
741 cfg.target = this.target;
746 initEvents: function() {
747 // Roo.log('init events?');
748 // Roo.log(this.el.dom);
751 if (typeof (this.menu) != 'undefined') {
752 this.menu.parentType = this.xtype;
753 this.menu.triggerEl = this.el;
754 this.addxtype(Roo.apply({}, this.menu));
758 if (this.el.hasClass('roo-button')) {
759 this.el.on('click', this.onClick, this);
761 this.el.select('.roo-button').on('click', this.onClick, this);
764 if(this.removeClass){
765 this.el.on('click', this.onClick, this);
768 this.el.enableDisplayMode();
771 onClick : function(e)
778 Roo.log('button on click ');
779 if(this.preventDefault){
782 if (this.pressed === true || this.pressed === false) {
783 this.pressed = !this.pressed;
784 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
785 this.fireEvent('toggle', this, e, this.pressed);
789 this.fireEvent('click', this, e);
793 * Enables this button
797 this.disabled = false;
798 this.el.removeClass('disabled');
802 * Disable this button
806 this.disabled = true;
807 this.el.addClass('disabled');
810 * sets the active state on/off,
811 * @param {Boolean} state (optional) Force a particular state
813 setActive : function(v) {
815 this.el[v ? 'addClass' : 'removeClass']('active');
818 * toggles the current active state
820 toggleActive : function()
822 var active = this.el.hasClass('active');
823 this.setActive(!active);
827 setText : function(str)
829 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
833 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
856 * @class Roo.bootstrap.Column
857 * @extends Roo.bootstrap.Component
858 * Bootstrap Column class
859 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
860 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
861 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
862 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
863 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
864 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
865 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
866 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
869 * @cfg {Boolean} hidden (true|false) hide the element
870 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
871 * @cfg {String} fa (ban|check|...) font awesome icon
872 * @cfg {Number} fasize (1|2|....) font awsome size
874 * @cfg {String} icon (info-sign|check|...) glyphicon name
876 * @cfg {String} html content of column.
879 * Create a new Column
880 * @param {Object} config The config object
883 Roo.bootstrap.Column = function(config){
884 Roo.bootstrap.Column.superclass.constructor.call(this, config);
887 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
905 getAutoCreate : function(){
906 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
914 ['xs','sm','md','lg'].map(function(size){
915 //Roo.log( size + ':' + settings[size]);
917 if (settings[size+'off'] !== false) {
918 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
921 if (settings[size] === false) {
924 Roo.log(settings[size]);
925 if (!settings[size]) { // 0 = hidden
926 cfg.cls += ' hidden-' + size;
929 cfg.cls += ' col-' + size + '-' + settings[size];
934 cfg.cls += ' hidden';
937 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
938 cfg.cls +=' alert alert-' + this.alert;
942 if (this.html.length) {
943 cfg.html = this.html;
947 if (this.fasize > 1) {
948 fasize = ' fa-' + this.fasize + 'x';
950 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
955 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
974 * @class Roo.bootstrap.Container
975 * @extends Roo.bootstrap.Component
976 * Bootstrap Container class
977 * @cfg {Boolean} jumbotron is it a jumbotron element
978 * @cfg {String} html content of element
979 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
980 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
981 * @cfg {String} header content of header (for panel)
982 * @cfg {String} footer content of footer (for panel)
983 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
984 * @cfg {String} tag (header|aside|section) type of HTML tag.
985 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
986 * @cfg {String} fa (ban|check|...) font awesome icon
987 * @cfg {String} icon (info-sign|check|...) glyphicon name
988 * @cfg {Boolean} hidden (true|false) hide the element
989 * @cfg {Boolean} expandable (true|false) default false
990 * @cfg {String} rheader contet on the right of header
994 * Create a new Container
995 * @param {Object} config The config object
998 Roo.bootstrap.Container = function(config){
999 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1005 * After the panel has been expand
1007 * @param {Roo.bootstrap.Container} this
1012 * After the panel has been collapsed
1014 * @param {Roo.bootstrap.Container} this
1020 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1036 getChildContainer : function() {
1042 if (this.panel.length) {
1043 return this.el.select('.panel-body',true).first();
1050 getAutoCreate : function(){
1053 tag : this.tag || 'div',
1057 if (this.jumbotron) {
1058 cfg.cls = 'jumbotron';
1063 // - this is applied by the parent..
1065 // cfg.cls = this.cls + '';
1068 if (this.sticky.length) {
1070 var bd = Roo.get(document.body);
1071 if (!bd.hasClass('bootstrap-sticky')) {
1072 bd.addClass('bootstrap-sticky');
1073 Roo.select('html',true).setStyle('height', '100%');
1076 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1080 if (this.well.length) {
1081 switch (this.well) {
1084 cfg.cls +=' well well-' +this.well;
1093 cfg.cls += ' hidden';
1097 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1098 cfg.cls +=' alert alert-' + this.alert;
1103 if (this.panel.length) {
1104 cfg.cls += ' panel panel-' + this.panel;
1106 if (this.header.length) {
1110 if(this.expandable){
1120 cls : 'panel-title',
1125 cls: 'panel-header-right',
1131 cls : 'panel-heading',
1144 if (this.footer.length) {
1146 cls : 'panel-footer',
1155 body.html = this.html || cfg.html;
1156 // prefix with the icons..
1158 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1161 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1166 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1167 cfg.cls = 'container';
1173 initEvents: function()
1175 var toggleEl = this.toggleEl();
1181 toggleEl.on('click', this.onToggleClick, this);
1184 onToggleClick : function()
1186 var toggleEl = this.toggleEl();
1192 if(toggleEl.hasClass('fa-minus')){
1203 if(this.fireEvent('expand', this)) {
1204 this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1206 var toggleEl = this.toggleEl();
1212 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1217 collapse : function()
1219 if(this.fireEvent('collapse', this)) {
1220 this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1222 var toggleEl = this.toggleEl();
1228 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1232 toggleEl : function()
1234 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1238 return this.el.select('.panel-heading .fa',true).first();
1241 titleEl : function()
1243 if(!this.el || !this.panel.length || !this.header.length){
1247 return this.el.select('.panel-title',true).first();
1250 setTitle : function(v)
1252 var titleEl = this.titleEl();
1258 titleEl.dom.innerHTML = v;
1261 getTitle : function()
1264 var titleEl = this.titleEl();
1270 return titleEl.dom.innerHTML;
1273 setRightTitle : function(v)
1275 var t = this.el.select('.panel-header-right',true).first();
1281 t.dom.innerHTML = v;
1295 * @class Roo.bootstrap.Img
1296 * @extends Roo.bootstrap.Component
1297 * Bootstrap Img class
1298 * @cfg {Boolean} imgResponsive false | true
1299 * @cfg {String} border rounded | circle | thumbnail
1300 * @cfg {String} src image source
1301 * @cfg {String} alt image alternative text
1302 * @cfg {String} href a tag href
1303 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1306 * Create a new Input
1307 * @param {Object} config The config object
1310 Roo.bootstrap.Img = function(config){
1311 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1317 * The img click event for the img.
1318 * @param {Roo.EventObject} e
1324 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1326 imgResponsive: true,
1332 getAutoCreate : function(){
1336 cls: (this.imgResponsive) ? 'img-responsive' : '',
1340 cfg.html = this.html || cfg.html;
1342 cfg.src = this.src || cfg.src;
1344 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1345 cfg.cls += ' img-' + this.border;
1362 a.target = this.target;
1368 return (this.href) ? a : cfg;
1371 initEvents: function() {
1374 this.el.on('click', this.onClick, this);
1378 onClick : function(e)
1380 Roo.log('img onclick');
1381 this.fireEvent('click', this, e);
1395 * @class Roo.bootstrap.Link
1396 * @extends Roo.bootstrap.Component
1397 * Bootstrap Link Class
1398 * @cfg {String} alt image alternative text
1399 * @cfg {String} href a tag href
1400 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1401 * @cfg {String} html the content of the link.
1402 * @cfg {String} anchor name for the anchor link
1404 * @cfg {Boolean} preventDefault (true | false) default false
1408 * Create a new Input
1409 * @param {Object} config The config object
1412 Roo.bootstrap.Link = function(config){
1413 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1419 * The img click event for the img.
1420 * @param {Roo.EventObject} e
1426 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1430 preventDefault: false,
1434 getAutoCreate : function()
1440 // anchor's do not require html/href...
1441 if (this.anchor === false) {
1442 cfg.html = this.html || 'html-missing';
1443 cfg.href = this.href || '#';
1445 cfg.name = this.anchor;
1446 if (this.html !== false) {
1447 cfg.html = this.html;
1449 if (this.href !== false) {
1450 cfg.href = this.href;
1454 if(this.alt !== false){
1459 if(this.target !== false) {
1460 cfg.target = this.target;
1466 initEvents: function() {
1468 if(!this.href || this.preventDefault){
1469 this.el.on('click', this.onClick, this);
1473 onClick : function(e)
1475 if(this.preventDefault){
1478 //Roo.log('img onclick');
1479 this.fireEvent('click', this, e);
1492 * @class Roo.bootstrap.Header
1493 * @extends Roo.bootstrap.Component
1494 * Bootstrap Header class
1495 * @cfg {String} html content of header
1496 * @cfg {Number} level (1|2|3|4|5|6) default 1
1499 * Create a new Header
1500 * @param {Object} config The config object
1504 Roo.bootstrap.Header = function(config){
1505 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1508 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1516 getAutoCreate : function(){
1521 tag: 'h' + (1 *this.level),
1522 html: this.html || ''
1534 * Ext JS Library 1.1.1
1535 * Copyright(c) 2006-2007, Ext JS, LLC.
1537 * Originally Released Under LGPL - original licence link has changed is not relivant.
1540 * <script type="text/javascript">
1544 * @class Roo.bootstrap.MenuMgr
1545 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1548 Roo.bootstrap.MenuMgr = function(){
1549 var menus, active, groups = {}, attached = false, lastShow = new Date();
1551 // private - called when first menu is created
1554 active = new Roo.util.MixedCollection();
1555 Roo.get(document).addKeyListener(27, function(){
1556 if(active.length > 0){
1564 if(active && active.length > 0){
1565 var c = active.clone();
1575 if(active.length < 1){
1576 Roo.get(document).un("mouseup", onMouseDown);
1584 var last = active.last();
1585 lastShow = new Date();
1588 Roo.get(document).on("mouseup", onMouseDown);
1593 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1594 m.parentMenu.activeChild = m;
1595 }else if(last && last.isVisible()){
1596 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1601 function onBeforeHide(m){
1603 m.activeChild.hide();
1605 if(m.autoHideTimer){
1606 clearTimeout(m.autoHideTimer);
1607 delete m.autoHideTimer;
1612 function onBeforeShow(m){
1613 var pm = m.parentMenu;
1614 if(!pm && !m.allowOtherMenus){
1616 }else if(pm && pm.activeChild && active != m){
1617 pm.activeChild.hide();
1622 function onMouseDown(e){
1623 Roo.log("on MouseDown");
1624 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1632 function onBeforeCheck(mi, state){
1634 var g = groups[mi.group];
1635 for(var i = 0, l = g.length; i < l; i++){
1637 g[i].setChecked(false);
1646 * Hides all menus that are currently visible
1648 hideAll : function(){
1653 register : function(menu){
1657 menus[menu.id] = menu;
1658 menu.on("beforehide", onBeforeHide);
1659 menu.on("hide", onHide);
1660 menu.on("beforeshow", onBeforeShow);
1661 menu.on("show", onShow);
1663 if(g && menu.events["checkchange"]){
1667 groups[g].push(menu);
1668 menu.on("checkchange", onCheck);
1673 * Returns a {@link Roo.menu.Menu} object
1674 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1675 * be used to generate and return a new Menu instance.
1677 get : function(menu){
1678 if(typeof menu == "string"){ // menu id
1680 }else if(menu.events){ // menu instance
1683 /*else if(typeof menu.length == 'number'){ // array of menu items?
1684 return new Roo.bootstrap.Menu({items:menu});
1685 }else{ // otherwise, must be a config
1686 return new Roo.bootstrap.Menu(menu);
1693 unregister : function(menu){
1694 delete menus[menu.id];
1695 menu.un("beforehide", onBeforeHide);
1696 menu.un("hide", onHide);
1697 menu.un("beforeshow", onBeforeShow);
1698 menu.un("show", onShow);
1700 if(g && menu.events["checkchange"]){
1701 groups[g].remove(menu);
1702 menu.un("checkchange", onCheck);
1707 registerCheckable : function(menuItem){
1708 var g = menuItem.group;
1713 groups[g].push(menuItem);
1714 menuItem.on("beforecheckchange", onBeforeCheck);
1719 unregisterCheckable : function(menuItem){
1720 var g = menuItem.group;
1722 groups[g].remove(menuItem);
1723 menuItem.un("beforecheckchange", onBeforeCheck);
1735 * @class Roo.bootstrap.Menu
1736 * @extends Roo.bootstrap.Component
1737 * Bootstrap Menu class - container for MenuItems
1738 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1742 * @param {Object} config The config object
1746 Roo.bootstrap.Menu = function(config){
1747 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1748 if (this.registerMenu) {
1749 Roo.bootstrap.MenuMgr.register(this);
1754 * Fires before this menu is displayed
1755 * @param {Roo.menu.Menu} this
1760 * Fires before this menu is hidden
1761 * @param {Roo.menu.Menu} this
1766 * Fires after this menu is displayed
1767 * @param {Roo.menu.Menu} this
1772 * Fires after this menu is hidden
1773 * @param {Roo.menu.Menu} this
1778 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1779 * @param {Roo.menu.Menu} this
1780 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1781 * @param {Roo.EventObject} e
1786 * Fires when the mouse is hovering over this menu
1787 * @param {Roo.menu.Menu} this
1788 * @param {Roo.EventObject} e
1789 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1794 * Fires when the mouse exits this menu
1795 * @param {Roo.menu.Menu} this
1796 * @param {Roo.EventObject} e
1797 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1802 * Fires when a menu item contained in this menu is clicked
1803 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1804 * @param {Roo.EventObject} e
1808 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1811 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1815 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1818 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1820 registerMenu : true,
1822 menuItems :false, // stores the menu items..
1828 getChildContainer : function() {
1832 getAutoCreate : function(){
1834 //if (['right'].indexOf(this.align)!==-1) {
1835 // cfg.cn[1].cls += ' pull-right'
1841 cls : 'dropdown-menu' ,
1842 style : 'z-index:1000'
1846 if (this.type === 'submenu') {
1847 cfg.cls = 'submenu active';
1849 if (this.type === 'treeview') {
1850 cfg.cls = 'treeview-menu';
1855 initEvents : function() {
1857 // Roo.log("ADD event");
1858 // Roo.log(this.triggerEl.dom);
1859 this.triggerEl.on('click', this.onTriggerPress, this);
1860 this.triggerEl.addClass('dropdown-toggle');
1861 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1863 this.el.on("mouseover", this.onMouseOver, this);
1864 this.el.on("mouseout", this.onMouseOut, this);
1868 findTargetItem : function(e){
1869 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1873 //Roo.log(t); Roo.log(t.id);
1875 //Roo.log(this.menuitems);
1876 return this.menuitems.get(t.id);
1878 //return this.items.get(t.menuItemId);
1883 onClick : function(e){
1884 Roo.log("menu.onClick");
1885 var t = this.findTargetItem(e);
1886 if(!t || t.isContainer){
1891 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1892 if(t == this.activeItem && t.shouldDeactivate(e)){
1893 this.activeItem.deactivate();
1894 delete this.activeItem;
1898 this.setActiveItem(t, true);
1906 Roo.log('pass click event');
1910 this.fireEvent("click", this, t, e);
1914 onMouseOver : function(e){
1915 var t = this.findTargetItem(e);
1918 // if(t.canActivate && !t.disabled){
1919 // this.setActiveItem(t, true);
1923 this.fireEvent("mouseover", this, e, t);
1925 isVisible : function(){
1926 return !this.hidden;
1928 onMouseOut : function(e){
1929 var t = this.findTargetItem(e);
1932 // if(t == this.activeItem && t.shouldDeactivate(e)){
1933 // this.activeItem.deactivate();
1934 // delete this.activeItem;
1937 this.fireEvent("mouseout", this, e, t);
1942 * Displays this menu relative to another element
1943 * @param {String/HTMLElement/Roo.Element} element The element to align to
1944 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1945 * the element (defaults to this.defaultAlign)
1946 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1948 show : function(el, pos, parentMenu){
1949 this.parentMenu = parentMenu;
1953 this.fireEvent("beforeshow", this);
1954 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1957 * Displays this menu at a specific xy position
1958 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1959 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1961 showAt : function(xy, parentMenu, /* private: */_e){
1962 this.parentMenu = parentMenu;
1967 this.fireEvent("beforeshow", this);
1968 //xy = this.el.adjustForConstraints(xy);
1972 this.hideMenuItems();
1973 this.hidden = false;
1974 this.triggerEl.addClass('open');
1976 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
1977 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
1982 this.fireEvent("show", this);
1988 this.doFocus.defer(50, this);
1992 doFocus : function(){
1994 this.focusEl.focus();
1999 * Hides this menu and optionally all parent menus
2000 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2002 hide : function(deep){
2004 this.hideMenuItems();
2005 if(this.el && this.isVisible()){
2006 this.fireEvent("beforehide", this);
2007 if(this.activeItem){
2008 this.activeItem.deactivate();
2009 this.activeItem = null;
2011 this.triggerEl.removeClass('open');;
2013 this.fireEvent("hide", this);
2015 if(deep === true && this.parentMenu){
2016 this.parentMenu.hide(true);
2020 onTriggerPress : function(e)
2023 Roo.log('trigger press');
2024 //Roo.log(e.getTarget());
2025 // Roo.log(this.triggerEl.dom);
2026 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
2029 if (this.isVisible()) {
2033 this.show(this.triggerEl, false, false);
2042 hideMenuItems : function()
2044 //$(backdrop).remove()
2045 Roo.select('.open',true).each(function(aa) {
2047 aa.removeClass('open');
2048 //var parent = getParent($(this))
2049 //var relatedTarget = { relatedTarget: this }
2051 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2052 //if (e.isDefaultPrevented()) return
2053 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2056 addxtypeChild : function (tree, cntr) {
2057 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2059 this.menuitems.add(comp);
2080 * @class Roo.bootstrap.MenuItem
2081 * @extends Roo.bootstrap.Component
2082 * Bootstrap MenuItem class
2083 * @cfg {String} html the menu label
2084 * @cfg {String} href the link
2085 * @cfg {Boolean} preventDefault (true | false) default true
2086 * @cfg {Boolean} isContainer (true | false) default false
2090 * Create a new MenuItem
2091 * @param {Object} config The config object
2095 Roo.bootstrap.MenuItem = function(config){
2096 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2101 * The raw click event for the entire grid.
2102 * @param {Roo.bootstrap.MenuItem} this
2103 * @param {Roo.EventObject} e
2109 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2113 preventDefault: true,
2114 isContainer : false,
2116 getAutoCreate : function(){
2118 if(this.isContainer){
2121 cls: 'dropdown-menu-item'
2127 cls: 'dropdown-menu-item',
2136 if (this.parent().type == 'treeview') {
2137 cfg.cls = 'treeview-menu';
2140 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2141 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2145 initEvents: function() {
2147 //this.el.select('a').on('click', this.onClick, this);
2150 onClick : function(e)
2152 Roo.log('item on click ');
2153 //if(this.preventDefault){
2154 // e.preventDefault();
2156 //this.parent().hideMenuItems();
2158 this.fireEvent('click', this, e);
2177 * @class Roo.bootstrap.MenuSeparator
2178 * @extends Roo.bootstrap.Component
2179 * Bootstrap MenuSeparator class
2182 * Create a new MenuItem
2183 * @param {Object} config The config object
2187 Roo.bootstrap.MenuSeparator = function(config){
2188 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2191 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2193 getAutoCreate : function(){
2212 * @class Roo.bootstrap.Modal
2213 * @extends Roo.bootstrap.Component
2214 * Bootstrap Modal class
2215 * @cfg {String} title Title of dialog
2216 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2217 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2218 * @cfg {Boolean} specificTitle default false
2219 * @cfg {Array} buttons Array of buttons or standard button set..
2220 * @cfg {String} buttonPosition (left|right|center) default right
2221 * @cfg {Boolean} animate default true
2222 * @cfg {Boolean} allow_close default true
2225 * Create a new Modal Dialog
2226 * @param {Object} config The config object
2229 Roo.bootstrap.Modal = function(config){
2230 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2235 * The raw btnclick event for the button
2236 * @param {Roo.EventObject} e
2240 this.buttons = this.buttons || [];
2243 this.tmpl = Roo.factory(this.tmpl);
2248 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2250 title : 'test dialog',
2260 specificTitle: false,
2262 buttonPosition: 'right',
2276 onRender : function(ct, position)
2278 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2281 var cfg = Roo.apply({}, this.getAutoCreate());
2284 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2286 //if (!cfg.name.length) {
2290 cfg.cls += ' ' + this.cls;
2293 cfg.style = this.style;
2295 this.el = Roo.get(document.body).createChild(cfg, position);
2297 //var type = this.el.dom.type;
2302 if(this.tabIndex !== undefined){
2303 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2307 this.bodyEl = this.el.select('.modal-body',true).first();
2308 this.closeEl = this.el.select('.modal-header .close', true).first();
2309 this.footerEl = this.el.select('.modal-footer',true).first();
2310 this.titleEl = this.el.select('.modal-title',true).first();
2314 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2315 this.maskEl.enableDisplayMode("block");
2317 //this.el.addClass("x-dlg-modal");
2319 if (this.buttons.length) {
2320 Roo.each(this.buttons, function(bb) {
2321 b = Roo.apply({}, bb);
2322 b.xns = b.xns || Roo.bootstrap;
2323 b.xtype = b.xtype || 'Button';
2324 if (typeof(b.listeners) == 'undefined') {
2325 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2328 var btn = Roo.factory(b);
2330 btn.onRender(this.el.select('.modal-footer div').first());
2334 // render the children.
2337 if(typeof(this.items) != 'undefined'){
2338 var items = this.items;
2341 for(var i =0;i < items.length;i++) {
2342 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2346 this.items = nitems;
2348 // where are these used - they used to be body/close/footer
2352 //this.el.addClass([this.fieldClass, this.cls]);
2355 getAutoCreate : function(){
2360 html : this.html || ''
2365 cls : 'modal-title',
2369 if(this.specificTitle){
2375 if (this.allow_close) {
2386 style : 'display: none',
2389 cls: "modal-dialog",
2392 cls : "modal-content",
2395 cls : 'modal-header',
2400 cls : 'modal-footer',
2404 cls: 'btn-' + this.buttonPosition
2421 modal.cls += ' fade';
2427 getChildContainer : function() {
2432 getButtonContainer : function() {
2433 return this.el.select('.modal-footer div',true).first();
2436 initEvents : function()
2438 if (this.allow_close) {
2439 this.closeEl.on('click', this.hide, this);
2445 if (!this.rendered) {
2449 this.el.setStyle('display', 'block');
2453 (function(){ _this.el.addClass('in'); }).defer(50);
2455 this.el.addClass('in');
2458 // not sure how we can show data in here..
2460 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2463 Roo.get(document.body).addClass("x-body-masked");
2464 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2466 this.el.setStyle('zIndex', '10001');
2468 this.fireEvent('show', this);
2475 Roo.get(document.body).removeClass("x-body-masked");
2476 this.el.removeClass('in');
2480 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2482 this.el.setStyle('display', 'none');
2485 this.fireEvent('hide', this);
2488 addButton : function(str, cb)
2492 var b = Roo.apply({}, { html : str } );
2493 b.xns = b.xns || Roo.bootstrap;
2494 b.xtype = b.xtype || 'Button';
2495 if (typeof(b.listeners) == 'undefined') {
2496 b.listeners = { click : cb.createDelegate(this) };
2499 var btn = Roo.factory(b);
2501 btn.onRender(this.el.select('.modal-footer div').first());
2507 setDefaultButton : function(btn)
2509 //this.el.select('.modal-footer').()
2511 resizeTo: function(w,h)
2515 setContentSize : function(w, h)
2519 onButtonClick: function(btn,e)
2522 this.fireEvent('btnclick', btn.name, e);
2525 * Set the title of the Dialog
2526 * @param {String} str new Title
2528 setTitle: function(str) {
2529 this.titleEl.dom.innerHTML = str;
2532 * Set the body of the Dialog
2533 * @param {String} str new Title
2535 setBody: function(str) {
2536 this.bodyEl.dom.innerHTML = str;
2539 * Set the body of the Dialog using the template
2540 * @param {Obj} data - apply this data to the template and replace the body contents.
2542 applyBody: function(obj)
2545 Roo.log("Error - using apply Body without a template");
2548 this.tmpl.overwrite(this.bodyEl, obj);
2554 Roo.apply(Roo.bootstrap.Modal, {
2556 * Button config that displays a single OK button
2565 * Button config that displays Yes and No buttons
2581 * Button config that displays OK and Cancel buttons
2596 * Button config that displays Yes, No and Cancel buttons
2619 * messagebox - can be used as a replace
2623 * @class Roo.MessageBox
2624 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2628 Roo.Msg.alert('Status', 'Changes saved successfully.');
2630 // Prompt for user data:
2631 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2633 // process text value...
2637 // Show a dialog using config options:
2639 title:'Save Changes?',
2640 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2641 buttons: Roo.Msg.YESNOCANCEL,
2648 Roo.bootstrap.MessageBox = function(){
2649 var dlg, opt, mask, waitTimer;
2650 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2651 var buttons, activeTextEl, bwidth;
2655 var handleButton = function(button){
2657 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2661 var handleHide = function(){
2663 dlg.el.removeClass(opt.cls);
2666 // Roo.TaskMgr.stop(waitTimer);
2667 // waitTimer = null;
2672 var updateButtons = function(b){
2675 buttons["ok"].hide();
2676 buttons["cancel"].hide();
2677 buttons["yes"].hide();
2678 buttons["no"].hide();
2679 //dlg.footer.dom.style.display = 'none';
2682 dlg.footerEl.dom.style.display = '';
2683 for(var k in buttons){
2684 if(typeof buttons[k] != "function"){
2687 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2688 width += buttons[k].el.getWidth()+15;
2698 var handleEsc = function(d, k, e){
2699 if(opt && opt.closable !== false){
2709 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2710 * @return {Roo.BasicDialog} The BasicDialog element
2712 getDialog : function(){
2714 dlg = new Roo.bootstrap.Modal( {
2717 //constraintoviewport:false,
2719 //collapsible : false,
2724 //buttonAlign:"center",
2725 closeClick : function(){
2726 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2729 handleButton("cancel");
2734 dlg.on("hide", handleHide);
2736 //dlg.addKeyListener(27, handleEsc);
2738 this.buttons = buttons;
2739 var bt = this.buttonText;
2740 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2741 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2742 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2743 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2745 bodyEl = dlg.bodyEl.createChild({
2747 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2748 '<textarea class="roo-mb-textarea"></textarea>' +
2749 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2751 msgEl = bodyEl.dom.firstChild;
2752 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2753 textboxEl.enableDisplayMode();
2754 textboxEl.addKeyListener([10,13], function(){
2755 if(dlg.isVisible() && opt && opt.buttons){
2758 }else if(opt.buttons.yes){
2759 handleButton("yes");
2763 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2764 textareaEl.enableDisplayMode();
2765 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2766 progressEl.enableDisplayMode();
2767 var pf = progressEl.dom.firstChild;
2769 pp = Roo.get(pf.firstChild);
2770 pp.setHeight(pf.offsetHeight);
2778 * Updates the message box body text
2779 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2780 * the XHTML-compliant non-breaking space character '&#160;')
2781 * @return {Roo.MessageBox} This message box
2783 updateText : function(text){
2784 if(!dlg.isVisible() && !opt.width){
2785 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2787 msgEl.innerHTML = text || ' ';
2789 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2790 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2792 Math.min(opt.width || cw , this.maxWidth),
2793 Math.max(opt.minWidth || this.minWidth, bwidth)
2796 activeTextEl.setWidth(w);
2798 if(dlg.isVisible()){
2799 dlg.fixedcenter = false;
2801 // to big, make it scroll. = But as usual stupid IE does not support
2804 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2805 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2806 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2808 bodyEl.dom.style.height = '';
2809 bodyEl.dom.style.overflowY = '';
2812 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2814 bodyEl.dom.style.overflowX = '';
2817 dlg.setContentSize(w, bodyEl.getHeight());
2818 if(dlg.isVisible()){
2819 dlg.fixedcenter = true;
2825 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2826 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2827 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2828 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2829 * @return {Roo.MessageBox} This message box
2831 updateProgress : function(value, text){
2833 this.updateText(text);
2835 if (pp) { // weird bug on my firefox - for some reason this is not defined
2836 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2842 * Returns true if the message box is currently displayed
2843 * @return {Boolean} True if the message box is visible, else false
2845 isVisible : function(){
2846 return dlg && dlg.isVisible();
2850 * Hides the message box if it is displayed
2853 if(this.isVisible()){
2859 * Displays a new message box, or reinitializes an existing message box, based on the config options
2860 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2861 * The following config object properties are supported:
2863 Property Type Description
2864 ---------- --------------- ------------------------------------------------------------------------------------
2865 animEl String/Element An id or Element from which the message box should animate as it opens and
2866 closes (defaults to undefined)
2867 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2868 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2869 closable Boolean False to hide the top-right close button (defaults to true). Note that
2870 progress and wait dialogs will ignore this property and always hide the
2871 close button as they can only be closed programmatically.
2872 cls String A custom CSS class to apply to the message box element
2873 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2874 displayed (defaults to 75)
2875 fn Function A callback function to execute after closing the dialog. The arguments to the
2876 function will be btn (the name of the button that was clicked, if applicable,
2877 e.g. "ok"), and text (the value of the active text field, if applicable).
2878 Progress and wait dialogs will ignore this option since they do not respond to
2879 user actions and can only be closed programmatically, so any required function
2880 should be called by the same code after it closes the dialog.
2881 icon String A CSS class that provides a background image to be used as an icon for
2882 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2883 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2884 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2885 modal Boolean False to allow user interaction with the page while the message box is
2886 displayed (defaults to true)
2887 msg String A string that will replace the existing message box body text (defaults
2888 to the XHTML-compliant non-breaking space character ' ')
2889 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2890 progress Boolean True to display a progress bar (defaults to false)
2891 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2892 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2893 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2894 title String The title text
2895 value String The string value to set into the active textbox element if displayed
2896 wait Boolean True to display a progress bar (defaults to false)
2897 width Number The width of the dialog in pixels
2904 msg: 'Please enter your address:',
2906 buttons: Roo.MessageBox.OKCANCEL,
2909 animEl: 'addAddressBtn'
2912 * @param {Object} config Configuration options
2913 * @return {Roo.MessageBox} This message box
2915 show : function(options)
2918 // this causes nightmares if you show one dialog after another
2919 // especially on callbacks..
2921 if(this.isVisible()){
2924 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2925 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2926 Roo.log("New Dialog Message:" + options.msg )
2927 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2928 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2931 var d = this.getDialog();
2933 d.setTitle(opt.title || " ");
2934 d.closeEl.setDisplayed(opt.closable !== false);
2935 activeTextEl = textboxEl;
2936 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2941 textareaEl.setHeight(typeof opt.multiline == "number" ?
2942 opt.multiline : this.defaultTextHeight);
2943 activeTextEl = textareaEl;
2952 progressEl.setDisplayed(opt.progress === true);
2953 this.updateProgress(0);
2954 activeTextEl.dom.value = opt.value || "";
2956 dlg.setDefaultButton(activeTextEl);
2958 var bs = opt.buttons;
2962 }else if(bs && bs.yes){
2963 db = buttons["yes"];
2965 dlg.setDefaultButton(db);
2967 bwidth = updateButtons(opt.buttons);
2968 this.updateText(opt.msg);
2970 d.el.addClass(opt.cls);
2972 d.proxyDrag = opt.proxyDrag === true;
2973 d.modal = opt.modal !== false;
2974 d.mask = opt.modal !== false ? mask : false;
2976 // force it to the end of the z-index stack so it gets a cursor in FF
2977 document.body.appendChild(dlg.el.dom);
2978 d.animateTarget = null;
2979 d.show(options.animEl);
2985 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2986 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2987 * and closing the message box when the process is complete.
2988 * @param {String} title The title bar text
2989 * @param {String} msg The message box body text
2990 * @return {Roo.MessageBox} This message box
2992 progress : function(title, msg){
2999 minWidth: this.minProgressWidth,
3006 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3007 * If a callback function is passed it will be called after the user clicks the button, and the
3008 * id of the button that was clicked will be passed as the only parameter to the callback
3009 * (could also be the top-right close button).
3010 * @param {String} title The title bar text
3011 * @param {String} msg The message box body text
3012 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3013 * @param {Object} scope (optional) The scope of the callback function
3014 * @return {Roo.MessageBox} This message box
3016 alert : function(title, msg, fn, scope){
3029 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3030 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3031 * You are responsible for closing the message box when the process is complete.
3032 * @param {String} msg The message box body text
3033 * @param {String} title (optional) The title bar text
3034 * @return {Roo.MessageBox} This message box
3036 wait : function(msg, title){
3047 waitTimer = Roo.TaskMgr.start({
3049 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3057 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3058 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3059 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3060 * @param {String} title The title bar text
3061 * @param {String} msg The message box body text
3062 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3063 * @param {Object} scope (optional) The scope of the callback function
3064 * @return {Roo.MessageBox} This message box
3066 confirm : function(title, msg, fn, scope){
3070 buttons: this.YESNO,
3079 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3080 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3081 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3082 * (could also be the top-right close button) and the text that was entered will be passed as the two
3083 * parameters to the callback.
3084 * @param {String} title The title bar text
3085 * @param {String} msg The message box body text
3086 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3087 * @param {Object} scope (optional) The scope of the callback function
3088 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3089 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3090 * @return {Roo.MessageBox} This message box
3092 prompt : function(title, msg, fn, scope, multiline){
3096 buttons: this.OKCANCEL,
3101 multiline: multiline,
3108 * Button config that displays a single OK button
3113 * Button config that displays Yes and No buttons
3116 YESNO : {yes:true, no:true},
3118 * Button config that displays OK and Cancel buttons
3121 OKCANCEL : {ok:true, cancel:true},
3123 * Button config that displays Yes, No and Cancel buttons
3126 YESNOCANCEL : {yes:true, no:true, cancel:true},
3129 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3132 defaultTextHeight : 75,
3134 * The maximum width in pixels of the message box (defaults to 600)
3139 * The minimum width in pixels of the message box (defaults to 100)
3144 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3145 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3148 minProgressWidth : 250,
3150 * An object containing the default button text strings that can be overriden for localized language support.
3151 * Supported properties are: ok, cancel, yes and no.
3152 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3165 * Shorthand for {@link Roo.MessageBox}
3167 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3168 Roo.Msg = Roo.Msg || Roo.MessageBox;
3177 * @class Roo.bootstrap.Navbar
3178 * @extends Roo.bootstrap.Component
3179 * Bootstrap Navbar class
3182 * Create a new Navbar
3183 * @param {Object} config The config object
3187 Roo.bootstrap.Navbar = function(config){
3188 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3192 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3201 getAutoCreate : function(){
3204 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3208 initEvents :function ()
3210 //Roo.log(this.el.select('.navbar-toggle',true));
3211 this.el.select('.navbar-toggle',true).on('click', function() {
3212 // Roo.log('click');
3213 this.el.select('.navbar-collapse',true).toggleClass('in');
3221 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3223 var size = this.el.getSize();
3224 this.maskEl.setSize(size.width, size.height);
3225 this.maskEl.enableDisplayMode("block");
3234 getChildContainer : function()
3236 if (this.el.select('.collapse').getCount()) {
3237 return this.el.select('.collapse',true).first();
3270 * @class Roo.bootstrap.NavSimplebar
3271 * @extends Roo.bootstrap.Navbar
3272 * Bootstrap Sidebar class
3274 * @cfg {Boolean} inverse is inverted color
3276 * @cfg {String} type (nav | pills | tabs)
3277 * @cfg {Boolean} arrangement stacked | justified
3278 * @cfg {String} align (left | right) alignment
3280 * @cfg {Boolean} main (true|false) main nav bar? default false
3281 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3283 * @cfg {String} tag (header|footer|nav|div) default is nav
3289 * Create a new Sidebar
3290 * @param {Object} config The config object
3294 Roo.bootstrap.NavSimplebar = function(config){
3295 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3298 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3314 getAutoCreate : function(){
3318 tag : this.tag || 'div',
3331 this.type = this.type || 'nav';
3332 if (['tabs','pills'].indexOf(this.type)!==-1) {
3333 cfg.cn[0].cls += ' nav-' + this.type
3337 if (this.type!=='nav') {
3338 Roo.log('nav type must be nav/tabs/pills')
3340 cfg.cn[0].cls += ' navbar-nav'
3346 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3347 cfg.cn[0].cls += ' nav-' + this.arrangement;
3351 if (this.align === 'right') {
3352 cfg.cn[0].cls += ' navbar-right';
3356 cfg.cls += ' navbar-inverse';
3383 * @class Roo.bootstrap.NavHeaderbar
3384 * @extends Roo.bootstrap.NavSimplebar
3385 * Bootstrap Sidebar class
3387 * @cfg {String} brand what is brand
3388 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3389 * @cfg {String} brand_href href of the brand
3390 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3391 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3392 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3393 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3396 * Create a new Sidebar
3397 * @param {Object} config The config object
3401 Roo.bootstrap.NavHeaderbar = function(config){
3402 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3406 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3413 desktopCenter : false,
3416 getAutoCreate : function(){
3419 tag: this.nav || 'nav',
3426 if (this.desktopCenter) {
3427 cn.push({cls : 'container', cn : []});
3434 cls: 'navbar-header',
3439 cls: 'navbar-toggle',
3440 'data-toggle': 'collapse',
3445 html: 'Toggle navigation'
3467 cls: 'collapse navbar-collapse',
3471 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3473 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3474 cfg.cls += ' navbar-' + this.position;
3476 // tag can override this..
3478 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3481 if (this.brand !== '') {
3484 href: this.brand_href ? this.brand_href : '#',
3485 cls: 'navbar-brand',
3493 cfg.cls += ' main-nav';
3501 getHeaderChildContainer : function()
3503 if (this.el.select('.navbar-header').getCount()) {
3504 return this.el.select('.navbar-header',true).first();
3507 return this.getChildContainer();
3511 initEvents : function()
3513 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3515 if (this.autohide) {
3520 Roo.get(document).on('scroll',function(e) {
3521 var ns = Roo.get(document).getScroll().top;
3522 var os = prevScroll;
3526 ft.removeClass('slideDown');
3527 ft.addClass('slideUp');
3530 ft.removeClass('slideUp');
3531 ft.addClass('slideDown');
3552 * @class Roo.bootstrap.NavSidebar
3553 * @extends Roo.bootstrap.Navbar
3554 * Bootstrap Sidebar class
3557 * Create a new Sidebar
3558 * @param {Object} config The config object
3562 Roo.bootstrap.NavSidebar = function(config){
3563 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3566 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3568 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3570 getAutoCreate : function(){
3575 cls: 'sidebar sidebar-nav'
3597 * @class Roo.bootstrap.NavGroup
3598 * @extends Roo.bootstrap.Component
3599 * Bootstrap NavGroup class
3600 * @cfg {String} align left | right
3601 * @cfg {Boolean} inverse false | true
3602 * @cfg {String} type (nav|pills|tab) default nav
3603 * @cfg {String} navId - reference Id for navbar.
3607 * Create a new nav group
3608 * @param {Object} config The config object
3611 Roo.bootstrap.NavGroup = function(config){
3612 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3615 Roo.bootstrap.NavGroup.register(this);
3619 * Fires when the active item changes
3620 * @param {Roo.bootstrap.NavGroup} this
3621 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3622 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3629 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3640 getAutoCreate : function()
3642 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3649 if (['tabs','pills'].indexOf(this.type)!==-1) {
3650 cfg.cls += ' nav-' + this.type
3652 if (this.type!=='nav') {
3653 Roo.log('nav type must be nav/tabs/pills')
3655 cfg.cls += ' navbar-nav'
3658 if (this.parent().sidebar) {
3661 cls: 'dashboard-menu sidebar-menu'
3667 if (this.form === true) {
3673 if (this.align === 'right') {
3674 cfg.cls += ' navbar-right';
3676 cfg.cls += ' navbar-left';
3680 if (this.align === 'right') {
3681 cfg.cls += ' navbar-right';
3685 cfg.cls += ' navbar-inverse';
3693 * sets the active Navigation item
3694 * @param {Roo.bootstrap.NavItem} the new current navitem
3696 setActiveItem : function(item)
3699 Roo.each(this.navItems, function(v){
3704 v.setActive(false, true);
3711 item.setActive(true, true);
3712 this.fireEvent('changed', this, item, prev);
3717 * gets the active Navigation item
3718 * @return {Roo.bootstrap.NavItem} the current navitem
3720 getActive : function()
3724 Roo.each(this.navItems, function(v){
3735 indexOfNav : function()
3739 Roo.each(this.navItems, function(v,i){
3750 * adds a Navigation item
3751 * @param {Roo.bootstrap.NavItem} the navitem to add
3753 addItem : function(cfg)
3755 var cn = new Roo.bootstrap.NavItem(cfg);
3757 cn.parentId = this.id;
3758 cn.onRender(this.el, null);
3762 * register a Navigation item
3763 * @param {Roo.bootstrap.NavItem} the navitem to add
3765 register : function(item)
3767 this.navItems.push( item);
3768 item.navId = this.navId;
3773 * clear all the Navigation item
3776 clearAll : function()
3779 this.el.dom.innerHTML = '';
3782 getNavItem: function(tabId)
3785 Roo.each(this.navItems, function(e) {
3786 if (e.tabId == tabId) {
3796 setActiveNext : function()
3798 var i = this.indexOfNav(this.getActive());
3799 if (i > this.navItems.length) {
3802 this.setActiveItem(this.navItems[i+1]);
3804 setActivePrev : function()
3806 var i = this.indexOfNav(this.getActive());
3810 this.setActiveItem(this.navItems[i-1]);
3812 clearWasActive : function(except) {
3813 Roo.each(this.navItems, function(e) {
3814 if (e.tabId != except.tabId && e.was_active) {
3815 e.was_active = false;
3822 getWasActive : function ()
3825 Roo.each(this.navItems, function(e) {
3840 Roo.apply(Roo.bootstrap.NavGroup, {
3844 * register a Navigation Group
3845 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3847 register : function(navgrp)
3849 this.groups[navgrp.navId] = navgrp;
3853 * fetch a Navigation Group based on the navigation ID
3854 * @param {string} the navgroup to add
3855 * @returns {Roo.bootstrap.NavGroup} the navgroup
3857 get: function(navId) {
3858 if (typeof(this.groups[navId]) == 'undefined') {
3860 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3862 return this.groups[navId] ;
3877 * @class Roo.bootstrap.NavItem
3878 * @extends Roo.bootstrap.Component
3879 * Bootstrap Navbar.NavItem class
3880 * @cfg {String} href link to
3881 * @cfg {String} html content of button
3882 * @cfg {String} badge text inside badge
3883 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3884 * @cfg {String} glyphicon name of glyphicon
3885 * @cfg {String} icon name of font awesome icon
3886 * @cfg {Boolean} active Is item active
3887 * @cfg {Boolean} disabled Is item disabled
3889 * @cfg {Boolean} preventDefault (true | false) default false
3890 * @cfg {String} tabId the tab that this item activates.
3891 * @cfg {String} tagtype (a|span) render as a href or span?
3892 * @cfg {Boolean} animateRef (true|false) link to element default false
3895 * Create a new Navbar Item
3896 * @param {Object} config The config object
3898 Roo.bootstrap.NavItem = function(config){
3899 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3904 * The raw click event for the entire grid.
3905 * @param {Roo.EventObject} e
3910 * Fires when the active item active state changes
3911 * @param {Roo.bootstrap.NavItem} this
3912 * @param {boolean} state the new state
3918 * Fires when scroll to element
3919 * @param {Roo.bootstrap.NavItem} this
3920 * @param {Object} options
3921 * @param {Roo.EventObject} e
3929 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3937 preventDefault : false,
3944 getAutoCreate : function(){
3952 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3954 if (this.disabled) {
3955 cfg.cls += ' disabled';
3958 if (this.href || this.html || this.glyphicon || this.icon) {
3962 href : this.href || "#",
3963 html: this.html || ''
3968 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3971 if(this.glyphicon) {
3972 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3977 cfg.cn[0].html += " <span class='caret'></span>";
3981 if (this.badge !== '') {
3983 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3991 initEvents: function()
3993 if (typeof (this.menu) != 'undefined') {
3994 this.menu.parentType = this.xtype;
3995 this.menu.triggerEl = this.el;
3996 this.menu = this.addxtype(Roo.apply({}, this.menu));
3999 this.el.select('a',true).on('click', this.onClick, this);
4001 if(this.tagtype == 'span'){
4002 this.el.select('span',true).on('click', this.onClick, this);
4005 // at this point parent should be available..
4006 this.parent().register(this);
4009 onClick : function(e)
4012 this.preventDefault ||
4019 if (this.disabled) {
4023 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4024 if (tg && tg.transition) {
4025 Roo.log("waiting for the transitionend");
4031 //Roo.log("fire event clicked");
4032 if(this.fireEvent('click', this, e) === false){
4036 if(this.tagtype == 'span'){
4040 //Roo.log(this.href);
4041 var ael = this.el.select('a',true).first();
4044 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4045 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4046 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4047 return; // ignore... - it's a 'hash' to another page.
4051 this.scrollToElement(e);
4055 var p = this.parent();
4057 if (['tabs','pills'].indexOf(p.type)!==-1) {
4058 if (typeof(p.setActiveItem) !== 'undefined') {
4059 p.setActiveItem(this);
4063 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4064 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4065 // remove the collapsed menu expand...
4066 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4070 isActive: function () {
4073 setActive : function(state, fire, is_was_active)
4075 if (this.active && !state & this.navId) {
4076 this.was_active = true;
4077 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4079 nv.clearWasActive(this);
4083 this.active = state;
4086 this.el.removeClass('active');
4087 } else if (!this.el.hasClass('active')) {
4088 this.el.addClass('active');
4091 this.fireEvent('changed', this, state);
4094 // show a panel if it's registered and related..
4096 if (!this.navId || !this.tabId || !state || is_was_active) {
4100 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4104 var pan = tg.getPanelByName(this.tabId);
4108 // if we can not flip to new panel - go back to old nav highlight..
4109 if (false == tg.showPanel(pan)) {
4110 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4112 var onav = nv.getWasActive();
4114 onav.setActive(true, false, true);
4123 // this should not be here...
4124 setDisabled : function(state)
4126 this.disabled = state;
4128 this.el.removeClass('disabled');
4129 } else if (!this.el.hasClass('disabled')) {
4130 this.el.addClass('disabled');
4136 * Fetch the element to display the tooltip on.
4137 * @return {Roo.Element} defaults to this.el
4139 tooltipEl : function()
4141 return this.el.select('' + this.tagtype + '', true).first();
4144 scrollToElement : function(e)
4146 var c = document.body;
4149 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4151 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4152 c = document.documentElement;
4155 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4161 var o = target.calcOffsetsTo(c);
4168 this.fireEvent('scrollto', this, options, e);
4170 Roo.get(c).scrollTo('top', options.value, true);
4183 * <span> icon </span>
4184 * <span> text </span>
4185 * <span>badge </span>
4189 * @class Roo.bootstrap.NavSidebarItem
4190 * @extends Roo.bootstrap.NavItem
4191 * Bootstrap Navbar.NavSidebarItem class
4193 * Create a new Navbar Button
4194 * @param {Object} config The config object
4196 Roo.bootstrap.NavSidebarItem = function(config){
4197 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4202 * The raw click event for the entire grid.
4203 * @param {Roo.EventObject} e
4208 * Fires when the active item active state changes
4209 * @param {Roo.bootstrap.NavSidebarItem} this
4210 * @param {boolean} state the new state
4218 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4221 getAutoCreate : function(){
4226 href : this.href || '#',
4238 html : this.html || ''
4243 cfg.cls += ' active';
4247 if (this.glyphicon || this.icon) {
4248 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4249 a.cn.push({ tag : 'i', cls : c }) ;
4254 if (this.badge !== '') {
4255 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4259 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4260 a.cls += 'dropdown-toggle treeview' ;
4284 * @class Roo.bootstrap.Row
4285 * @extends Roo.bootstrap.Component
4286 * Bootstrap Row class (contains columns...)
4290 * @param {Object} config The config object
4293 Roo.bootstrap.Row = function(config){
4294 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4297 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4299 getAutoCreate : function(){
4318 * @class Roo.bootstrap.Element
4319 * @extends Roo.bootstrap.Component
4320 * Bootstrap Element class
4321 * @cfg {String} html contents of the element
4322 * @cfg {String} tag tag of the element
4323 * @cfg {String} cls class of the element
4324 * @cfg {Boolean} preventDefault (true|false) default false
4325 * @cfg {Boolean} clickable (true|false) default false
4328 * Create a new Element
4329 * @param {Object} config The config object
4332 Roo.bootstrap.Element = function(config){
4333 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4339 * When a element is chick
4340 * @param {Roo.bootstrap.Element} this
4341 * @param {Roo.EventObject} e
4347 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4352 preventDefault: false,
4355 getAutoCreate : function(){
4366 initEvents: function()
4368 Roo.bootstrap.Element.superclass.initEvents.call(this);
4371 this.el.on('click', this.onClick, this);
4376 onClick : function(e)
4378 if(this.preventDefault){
4382 this.fireEvent('click', this, e);
4385 getValue : function()
4387 return this.el.dom.innerHTML;
4390 setValue : function(value)
4392 this.el.dom.innerHTML = value;
4407 * @class Roo.bootstrap.Pagination
4408 * @extends Roo.bootstrap.Component
4409 * Bootstrap Pagination class
4410 * @cfg {String} size xs | sm | md | lg
4411 * @cfg {Boolean} inverse false | true
4414 * Create a new Pagination
4415 * @param {Object} config The config object
4418 Roo.bootstrap.Pagination = function(config){
4419 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4422 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4428 getAutoCreate : function(){
4434 cfg.cls += ' inverse';
4440 cfg.cls += " " + this.cls;
4458 * @class Roo.bootstrap.PaginationItem
4459 * @extends Roo.bootstrap.Component
4460 * Bootstrap PaginationItem class
4461 * @cfg {String} html text
4462 * @cfg {String} href the link
4463 * @cfg {Boolean} preventDefault (true | false) default true
4464 * @cfg {Boolean} active (true | false) default false
4465 * @cfg {Boolean} disabled default false
4469 * Create a new PaginationItem
4470 * @param {Object} config The config object
4474 Roo.bootstrap.PaginationItem = function(config){
4475 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4480 * The raw click event for the entire grid.
4481 * @param {Roo.EventObject} e
4487 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4491 preventDefault: true,
4496 getAutoCreate : function(){
4502 href : this.href ? this.href : '#',
4503 html : this.html ? this.html : ''
4513 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4517 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4523 initEvents: function() {
4525 this.el.on('click', this.onClick, this);
4528 onClick : function(e)
4530 Roo.log('PaginationItem on click ');
4531 if(this.preventDefault){
4539 this.fireEvent('click', this, e);
4555 * @class Roo.bootstrap.Slider
4556 * @extends Roo.bootstrap.Component
4557 * Bootstrap Slider class
4560 * Create a new Slider
4561 * @param {Object} config The config object
4564 Roo.bootstrap.Slider = function(config){
4565 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4568 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4570 getAutoCreate : function(){
4574 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4578 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4590 * Ext JS Library 1.1.1
4591 * Copyright(c) 2006-2007, Ext JS, LLC.
4593 * Originally Released Under LGPL - original licence link has changed is not relivant.
4596 * <script type="text/javascript">
4601 * @class Roo.grid.ColumnModel
4602 * @extends Roo.util.Observable
4603 * This is the default implementation of a ColumnModel used by the Grid. It defines
4604 * the columns in the grid.
4607 var colModel = new Roo.grid.ColumnModel([
4608 {header: "Ticker", width: 60, sortable: true, locked: true},
4609 {header: "Company Name", width: 150, sortable: true},
4610 {header: "Market Cap.", width: 100, sortable: true},
4611 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4612 {header: "Employees", width: 100, sortable: true, resizable: false}
4617 * The config options listed for this class are options which may appear in each
4618 * individual column definition.
4619 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4621 * @param {Object} config An Array of column config objects. See this class's
4622 * config objects for details.
4624 Roo.grid.ColumnModel = function(config){
4626 * The config passed into the constructor
4628 this.config = config;
4631 // if no id, create one
4632 // if the column does not have a dataIndex mapping,
4633 // map it to the order it is in the config
4634 for(var i = 0, len = config.length; i < len; i++){
4636 if(typeof c.dataIndex == "undefined"){
4639 if(typeof c.renderer == "string"){
4640 c.renderer = Roo.util.Format[c.renderer];
4642 if(typeof c.id == "undefined"){
4645 if(c.editor && c.editor.xtype){
4646 c.editor = Roo.factory(c.editor, Roo.grid);
4648 if(c.editor && c.editor.isFormField){
4649 c.editor = new Roo.grid.GridEditor(c.editor);
4651 this.lookup[c.id] = c;
4655 * The width of columns which have no width specified (defaults to 100)
4658 this.defaultWidth = 100;
4661 * Default sortable of columns which have no sortable specified (defaults to false)
4664 this.defaultSortable = false;
4668 * @event widthchange
4669 * Fires when the width of a column changes.
4670 * @param {ColumnModel} this
4671 * @param {Number} columnIndex The column index
4672 * @param {Number} newWidth The new width
4674 "widthchange": true,
4676 * @event headerchange
4677 * Fires when the text of a header changes.
4678 * @param {ColumnModel} this
4679 * @param {Number} columnIndex The column index
4680 * @param {Number} newText The new header text
4682 "headerchange": true,
4684 * @event hiddenchange
4685 * Fires when a column is hidden or "unhidden".
4686 * @param {ColumnModel} this
4687 * @param {Number} columnIndex The column index
4688 * @param {Boolean} hidden true if hidden, false otherwise
4690 "hiddenchange": true,
4692 * @event columnmoved
4693 * Fires when a column is moved.
4694 * @param {ColumnModel} this
4695 * @param {Number} oldIndex
4696 * @param {Number} newIndex
4698 "columnmoved" : true,
4700 * @event columlockchange
4701 * Fires when a column's locked state is changed
4702 * @param {ColumnModel} this
4703 * @param {Number} colIndex
4704 * @param {Boolean} locked true if locked
4706 "columnlockchange" : true
4708 Roo.grid.ColumnModel.superclass.constructor.call(this);
4710 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4712 * @cfg {String} header The header text to display in the Grid view.
4715 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4716 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4717 * specified, the column's index is used as an index into the Record's data Array.
4720 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4721 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4724 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4725 * Defaults to the value of the {@link #defaultSortable} property.
4726 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4729 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4732 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4735 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4738 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4741 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4742 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4743 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4744 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4747 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4750 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4753 * @cfg {String} cursor (Optional)
4756 * @cfg {String} tooltip (Optional)
4759 * Returns the id of the column at the specified index.
4760 * @param {Number} index The column index
4761 * @return {String} the id
4763 getColumnId : function(index){
4764 return this.config[index].id;
4768 * Returns the column for a specified id.
4769 * @param {String} id The column id
4770 * @return {Object} the column
4772 getColumnById : function(id){
4773 return this.lookup[id];
4778 * Returns the column for a specified dataIndex.
4779 * @param {String} dataIndex The column dataIndex
4780 * @return {Object|Boolean} the column or false if not found
4782 getColumnByDataIndex: function(dataIndex){
4783 var index = this.findColumnIndex(dataIndex);
4784 return index > -1 ? this.config[index] : false;
4788 * Returns the index for a specified column id.
4789 * @param {String} id The column id
4790 * @return {Number} the index, or -1 if not found
4792 getIndexById : function(id){
4793 for(var i = 0, len = this.config.length; i < len; i++){
4794 if(this.config[i].id == id){
4802 * Returns the index for a specified column dataIndex.
4803 * @param {String} dataIndex The column dataIndex
4804 * @return {Number} the index, or -1 if not found
4807 findColumnIndex : function(dataIndex){
4808 for(var i = 0, len = this.config.length; i < len; i++){
4809 if(this.config[i].dataIndex == dataIndex){
4817 moveColumn : function(oldIndex, newIndex){
4818 var c = this.config[oldIndex];
4819 this.config.splice(oldIndex, 1);
4820 this.config.splice(newIndex, 0, c);
4821 this.dataMap = null;
4822 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4825 isLocked : function(colIndex){
4826 return this.config[colIndex].locked === true;
4829 setLocked : function(colIndex, value, suppressEvent){
4830 if(this.isLocked(colIndex) == value){
4833 this.config[colIndex].locked = value;
4835 this.fireEvent("columnlockchange", this, colIndex, value);
4839 getTotalLockedWidth : function(){
4841 for(var i = 0; i < this.config.length; i++){
4842 if(this.isLocked(i) && !this.isHidden(i)){
4843 this.totalWidth += this.getColumnWidth(i);
4849 getLockedCount : function(){
4850 for(var i = 0, len = this.config.length; i < len; i++){
4851 if(!this.isLocked(i)){
4858 * Returns the number of columns.
4861 getColumnCount : function(visibleOnly){
4862 if(visibleOnly === true){
4864 for(var i = 0, len = this.config.length; i < len; i++){
4865 if(!this.isHidden(i)){
4871 return this.config.length;
4875 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4876 * @param {Function} fn
4877 * @param {Object} scope (optional)
4878 * @return {Array} result
4880 getColumnsBy : function(fn, scope){
4882 for(var i = 0, len = this.config.length; i < len; i++){
4883 var c = this.config[i];
4884 if(fn.call(scope||this, c, i) === true){
4892 * Returns true if the specified column is sortable.
4893 * @param {Number} col The column index
4896 isSortable : function(col){
4897 if(typeof this.config[col].sortable == "undefined"){
4898 return this.defaultSortable;
4900 return this.config[col].sortable;
4904 * Returns the rendering (formatting) function defined for the column.
4905 * @param {Number} col The column index.
4906 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4908 getRenderer : function(col){
4909 if(!this.config[col].renderer){
4910 return Roo.grid.ColumnModel.defaultRenderer;
4912 return this.config[col].renderer;
4916 * Sets the rendering (formatting) function for a column.
4917 * @param {Number} col The column index
4918 * @param {Function} fn The function to use to process the cell's raw data
4919 * to return HTML markup for the grid view. The render function is called with
4920 * the following parameters:<ul>
4921 * <li>Data value.</li>
4922 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4923 * <li>css A CSS style string to apply to the table cell.</li>
4924 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4925 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4926 * <li>Row index</li>
4927 * <li>Column index</li>
4928 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4930 setRenderer : function(col, fn){
4931 this.config[col].renderer = fn;
4935 * Returns the width for the specified column.
4936 * @param {Number} col The column index
4939 getColumnWidth : function(col){
4940 return this.config[col].width * 1 || this.defaultWidth;
4944 * Sets the width for a column.
4945 * @param {Number} col The column index
4946 * @param {Number} width The new width
4948 setColumnWidth : function(col, width, suppressEvent){
4949 this.config[col].width = width;
4950 this.totalWidth = null;
4952 this.fireEvent("widthchange", this, col, width);
4957 * Returns the total width of all columns.
4958 * @param {Boolean} includeHidden True to include hidden column widths
4961 getTotalWidth : function(includeHidden){
4962 if(!this.totalWidth){
4963 this.totalWidth = 0;
4964 for(var i = 0, len = this.config.length; i < len; i++){
4965 if(includeHidden || !this.isHidden(i)){
4966 this.totalWidth += this.getColumnWidth(i);
4970 return this.totalWidth;
4974 * Returns the header for the specified column.
4975 * @param {Number} col The column index
4978 getColumnHeader : function(col){
4979 return this.config[col].header;
4983 * Sets the header for a column.
4984 * @param {Number} col The column index
4985 * @param {String} header The new header
4987 setColumnHeader : function(col, header){
4988 this.config[col].header = header;
4989 this.fireEvent("headerchange", this, col, header);
4993 * Returns the tooltip for the specified column.
4994 * @param {Number} col The column index
4997 getColumnTooltip : function(col){
4998 return this.config[col].tooltip;
5001 * Sets the tooltip for a column.
5002 * @param {Number} col The column index
5003 * @param {String} tooltip The new tooltip
5005 setColumnTooltip : function(col, tooltip){
5006 this.config[col].tooltip = tooltip;
5010 * Returns the dataIndex for the specified column.
5011 * @param {Number} col The column index
5014 getDataIndex : function(col){
5015 return this.config[col].dataIndex;
5019 * Sets the dataIndex for a column.
5020 * @param {Number} col The column index
5021 * @param {Number} dataIndex The new dataIndex
5023 setDataIndex : function(col, dataIndex){
5024 this.config[col].dataIndex = dataIndex;
5030 * Returns true if the cell is editable.
5031 * @param {Number} colIndex The column index
5032 * @param {Number} rowIndex The row index
5035 isCellEditable : function(colIndex, rowIndex){
5036 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5040 * Returns the editor defined for the cell/column.
5041 * return false or null to disable editing.
5042 * @param {Number} colIndex The column index
5043 * @param {Number} rowIndex The row index
5046 getCellEditor : function(colIndex, rowIndex){
5047 return this.config[colIndex].editor;
5051 * Sets if a column is editable.
5052 * @param {Number} col The column index
5053 * @param {Boolean} editable True if the column is editable
5055 setEditable : function(col, editable){
5056 this.config[col].editable = editable;
5061 * Returns true if the column is hidden.
5062 * @param {Number} colIndex The column index
5065 isHidden : function(colIndex){
5066 return this.config[colIndex].hidden;
5071 * Returns true if the column width cannot be changed
5073 isFixed : function(colIndex){
5074 return this.config[colIndex].fixed;
5078 * Returns true if the column can be resized
5081 isResizable : function(colIndex){
5082 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5085 * Sets if a column is hidden.
5086 * @param {Number} colIndex The column index
5087 * @param {Boolean} hidden True if the column is hidden
5089 setHidden : function(colIndex, hidden){
5090 this.config[colIndex].hidden = hidden;
5091 this.totalWidth = null;
5092 this.fireEvent("hiddenchange", this, colIndex, hidden);
5096 * Sets the editor for a column.
5097 * @param {Number} col The column index
5098 * @param {Object} editor The editor object
5100 setEditor : function(col, editor){
5101 this.config[col].editor = editor;
5105 Roo.grid.ColumnModel.defaultRenderer = function(value){
5106 if(typeof value == "string" && value.length < 1){
5112 // Alias for backwards compatibility
5113 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5116 * Ext JS Library 1.1.1
5117 * Copyright(c) 2006-2007, Ext JS, LLC.
5119 * Originally Released Under LGPL - original licence link has changed is not relivant.
5122 * <script type="text/javascript">
5126 * @class Roo.LoadMask
5127 * A simple utility class for generically masking elements while loading data. If the element being masked has
5128 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5129 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5130 * element's UpdateManager load indicator and will be destroyed after the initial load.
5132 * Create a new LoadMask
5133 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5134 * @param {Object} config The config object
5136 Roo.LoadMask = function(el, config){
5137 this.el = Roo.get(el);
5138 Roo.apply(this, config);
5140 this.store.on('beforeload', this.onBeforeLoad, this);
5141 this.store.on('load', this.onLoad, this);
5142 this.store.on('loadexception', this.onLoadException, this);
5143 this.removeMask = false;
5145 var um = this.el.getUpdateManager();
5146 um.showLoadIndicator = false; // disable the default indicator
5147 um.on('beforeupdate', this.onBeforeLoad, this);
5148 um.on('update', this.onLoad, this);
5149 um.on('failure', this.onLoad, this);
5150 this.removeMask = true;
5154 Roo.LoadMask.prototype = {
5156 * @cfg {Boolean} removeMask
5157 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5158 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5162 * The text to display in a centered loading message box (defaults to 'Loading...')
5166 * @cfg {String} msgCls
5167 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5169 msgCls : 'x-mask-loading',
5172 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5178 * Disables the mask to prevent it from being displayed
5180 disable : function(){
5181 this.disabled = true;
5185 * Enables the mask so that it can be displayed
5187 enable : function(){
5188 this.disabled = false;
5191 onLoadException : function()
5195 if (typeof(arguments[3]) != 'undefined') {
5196 Roo.MessageBox.alert("Error loading",arguments[3]);
5200 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5201 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5210 this.el.unmask(this.removeMask);
5215 this.el.unmask(this.removeMask);
5219 onBeforeLoad : function(){
5221 this.el.mask(this.msg, this.msgCls);
5226 destroy : function(){
5228 this.store.un('beforeload', this.onBeforeLoad, this);
5229 this.store.un('load', this.onLoad, this);
5230 this.store.un('loadexception', this.onLoadException, this);
5232 var um = this.el.getUpdateManager();
5233 um.un('beforeupdate', this.onBeforeLoad, this);
5234 um.un('update', this.onLoad, this);
5235 um.un('failure', this.onLoad, this);
5246 * @class Roo.bootstrap.Table
5247 * @extends Roo.bootstrap.Component
5248 * Bootstrap Table class
5249 * @cfg {String} cls table class
5250 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5251 * @cfg {String} bgcolor Specifies the background color for a table
5252 * @cfg {Number} border Specifies whether the table cells should have borders or not
5253 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5254 * @cfg {Number} cellspacing Specifies the space between cells
5255 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5256 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5257 * @cfg {String} sortable Specifies that the table should be sortable
5258 * @cfg {String} summary Specifies a summary of the content of a table
5259 * @cfg {Number} width Specifies the width of a table
5260 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5262 * @cfg {boolean} striped Should the rows be alternative striped
5263 * @cfg {boolean} bordered Add borders to the table
5264 * @cfg {boolean} hover Add hover highlighting
5265 * @cfg {boolean} condensed Format condensed
5266 * @cfg {boolean} responsive Format condensed
5267 * @cfg {Boolean} loadMask (true|false) default false
5268 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5269 * @cfg {Boolean} thead (true|false) generate thead, default true
5270 * @cfg {Boolean} RowSelection (true|false) default false
5271 * @cfg {Boolean} CellSelection (true|false) default false
5272 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5276 * Create a new Table
5277 * @param {Object} config The config object
5280 Roo.bootstrap.Table = function(config){
5281 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5284 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5285 this.sm = this.selModel;
5286 this.sm.xmodule = this.xmodule || false;
5288 if (this.cm && typeof(this.cm.config) == 'undefined') {
5289 this.colModel = new Roo.grid.ColumnModel(this.cm);
5290 this.cm = this.colModel;
5291 this.cm.xmodule = this.xmodule || false;
5294 this.store= Roo.factory(this.store, Roo.data);
5295 this.ds = this.store;
5296 this.ds.xmodule = this.xmodule || false;
5299 if (this.footer && this.store) {
5300 this.footer.dataSource = this.ds;
5301 this.footer = Roo.factory(this.footer);
5308 * Fires when a cell is clicked
5309 * @param {Roo.bootstrap.Table} this
5310 * @param {Roo.Element} el
5311 * @param {Number} rowIndex
5312 * @param {Number} columnIndex
5313 * @param {Roo.EventObject} e
5317 * @event celldblclick
5318 * Fires when a cell is double clicked
5319 * @param {Roo.bootstrap.Table} this
5320 * @param {Roo.Element} el
5321 * @param {Number} rowIndex
5322 * @param {Number} columnIndex
5323 * @param {Roo.EventObject} e
5325 "celldblclick" : true,
5328 * Fires when a row is clicked
5329 * @param {Roo.bootstrap.Table} this
5330 * @param {Roo.Element} el
5331 * @param {Number} rowIndex
5332 * @param {Roo.EventObject} e
5336 * @event rowdblclick
5337 * Fires when a row is double clicked
5338 * @param {Roo.bootstrap.Table} this
5339 * @param {Roo.Element} el
5340 * @param {Number} rowIndex
5341 * @param {Roo.EventObject} e
5343 "rowdblclick" : true,
5346 * Fires when a mouseover occur
5347 * @param {Roo.bootstrap.Table} this
5348 * @param {Roo.Element} el
5349 * @param {Number} rowIndex
5350 * @param {Number} columnIndex
5351 * @param {Roo.EventObject} e
5356 * Fires when a mouseout occur
5357 * @param {Roo.bootstrap.Table} this
5358 * @param {Roo.Element} el
5359 * @param {Number} rowIndex
5360 * @param {Number} columnIndex
5361 * @param {Roo.EventObject} e
5366 * Fires when a row is rendered, so you can change add a style to it.
5367 * @param {Roo.bootstrap.Table} this
5368 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5372 * @event rowsrendered
5373 * Fires when all the rows have been rendered
5374 * @param {Roo.bootstrap.Table} this
5376 'rowsrendered' : true
5381 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5405 RowSelection : false,
5406 CellSelection : false,
5409 // Roo.Element - the tbody
5412 getAutoCreate : function(){
5413 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5422 cfg.cls += ' table-striped';
5426 cfg.cls += ' table-hover';
5428 if (this.bordered) {
5429 cfg.cls += ' table-bordered';
5431 if (this.condensed) {
5432 cfg.cls += ' table-condensed';
5434 if (this.responsive) {
5435 cfg.cls += ' table-responsive';
5439 cfg.cls+= ' ' +this.cls;
5442 // this lot should be simplifed...
5445 cfg.align=this.align;
5448 cfg.bgcolor=this.bgcolor;
5451 cfg.border=this.border;
5453 if (this.cellpadding) {
5454 cfg.cellpadding=this.cellpadding;
5456 if (this.cellspacing) {
5457 cfg.cellspacing=this.cellspacing;
5460 cfg.frame=this.frame;
5463 cfg.rules=this.rules;
5465 if (this.sortable) {
5466 cfg.sortable=this.sortable;
5469 cfg.summary=this.summary;
5472 cfg.width=this.width;
5475 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5478 if(this.store || this.cm){
5480 cfg.cn.push(this.renderHeader());
5483 cfg.cn.push(this.renderBody());
5486 cfg.cn.push(this.renderFooter());
5489 cfg.cls+= ' TableGrid';
5492 return { cn : [ cfg ] };
5495 initEvents : function()
5497 if(!this.store || !this.cm){
5501 //Roo.log('initEvents with ds!!!!');
5503 this.mainBody = this.el.select('tbody', true).first();
5508 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5509 e.on('click', _this.sort, _this);
5512 this.el.on("click", this.onClick, this);
5513 this.el.on("dblclick", this.onDblClick, this);
5515 // why is this done????? = it breaks dialogs??
5516 //this.parent().el.setStyle('position', 'relative');
5520 this.footer.parentId = this.id;
5521 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5524 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5526 this.store.on('load', this.onLoad, this);
5527 this.store.on('beforeload', this.onBeforeLoad, this);
5528 this.store.on('update', this.onUpdate, this);
5529 this.store.on('add', this.onAdd, this);
5533 onMouseover : function(e, el)
5535 var cell = Roo.get(el);
5541 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5542 cell = cell.findParent('td', false, true);
5545 var row = cell.findParent('tr', false, true);
5546 var cellIndex = cell.dom.cellIndex;
5547 var rowIndex = row.dom.rowIndex - 1; // start from 0
5549 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5553 onMouseout : function(e, el)
5555 var cell = Roo.get(el);
5561 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5562 cell = cell.findParent('td', false, true);
5565 var row = cell.findParent('tr', false, true);
5566 var cellIndex = cell.dom.cellIndex;
5567 var rowIndex = row.dom.rowIndex - 1; // start from 0
5569 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5573 onClick : function(e, el)
5575 var cell = Roo.get(el);
5577 if(!cell || (!this.CellSelection && !this.RowSelection)){
5581 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5582 cell = cell.findParent('td', false, true);
5585 if(!cell || typeof(cell) == 'undefined'){
5589 var row = cell.findParent('tr', false, true);
5591 if(!row || typeof(row) == 'undefined'){
5595 var cellIndex = cell.dom.cellIndex;
5596 var rowIndex = this.getRowIndex(row);
5598 if(this.CellSelection){
5599 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5602 if(this.RowSelection){
5603 this.fireEvent('rowclick', this, row, rowIndex, e);
5609 onDblClick : function(e,el)
5611 var cell = Roo.get(el);
5613 if(!cell || (!this.CellSelection && !this.RowSelection)){
5617 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5618 cell = cell.findParent('td', false, true);
5621 if(!cell || typeof(cell) == 'undefined'){
5625 var row = cell.findParent('tr', false, true);
5627 if(!row || typeof(row) == 'undefined'){
5631 var cellIndex = cell.dom.cellIndex;
5632 var rowIndex = this.getRowIndex(row);
5634 if(this.CellSelection){
5635 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5638 if(this.RowSelection){
5639 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5643 sort : function(e,el)
5645 var col = Roo.get(el);
5647 if(!col.hasClass('sortable')){
5651 var sort = col.attr('sort');
5654 if(col.hasClass('glyphicon-arrow-up')){
5658 this.store.sortInfo = {field : sort, direction : dir};
5661 Roo.log("calling footer first");
5662 this.footer.onClick('first');
5665 this.store.load({ params : { start : 0 } });
5669 renderHeader : function()
5678 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5680 var config = cm.config[i];
5685 html: cm.getColumnHeader(i)
5688 if(typeof(config.tooltip) != 'undefined'){
5689 c.tooltip = config.tooltip;
5692 if(typeof(config.colspan) != 'undefined'){
5693 c.colspan = config.colspan;
5696 if(typeof(config.hidden) != 'undefined' && config.hidden){
5697 c.style += ' display:none;';
5700 if(typeof(config.dataIndex) != 'undefined'){
5701 c.sort = config.dataIndex;
5704 if(typeof(config.sortable) != 'undefined' && config.sortable){
5708 if(typeof(config.align) != 'undefined' && config.align.length){
5709 c.style += ' text-align:' + config.align + ';';
5712 if(typeof(config.width) != 'undefined'){
5713 c.style += ' width:' + config.width + 'px;';
5716 if(typeof(config.cls) != 'undefined'){
5717 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5726 renderBody : function()
5736 colspan : this.cm.getColumnCount()
5746 renderFooter : function()
5756 colspan : this.cm.getColumnCount()
5770 Roo.log('ds onload');
5775 var ds = this.store;
5777 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5778 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5780 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5781 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5784 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5785 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5789 var tbody = this.mainBody;
5791 if(ds.getCount() > 0){
5792 ds.data.each(function(d,rowIndex){
5793 var row = this.renderRow(cm, ds, rowIndex);
5795 tbody.createChild(row);
5799 if(row.cellObjects.length){
5800 Roo.each(row.cellObjects, function(r){
5801 _this.renderCellObject(r);
5808 Roo.each(this.el.select('tbody td', true).elements, function(e){
5809 e.on('mouseover', _this.onMouseover, _this);
5812 Roo.each(this.el.select('tbody td', true).elements, function(e){
5813 e.on('mouseout', _this.onMouseout, _this);
5815 this.fireEvent('rowsrendered', this);
5816 //if(this.loadMask){
5817 // this.maskEl.hide();
5822 onUpdate : function(ds,record)
5824 this.refreshRow(record);
5827 onRemove : function(ds, record, index, isUpdate){
5828 if(isUpdate !== true){
5829 this.fireEvent("beforerowremoved", this, index, record);
5831 var bt = this.mainBody.dom;
5833 var rows = this.el.select('tbody > tr', true).elements;
5835 if(typeof(rows[index]) != 'undefined'){
5836 bt.removeChild(rows[index].dom);
5839 // if(bt.rows[index]){
5840 // bt.removeChild(bt.rows[index]);
5843 if(isUpdate !== true){
5844 //this.stripeRows(index);
5845 //this.syncRowHeights(index, index);
5847 this.fireEvent("rowremoved", this, index, record);
5851 onAdd : function(ds, records, rowIndex)
5853 //Roo.log('on Add called');
5854 // - note this does not handle multiple adding very well..
5855 var bt = this.mainBody.dom;
5856 for (var i =0 ; i < records.length;i++) {
5857 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5858 //Roo.log(records[i]);
5859 //Roo.log(this.store.getAt(rowIndex+i));
5860 this.insertRow(this.store, rowIndex + i, false);
5867 refreshRow : function(record){
5868 var ds = this.store, index;
5869 if(typeof record == 'number'){
5871 record = ds.getAt(index);
5873 index = ds.indexOf(record);
5875 this.insertRow(ds, index, true);
5876 this.onRemove(ds, record, index+1, true);
5877 //this.syncRowHeights(index, index);
5879 this.fireEvent("rowupdated", this, index, record);
5882 insertRow : function(dm, rowIndex, isUpdate){
5885 this.fireEvent("beforerowsinserted", this, rowIndex);
5887 //var s = this.getScrollState();
5888 var row = this.renderRow(this.cm, this.store, rowIndex);
5889 // insert before rowIndex..
5890 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5894 if(row.cellObjects.length){
5895 Roo.each(row.cellObjects, function(r){
5896 _this.renderCellObject(r);
5901 this.fireEvent("rowsinserted", this, rowIndex);
5902 //this.syncRowHeights(firstRow, lastRow);
5903 //this.stripeRows(firstRow);
5910 getRowDom : function(rowIndex)
5912 var rows = this.el.select('tbody > tr', true).elements;
5914 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5917 // returns the object tree for a tr..
5920 renderRow : function(cm, ds, rowIndex)
5923 var d = ds.getAt(rowIndex);
5930 var cellObjects = [];
5932 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5933 var config = cm.config[i];
5935 var renderer = cm.getRenderer(i);
5939 if(typeof(renderer) !== 'undefined'){
5940 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5942 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5943 // and are rendered into the cells after the row is rendered - using the id for the element.
5945 if(typeof(value) === 'object'){
5955 rowIndex : rowIndex,
5960 this.fireEvent('rowclass', this, rowcfg);
5964 cls : rowcfg.rowClass,
5966 html: (typeof(value) === 'object') ? '' : value
5973 if(typeof(config.colspan) != 'undefined'){
5974 td.colspan = config.colspan;
5977 if(typeof(config.hidden) != 'undefined' && config.hidden){
5978 td.style += ' display:none;';
5981 if(typeof(config.align) != 'undefined' && config.align.length){
5982 td.style += ' text-align:' + config.align + ';';
5985 if(typeof(config.width) != 'undefined'){
5986 td.style += ' width:' + config.width + 'px;';
5989 if(typeof(config.cursor) != 'undefined'){
5990 td.style += ' cursor:' + config.cursor + ';';
5993 if(typeof(config.cls) != 'undefined'){
5994 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6001 row.cellObjects = cellObjects;
6009 onBeforeLoad : function()
6011 //Roo.log('ds onBeforeLoad');
6015 //if(this.loadMask){
6016 // this.maskEl.show();
6024 this.el.select('tbody', true).first().dom.innerHTML = '';
6027 * Show or hide a row.
6028 * @param {Number} rowIndex to show or hide
6029 * @param {Boolean} state hide
6031 setRowVisibility : function(rowIndex, state)
6033 var bt = this.mainBody.dom;
6035 var rows = this.el.select('tbody > tr', true).elements;
6037 if(typeof(rows[rowIndex]) == 'undefined'){
6040 rows[rowIndex].dom.style.display = state ? '' : 'none';
6044 getSelectionModel : function(){
6046 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6048 return this.selModel;
6051 * Render the Roo.bootstrap object from renderder
6053 renderCellObject : function(r)
6057 var t = r.cfg.render(r.container);
6060 Roo.each(r.cfg.cn, function(c){
6062 container: t.getChildContainer(),
6065 _this.renderCellObject(child);
6070 getRowIndex : function(row)
6074 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6097 * @class Roo.bootstrap.TableCell
6098 * @extends Roo.bootstrap.Component
6099 * Bootstrap TableCell class
6100 * @cfg {String} html cell contain text
6101 * @cfg {String} cls cell class
6102 * @cfg {String} tag cell tag (td|th) default td
6103 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6104 * @cfg {String} align Aligns the content in a cell
6105 * @cfg {String} axis Categorizes cells
6106 * @cfg {String} bgcolor Specifies the background color of a cell
6107 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6108 * @cfg {Number} colspan Specifies the number of columns a cell should span
6109 * @cfg {String} headers Specifies one or more header cells a cell is related to
6110 * @cfg {Number} height Sets the height of a cell
6111 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6112 * @cfg {Number} rowspan Sets the number of rows a cell should span
6113 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6114 * @cfg {String} valign Vertical aligns the content in a cell
6115 * @cfg {Number} width Specifies the width of a cell
6118 * Create a new TableCell
6119 * @param {Object} config The config object
6122 Roo.bootstrap.TableCell = function(config){
6123 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6126 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6146 getAutoCreate : function(){
6147 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6167 cfg.align=this.align
6173 cfg.bgcolor=this.bgcolor
6176 cfg.charoff=this.charoff
6179 cfg.colspan=this.colspan
6182 cfg.headers=this.headers
6185 cfg.height=this.height
6188 cfg.nowrap=this.nowrap
6191 cfg.rowspan=this.rowspan
6194 cfg.scope=this.scope
6197 cfg.valign=this.valign
6200 cfg.width=this.width
6219 * @class Roo.bootstrap.TableRow
6220 * @extends Roo.bootstrap.Component
6221 * Bootstrap TableRow class
6222 * @cfg {String} cls row class
6223 * @cfg {String} align Aligns the content in a table row
6224 * @cfg {String} bgcolor Specifies a background color for a table row
6225 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6226 * @cfg {String} valign Vertical aligns the content in a table row
6229 * Create a new TableRow
6230 * @param {Object} config The config object
6233 Roo.bootstrap.TableRow = function(config){
6234 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6237 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6245 getAutoCreate : function(){
6246 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6256 cfg.align = this.align;
6259 cfg.bgcolor = this.bgcolor;
6262 cfg.charoff = this.charoff;
6265 cfg.valign = this.valign;
6283 * @class Roo.bootstrap.TableBody
6284 * @extends Roo.bootstrap.Component
6285 * Bootstrap TableBody class
6286 * @cfg {String} cls element class
6287 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6288 * @cfg {String} align Aligns the content inside the element
6289 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6290 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6293 * Create a new TableBody
6294 * @param {Object} config The config object
6297 Roo.bootstrap.TableBody = function(config){
6298 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6301 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6309 getAutoCreate : function(){
6310 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6324 cfg.align = this.align;
6327 cfg.charoff = this.charoff;
6330 cfg.valign = this.valign;
6337 // initEvents : function()
6344 // this.store = Roo.factory(this.store, Roo.data);
6345 // this.store.on('load', this.onLoad, this);
6347 // this.store.load();
6351 // onLoad: function ()
6353 // this.fireEvent('load', this);
6363 * Ext JS Library 1.1.1
6364 * Copyright(c) 2006-2007, Ext JS, LLC.
6366 * Originally Released Under LGPL - original licence link has changed is not relivant.
6369 * <script type="text/javascript">
6372 // as we use this in bootstrap.
6373 Roo.namespace('Roo.form');
6375 * @class Roo.form.Action
6376 * Internal Class used to handle form actions
6378 * @param {Roo.form.BasicForm} el The form element or its id
6379 * @param {Object} config Configuration options
6384 // define the action interface
6385 Roo.form.Action = function(form, options){
6387 this.options = options || {};
6390 * Client Validation Failed
6393 Roo.form.Action.CLIENT_INVALID = 'client';
6395 * Server Validation Failed
6398 Roo.form.Action.SERVER_INVALID = 'server';
6400 * Connect to Server Failed
6403 Roo.form.Action.CONNECT_FAILURE = 'connect';
6405 * Reading Data from Server Failed
6408 Roo.form.Action.LOAD_FAILURE = 'load';
6410 Roo.form.Action.prototype = {
6412 failureType : undefined,
6413 response : undefined,
6417 run : function(options){
6422 success : function(response){
6427 handleResponse : function(response){
6431 // default connection failure
6432 failure : function(response){
6434 this.response = response;
6435 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6436 this.form.afterAction(this, false);
6439 processResponse : function(response){
6440 this.response = response;
6441 if(!response.responseText){
6444 this.result = this.handleResponse(response);
6448 // utility functions used internally
6449 getUrl : function(appendParams){
6450 var url = this.options.url || this.form.url || this.form.el.dom.action;
6452 var p = this.getParams();
6454 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6460 getMethod : function(){
6461 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6464 getParams : function(){
6465 var bp = this.form.baseParams;
6466 var p = this.options.params;
6468 if(typeof p == "object"){
6469 p = Roo.urlEncode(Roo.applyIf(p, bp));
6470 }else if(typeof p == 'string' && bp){
6471 p += '&' + Roo.urlEncode(bp);
6474 p = Roo.urlEncode(bp);
6479 createCallback : function(){
6481 success: this.success,
6482 failure: this.failure,
6484 timeout: (this.form.timeout*1000),
6485 upload: this.form.fileUpload ? this.success : undefined
6490 Roo.form.Action.Submit = function(form, options){
6491 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6494 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6497 haveProgress : false,
6498 uploadComplete : false,
6500 // uploadProgress indicator.
6501 uploadProgress : function()
6503 if (!this.form.progressUrl) {
6507 if (!this.haveProgress) {
6508 Roo.MessageBox.progress("Uploading", "Uploading");
6510 if (this.uploadComplete) {
6511 Roo.MessageBox.hide();
6515 this.haveProgress = true;
6517 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6519 var c = new Roo.data.Connection();
6521 url : this.form.progressUrl,
6526 success : function(req){
6527 //console.log(data);
6531 rdata = Roo.decode(req.responseText)
6533 Roo.log("Invalid data from server..");
6537 if (!rdata || !rdata.success) {
6539 Roo.MessageBox.alert(Roo.encode(rdata));
6542 var data = rdata.data;
6544 if (this.uploadComplete) {
6545 Roo.MessageBox.hide();
6550 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6551 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6554 this.uploadProgress.defer(2000,this);
6557 failure: function(data) {
6558 Roo.log('progress url failed ');
6569 // run get Values on the form, so it syncs any secondary forms.
6570 this.form.getValues();
6572 var o = this.options;
6573 var method = this.getMethod();
6574 var isPost = method == 'POST';
6575 if(o.clientValidation === false || this.form.isValid()){
6577 if (this.form.progressUrl) {
6578 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6579 (new Date() * 1) + '' + Math.random());
6584 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6585 form:this.form.el.dom,
6586 url:this.getUrl(!isPost),
6588 params:isPost ? this.getParams() : null,
6589 isUpload: this.form.fileUpload
6592 this.uploadProgress();
6594 }else if (o.clientValidation !== false){ // client validation failed
6595 this.failureType = Roo.form.Action.CLIENT_INVALID;
6596 this.form.afterAction(this, false);
6600 success : function(response)
6602 this.uploadComplete= true;
6603 if (this.haveProgress) {
6604 Roo.MessageBox.hide();
6608 var result = this.processResponse(response);
6609 if(result === true || result.success){
6610 this.form.afterAction(this, true);
6614 this.form.markInvalid(result.errors);
6615 this.failureType = Roo.form.Action.SERVER_INVALID;
6617 this.form.afterAction(this, false);
6619 failure : function(response)
6621 this.uploadComplete= true;
6622 if (this.haveProgress) {
6623 Roo.MessageBox.hide();
6626 this.response = response;
6627 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6628 this.form.afterAction(this, false);
6631 handleResponse : function(response){
6632 if(this.form.errorReader){
6633 var rs = this.form.errorReader.read(response);
6636 for(var i = 0, len = rs.records.length; i < len; i++) {
6637 var r = rs.records[i];
6641 if(errors.length < 1){
6645 success : rs.success,
6651 ret = Roo.decode(response.responseText);
6655 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6665 Roo.form.Action.Load = function(form, options){
6666 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6667 this.reader = this.form.reader;
6670 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6675 Roo.Ajax.request(Roo.apply(
6676 this.createCallback(), {
6677 method:this.getMethod(),
6678 url:this.getUrl(false),
6679 params:this.getParams()
6683 success : function(response){
6685 var result = this.processResponse(response);
6686 if(result === true || !result.success || !result.data){
6687 this.failureType = Roo.form.Action.LOAD_FAILURE;
6688 this.form.afterAction(this, false);
6691 this.form.clearInvalid();
6692 this.form.setValues(result.data);
6693 this.form.afterAction(this, true);
6696 handleResponse : function(response){
6697 if(this.form.reader){
6698 var rs = this.form.reader.read(response);
6699 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6701 success : rs.success,
6705 return Roo.decode(response.responseText);
6709 Roo.form.Action.ACTION_TYPES = {
6710 'load' : Roo.form.Action.Load,
6711 'submit' : Roo.form.Action.Submit
6720 * @class Roo.bootstrap.Form
6721 * @extends Roo.bootstrap.Component
6722 * Bootstrap Form class
6723 * @cfg {String} method GET | POST (default POST)
6724 * @cfg {String} labelAlign top | left (default top)
6725 * @cfg {String} align left | right - for navbars
6726 * @cfg {Boolean} loadMask load mask when submit (default true)
6731 * @param {Object} config The config object
6735 Roo.bootstrap.Form = function(config){
6736 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6739 * @event clientvalidation
6740 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6741 * @param {Form} this
6742 * @param {Boolean} valid true if the form has passed client-side validation
6744 clientvalidation: true,
6746 * @event beforeaction
6747 * Fires before any action is performed. Return false to cancel the action.
6748 * @param {Form} this
6749 * @param {Action} action The action to be performed
6753 * @event actionfailed
6754 * Fires when an action fails.
6755 * @param {Form} this
6756 * @param {Action} action The action that failed
6758 actionfailed : true,
6760 * @event actioncomplete
6761 * Fires when an action is completed.
6762 * @param {Form} this
6763 * @param {Action} action The action that completed
6765 actioncomplete : true
6770 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6773 * @cfg {String} method
6774 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6779 * The URL to use for form actions if one isn't supplied in the action options.
6782 * @cfg {Boolean} fileUpload
6783 * Set to true if this form is a file upload.
6787 * @cfg {Object} baseParams
6788 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6792 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6796 * @cfg {Sting} align (left|right) for navbar forms
6801 activeAction : null,
6804 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6805 * element by passing it or its id or mask the form itself by passing in true.
6808 waitMsgTarget : false,
6812 getAutoCreate : function(){
6816 method : this.method || 'POST',
6817 id : this.id || Roo.id(),
6820 if (this.parent().xtype.match(/^Nav/)) {
6821 cfg.cls = 'navbar-form navbar-' + this.align;
6825 if (this.labelAlign == 'left' ) {
6826 cfg.cls += ' form-horizontal';
6832 initEvents : function()
6834 this.el.on('submit', this.onSubmit, this);
6835 // this was added as random key presses on the form where triggering form submit.
6836 this.el.on('keypress', function(e) {
6837 if (e.getCharCode() != 13) {
6840 // we might need to allow it for textareas.. and some other items.
6841 // check e.getTarget().
6843 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6847 Roo.log("keypress blocked");
6855 onSubmit : function(e){
6860 * Returns true if client-side validation on the form is successful.
6863 isValid : function(){
6864 var items = this.getItems();
6866 items.each(function(f){
6875 * Returns true if any fields in this form have changed since their original load.
6878 isDirty : function(){
6880 var items = this.getItems();
6881 items.each(function(f){
6891 * Performs a predefined action (submit or load) or custom actions you define on this form.
6892 * @param {String} actionName The name of the action type
6893 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6894 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6895 * accept other config options):
6897 Property Type Description
6898 ---------------- --------------- ----------------------------------------------------------------------------------
6899 url String The url for the action (defaults to the form's url)
6900 method String The form method to use (defaults to the form's method, or POST if not defined)
6901 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6902 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6903 validate the form on the client (defaults to false)
6905 * @return {BasicForm} this
6907 doAction : function(action, options){
6908 if(typeof action == 'string'){
6909 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6911 if(this.fireEvent('beforeaction', this, action) !== false){
6912 this.beforeAction(action);
6913 action.run.defer(100, action);
6919 beforeAction : function(action){
6920 var o = action.options;
6923 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6925 // not really supported yet.. ??
6927 //if(this.waitMsgTarget === true){
6928 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6929 //}else if(this.waitMsgTarget){
6930 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6931 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6933 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6939 afterAction : function(action, success){
6940 this.activeAction = null;
6941 var o = action.options;
6943 //if(this.waitMsgTarget === true){
6945 //}else if(this.waitMsgTarget){
6946 // this.waitMsgTarget.unmask();
6948 // Roo.MessageBox.updateProgress(1);
6949 // Roo.MessageBox.hide();
6956 Roo.callback(o.success, o.scope, [this, action]);
6957 this.fireEvent('actioncomplete', this, action);
6961 // failure condition..
6962 // we have a scenario where updates need confirming.
6963 // eg. if a locking scenario exists..
6964 // we look for { errors : { needs_confirm : true }} in the response.
6966 (typeof(action.result) != 'undefined') &&
6967 (typeof(action.result.errors) != 'undefined') &&
6968 (typeof(action.result.errors.needs_confirm) != 'undefined')
6971 Roo.log("not supported yet");
6974 Roo.MessageBox.confirm(
6975 "Change requires confirmation",
6976 action.result.errorMsg,
6981 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6991 Roo.callback(o.failure, o.scope, [this, action]);
6992 // show an error message if no failed handler is set..
6993 if (!this.hasListener('actionfailed')) {
6994 Roo.log("need to add dialog support");
6996 Roo.MessageBox.alert("Error",
6997 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6998 action.result.errorMsg :
6999 "Saving Failed, please check your entries or try again"
7004 this.fireEvent('actionfailed', this, action);
7009 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7010 * @param {String} id The value to search for
7013 findField : function(id){
7014 var items = this.getItems();
7015 var field = items.get(id);
7017 items.each(function(f){
7018 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7025 return field || null;
7028 * Mark fields in this form invalid in bulk.
7029 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7030 * @return {BasicForm} this
7032 markInvalid : function(errors){
7033 if(errors instanceof Array){
7034 for(var i = 0, len = errors.length; i < len; i++){
7035 var fieldError = errors[i];
7036 var f = this.findField(fieldError.id);
7038 f.markInvalid(fieldError.msg);
7044 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7045 field.markInvalid(errors[id]);
7049 //Roo.each(this.childForms || [], function (f) {
7050 // f.markInvalid(errors);
7057 * Set values for fields in this form in bulk.
7058 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7059 * @return {BasicForm} this
7061 setValues : function(values){
7062 if(values instanceof Array){ // array of objects
7063 for(var i = 0, len = values.length; i < len; i++){
7065 var f = this.findField(v.id);
7067 f.setValue(v.value);
7068 if(this.trackResetOnLoad){
7069 f.originalValue = f.getValue();
7073 }else{ // object hash
7076 if(typeof values[id] != 'function' && (field = this.findField(id))){
7078 if (field.setFromData &&
7080 field.displayField &&
7081 // combos' with local stores can
7082 // be queried via setValue()
7083 // to set their value..
7084 (field.store && !field.store.isLocal)
7088 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7089 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7090 field.setFromData(sd);
7093 field.setValue(values[id]);
7097 if(this.trackResetOnLoad){
7098 field.originalValue = field.getValue();
7104 //Roo.each(this.childForms || [], function (f) {
7105 // f.setValues(values);
7112 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7113 * they are returned as an array.
7114 * @param {Boolean} asString
7117 getValues : function(asString){
7118 //if (this.childForms) {
7119 // copy values from the child forms
7120 // Roo.each(this.childForms, function (f) {
7121 // this.setValues(f.getValues());
7127 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7128 if(asString === true){
7131 return Roo.urlDecode(fs);
7135 * Returns the fields in this form as an object with key/value pairs.
7136 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7139 getFieldValues : function(with_hidden)
7141 var items = this.getItems();
7143 items.each(function(f){
7147 var v = f.getValue();
7148 if (f.inputType =='radio') {
7149 if (typeof(ret[f.getName()]) == 'undefined') {
7150 ret[f.getName()] = ''; // empty..
7153 if (!f.el.dom.checked) {
7161 // not sure if this supported any more..
7162 if ((typeof(v) == 'object') && f.getRawValue) {
7163 v = f.getRawValue() ; // dates..
7165 // combo boxes where name != hiddenName...
7166 if (f.name != f.getName()) {
7167 ret[f.name] = f.getRawValue();
7169 ret[f.getName()] = v;
7176 * Clears all invalid messages in this form.
7177 * @return {BasicForm} this
7179 clearInvalid : function(){
7180 var items = this.getItems();
7182 items.each(function(f){
7193 * @return {BasicForm} this
7196 var items = this.getItems();
7197 items.each(function(f){
7201 Roo.each(this.childForms || [], function (f) {
7208 getItems : function()
7210 var r=new Roo.util.MixedCollection(false, function(o){
7211 return o.id || (o.id = Roo.id());
7213 var iter = function(el) {
7220 Roo.each(el.items,function(e) {
7240 * Ext JS Library 1.1.1
7241 * Copyright(c) 2006-2007, Ext JS, LLC.
7243 * Originally Released Under LGPL - original licence link has changed is not relivant.
7246 * <script type="text/javascript">
7249 * @class Roo.form.VTypes
7250 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7253 Roo.form.VTypes = function(){
7254 // closure these in so they are only created once.
7255 var alpha = /^[a-zA-Z_]+$/;
7256 var alphanum = /^[a-zA-Z0-9_]+$/;
7257 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7258 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7260 // All these messages and functions are configurable
7263 * The function used to validate email addresses
7264 * @param {String} value The email address
7266 'email' : function(v){
7267 return email.test(v);
7270 * The error text to display when the email validation function returns false
7273 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7275 * The keystroke filter mask to be applied on email input
7278 'emailMask' : /[a-z0-9_\.\-@]/i,
7281 * The function used to validate URLs
7282 * @param {String} value The URL
7284 'url' : function(v){
7288 * The error text to display when the url validation function returns false
7291 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7294 * The function used to validate alpha values
7295 * @param {String} value The value
7297 'alpha' : function(v){
7298 return alpha.test(v);
7301 * The error text to display when the alpha validation function returns false
7304 'alphaText' : 'This field should only contain letters and _',
7306 * The keystroke filter mask to be applied on alpha input
7309 'alphaMask' : /[a-z_]/i,
7312 * The function used to validate alphanumeric values
7313 * @param {String} value The value
7315 'alphanum' : function(v){
7316 return alphanum.test(v);
7319 * The error text to display when the alphanumeric validation function returns false
7322 'alphanumText' : 'This field should only contain letters, numbers and _',
7324 * The keystroke filter mask to be applied on alphanumeric input
7327 'alphanumMask' : /[a-z0-9_]/i
7337 * @class Roo.bootstrap.Input
7338 * @extends Roo.bootstrap.Component
7339 * Bootstrap Input class
7340 * @cfg {Boolean} disabled is it disabled
7341 * @cfg {String} fieldLabel - the label associated
7342 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7343 * @cfg {String} name name of the input
7344 * @cfg {string} fieldLabel - the label associated
7345 * @cfg {string} inputType - input / file submit ...
7346 * @cfg {string} placeholder - placeholder to put in text.
7347 * @cfg {string} before - input group add on before
7348 * @cfg {string} after - input group add on after
7349 * @cfg {string} size - (lg|sm) or leave empty..
7350 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7351 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7352 * @cfg {Number} md colspan out of 12 for computer-sized screens
7353 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7354 * @cfg {string} value default value of the input
7355 * @cfg {Number} labelWidth set the width of label (0-12)
7356 * @cfg {String} labelAlign (top|left)
7357 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7358 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7360 * @cfg {String} align (left|center|right) Default left
7365 * Create a new Input
7366 * @param {Object} config The config object
7369 Roo.bootstrap.Input = function(config){
7370 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7375 * Fires when this field receives input focus.
7376 * @param {Roo.form.Field} this
7381 * Fires when this field loses input focus.
7382 * @param {Roo.form.Field} this
7387 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7388 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7389 * @param {Roo.form.Field} this
7390 * @param {Roo.EventObject} e The event object
7395 * Fires just before the field blurs if the field value has changed.
7396 * @param {Roo.form.Field} this
7397 * @param {Mixed} newValue The new value
7398 * @param {Mixed} oldValue The original value
7403 * Fires after the field has been marked as invalid.
7404 * @param {Roo.form.Field} this
7405 * @param {String} msg The validation message
7410 * Fires after the field has been validated with no errors.
7411 * @param {Roo.form.Field} this
7416 * Fires after the key up
7417 * @param {Roo.form.Field} this
7418 * @param {Roo.EventObject} e The event Object
7424 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7426 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7427 automatic validation (defaults to "keyup").
7429 validationEvent : "keyup",
7431 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7433 validateOnBlur : true,
7435 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7437 validationDelay : 250,
7439 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7441 focusClass : "x-form-focus", // not needed???
7445 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7447 invalidClass : "has-warning",
7450 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7452 validClass : "has-success",
7455 * @cfg {Boolean} hasFeedback (true|false) default true
7460 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7462 invalidFeedbackClass : "glyphicon-warning-sign",
7465 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7467 validFeedbackClass : "glyphicon-ok",
7470 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7472 selectOnFocus : false,
7475 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7479 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7484 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7486 disableKeyFilter : false,
7489 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7493 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7497 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7499 blankText : "This field is required",
7502 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7506 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7508 maxLength : Number.MAX_VALUE,
7510 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7512 minLengthText : "The minimum length for this field is {0}",
7514 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7516 maxLengthText : "The maximum length for this field is {0}",
7520 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7521 * If available, this function will be called only after the basic validators all return true, and will be passed the
7522 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7526 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7527 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7528 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7532 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7536 autocomplete: false,
7555 formatedValue : false,
7557 parentLabelAlign : function()
7560 while (parent.parent()) {
7561 parent = parent.parent();
7562 if (typeof(parent.labelAlign) !='undefined') {
7563 return parent.labelAlign;
7570 getAutoCreate : function(){
7572 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7578 if(this.inputType != 'hidden'){
7579 cfg.cls = 'form-group' //input-group
7585 type : this.inputType,
7587 cls : 'form-control',
7588 placeholder : this.placeholder || '',
7589 autocomplete : this.autocomplete || 'new-password'
7594 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7597 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7598 input.maxLength = this.maxLength;
7601 if (this.disabled) {
7602 input.disabled=true;
7605 if (this.readOnly) {
7606 input.readonly=true;
7610 input.name = this.name;
7613 input.cls += ' input-' + this.size;
7616 ['xs','sm','md','lg'].map(function(size){
7617 if (settings[size]) {
7618 cfg.cls += ' col-' + size + '-' + settings[size];
7622 var inputblock = input;
7626 cls: 'glyphicon form-control-feedback'
7629 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7632 cls : 'has-feedback',
7640 if (this.before || this.after) {
7643 cls : 'input-group',
7647 if (this.before && typeof(this.before) == 'string') {
7649 inputblock.cn.push({
7651 cls : 'roo-input-before input-group-addon',
7655 if (this.before && typeof(this.before) == 'object') {
7656 this.before = Roo.factory(this.before);
7657 Roo.log(this.before);
7658 inputblock.cn.push({
7660 cls : 'roo-input-before input-group-' +
7661 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7665 inputblock.cn.push(input);
7667 if (this.after && typeof(this.after) == 'string') {
7668 inputblock.cn.push({
7670 cls : 'roo-input-after input-group-addon',
7674 if (this.after && typeof(this.after) == 'object') {
7675 this.after = Roo.factory(this.after);
7676 Roo.log(this.after);
7677 inputblock.cn.push({
7679 cls : 'roo-input-after input-group-' +
7680 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7684 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7685 inputblock.cls += ' has-feedback';
7686 inputblock.cn.push(feedback);
7690 if (align ==='left' && this.fieldLabel.length) {
7691 Roo.log("left and has label");
7697 cls : 'control-label col-sm-' + this.labelWidth,
7698 html : this.fieldLabel
7702 cls : "col-sm-" + (12 - this.labelWidth),
7709 } else if ( this.fieldLabel.length) {
7715 //cls : 'input-group-addon',
7716 html : this.fieldLabel
7726 Roo.log(" no label && no align");
7735 Roo.log('input-parentType: ' + this.parentType);
7737 if (this.parentType === 'Navbar' && this.parent().bar) {
7738 cfg.cls += ' navbar-form';
7746 * return the real input element.
7748 inputEl: function ()
7750 return this.el.select('input.form-control',true).first();
7753 tooltipEl : function()
7755 return this.inputEl();
7758 setDisabled : function(v)
7760 var i = this.inputEl().dom;
7762 i.removeAttribute('disabled');
7766 i.setAttribute('disabled','true');
7768 initEvents : function()
7771 this.inputEl().on("keydown" , this.fireKey, this);
7772 this.inputEl().on("focus", this.onFocus, this);
7773 this.inputEl().on("blur", this.onBlur, this);
7775 this.inputEl().relayEvent('keyup', this);
7777 // reference to original value for reset
7778 this.originalValue = this.getValue();
7779 //Roo.form.TextField.superclass.initEvents.call(this);
7780 if(this.validationEvent == 'keyup'){
7781 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7782 this.inputEl().on('keyup', this.filterValidation, this);
7784 else if(this.validationEvent !== false){
7785 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7788 if(this.selectOnFocus){
7789 this.on("focus", this.preFocus, this);
7792 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7793 this.inputEl().on("keypress", this.filterKeys, this);
7796 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7797 this.el.on("click", this.autoSize, this);
7800 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7801 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7804 if (typeof(this.before) == 'object') {
7805 this.before.render(this.el.select('.roo-input-before',true).first());
7807 if (typeof(this.after) == 'object') {
7808 this.after.render(this.el.select('.roo-input-after',true).first());
7813 filterValidation : function(e){
7814 if(!e.isNavKeyPress()){
7815 this.validationTask.delay(this.validationDelay);
7819 * Validates the field value
7820 * @return {Boolean} True if the value is valid, else false
7822 validate : function(){
7823 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7824 if(this.disabled || this.validateValue(this.getRawValue())){
7835 * Validates a value according to the field's validation rules and marks the field as invalid
7836 * if the validation fails
7837 * @param {Mixed} value The value to validate
7838 * @return {Boolean} True if the value is valid, else false
7840 validateValue : function(value){
7841 if(value.length < 1) { // if it's blank
7842 if(this.allowBlank){
7848 if(value.length < this.minLength){
7851 if(value.length > this.maxLength){
7855 var vt = Roo.form.VTypes;
7856 if(!vt[this.vtype](value, this)){
7860 if(typeof this.validator == "function"){
7861 var msg = this.validator(value);
7867 if(this.regex && !this.regex.test(value)){
7877 fireKey : function(e){
7878 //Roo.log('field ' + e.getKey());
7879 if(e.isNavKeyPress()){
7880 this.fireEvent("specialkey", this, e);
7883 focus : function (selectText){
7885 this.inputEl().focus();
7886 if(selectText === true){
7887 this.inputEl().dom.select();
7893 onFocus : function(){
7894 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7895 // this.el.addClass(this.focusClass);
7898 this.hasFocus = true;
7899 this.startValue = this.getValue();
7900 this.fireEvent("focus", this);
7904 beforeBlur : Roo.emptyFn,
7908 onBlur : function(){
7910 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7911 //this.el.removeClass(this.focusClass);
7913 this.hasFocus = false;
7914 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7917 var v = this.getValue();
7918 if(String(v) !== String(this.startValue)){
7919 this.fireEvent('change', this, v, this.startValue);
7921 this.fireEvent("blur", this);
7925 * Resets the current field value to the originally loaded value and clears any validation messages
7928 this.setValue(this.originalValue);
7932 * Returns the name of the field
7933 * @return {Mixed} name The name field
7935 getName: function(){
7939 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7940 * @return {Mixed} value The field value
7942 getValue : function(){
7944 var v = this.inputEl().getValue();
7949 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7950 * @return {Mixed} value The field value
7952 getRawValue : function(){
7953 var v = this.inputEl().getValue();
7959 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7960 * @param {Mixed} value The value to set
7962 setRawValue : function(v){
7963 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7966 selectText : function(start, end){
7967 var v = this.getRawValue();
7969 start = start === undefined ? 0 : start;
7970 end = end === undefined ? v.length : end;
7971 var d = this.inputEl().dom;
7972 if(d.setSelectionRange){
7973 d.setSelectionRange(start, end);
7974 }else if(d.createTextRange){
7975 var range = d.createTextRange();
7976 range.moveStart("character", start);
7977 range.moveEnd("character", v.length-end);
7984 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7985 * @param {Mixed} value The value to set
7987 setValue : function(v){
7990 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7996 processValue : function(value){
7997 if(this.stripCharsRe){
7998 var newValue = value.replace(this.stripCharsRe, '');
7999 if(newValue !== value){
8000 this.setRawValue(newValue);
8007 preFocus : function(){
8009 if(this.selectOnFocus){
8010 this.inputEl().dom.select();
8013 filterKeys : function(e){
8015 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8018 var c = e.getCharCode(), cc = String.fromCharCode(c);
8019 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8022 if(!this.maskRe.test(cc)){
8027 * Clear any invalid styles/messages for this field
8029 clearInvalid : function(){
8031 if(!this.el || this.preventMark){ // not rendered
8034 this.el.removeClass(this.invalidClass);
8036 this.fireEvent('valid', this);
8040 * Mark this field as valid
8042 markValid : function(){
8043 if(!this.el || this.preventMark){ // not rendered
8047 this.el.removeClass([this.invalidClass, this.validClass]);
8049 if(this.disabled || this.allowBlank){
8053 this.el.addClass(this.validClass);
8055 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8057 var feedback = this.el.select('.form-control-feedback', true).first();
8060 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8061 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8066 this.fireEvent('valid', this);
8070 * Mark this field as invalid
8071 * @param {String} msg The validation message
8073 markInvalid : function(msg){
8074 if(!this.el || this.preventMark){ // not rendered
8078 this.el.removeClass([this.invalidClass, this.validClass]);
8080 if(this.disabled || this.allowBlank){
8084 this.el.addClass(this.invalidClass);
8086 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8088 var feedback = this.el.select('.form-control-feedback', true).first();
8091 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8093 if(this.getValue().length){
8094 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8101 this.fireEvent('invalid', this, msg);
8104 SafariOnKeyDown : function(event)
8106 // this is a workaround for a password hang bug on chrome/ webkit.
8108 var isSelectAll = false;
8110 if(this.inputEl().dom.selectionEnd > 0){
8111 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8113 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8114 event.preventDefault();
8119 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8121 event.preventDefault();
8122 // this is very hacky as keydown always get's upper case.
8124 var cc = String.fromCharCode(event.getCharCode());
8125 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8129 adjustWidth : function(tag, w){
8130 tag = tag.toLowerCase();
8131 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8132 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8136 if(tag == 'textarea'){
8139 }else if(Roo.isOpera){
8143 if(tag == 'textarea'){
8162 * @class Roo.bootstrap.TextArea
8163 * @extends Roo.bootstrap.Input
8164 * Bootstrap TextArea class
8165 * @cfg {Number} cols Specifies the visible width of a text area
8166 * @cfg {Number} rows Specifies the visible number of lines in a text area
8167 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8168 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8169 * @cfg {string} html text
8172 * Create a new TextArea
8173 * @param {Object} config The config object
8176 Roo.bootstrap.TextArea = function(config){
8177 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8181 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8191 getAutoCreate : function(){
8193 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8204 value : this.value || '',
8205 html: this.html || '',
8206 cls : 'form-control',
8207 placeholder : this.placeholder || ''
8211 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8212 input.maxLength = this.maxLength;
8216 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8220 input.cols = this.cols;
8223 if (this.readOnly) {
8224 input.readonly = true;
8228 input.name = this.name;
8232 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8236 ['xs','sm','md','lg'].map(function(size){
8237 if (settings[size]) {
8238 cfg.cls += ' col-' + size + '-' + settings[size];
8242 var inputblock = input;
8244 if(this.hasFeedback && !this.allowBlank){
8248 cls: 'glyphicon form-control-feedback'
8252 cls : 'has-feedback',
8261 if (this.before || this.after) {
8264 cls : 'input-group',
8268 inputblock.cn.push({
8270 cls : 'input-group-addon',
8275 inputblock.cn.push(input);
8277 if(this.hasFeedback && !this.allowBlank){
8278 inputblock.cls += ' has-feedback';
8279 inputblock.cn.push(feedback);
8283 inputblock.cn.push({
8285 cls : 'input-group-addon',
8292 if (align ==='left' && this.fieldLabel.length) {
8293 Roo.log("left and has label");
8299 cls : 'control-label col-sm-' + this.labelWidth,
8300 html : this.fieldLabel
8304 cls : "col-sm-" + (12 - this.labelWidth),
8311 } else if ( this.fieldLabel.length) {
8317 //cls : 'input-group-addon',
8318 html : this.fieldLabel
8328 Roo.log(" no label && no align");
8338 if (this.disabled) {
8339 input.disabled=true;
8346 * return the real textarea element.
8348 inputEl: function ()
8350 return this.el.select('textarea.form-control',true).first();
8358 * trigger field - base class for combo..
8363 * @class Roo.bootstrap.TriggerField
8364 * @extends Roo.bootstrap.Input
8365 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8366 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8367 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8368 * for which you can provide a custom implementation. For example:
8370 var trigger = new Roo.bootstrap.TriggerField();
8371 trigger.onTriggerClick = myTriggerFn;
8372 trigger.applyTo('my-field');
8375 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8376 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8377 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8378 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8379 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8382 * Create a new TriggerField.
8383 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8384 * to the base TextField)
8386 Roo.bootstrap.TriggerField = function(config){
8387 this.mimicing = false;
8388 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8391 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8393 * @cfg {String} triggerClass A CSS class to apply to the trigger
8396 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8400 /** @cfg {Boolean} grow @hide */
8401 /** @cfg {Number} growMin @hide */
8402 /** @cfg {Number} growMax @hide */
8408 autoSize: Roo.emptyFn,
8415 actionMode : 'wrap',
8420 getAutoCreate : function(){
8422 var align = this.labelAlign || this.parentLabelAlign();
8427 cls: 'form-group' //input-group
8434 type : this.inputType,
8435 cls : 'form-control',
8436 autocomplete: 'new-password',
8437 placeholder : this.placeholder || ''
8441 input.name = this.name;
8444 input.cls += ' input-' + this.size;
8447 if (this.disabled) {
8448 input.disabled=true;
8451 var inputblock = input;
8453 if(this.hasFeedback && !this.allowBlank){
8457 cls: 'glyphicon form-control-feedback'
8461 cls : 'has-feedback',
8469 if (this.before || this.after) {
8472 cls : 'input-group',
8476 inputblock.cn.push({
8478 cls : 'input-group-addon',
8483 inputblock.cn.push(input);
8485 if(this.hasFeedback && !this.allowBlank){
8486 inputblock.cls += ' has-feedback';
8487 inputblock.cn.push(feedback);
8491 inputblock.cn.push({
8493 cls : 'input-group-addon',
8506 cls: 'form-hidden-field'
8514 Roo.log('multiple');
8522 cls: 'form-hidden-field'
8526 cls: 'select2-choices',
8530 cls: 'select2-search-field',
8543 cls: 'select2-container input-group',
8548 // cls: 'typeahead typeahead-long dropdown-menu',
8549 // style: 'display:none'
8554 if(!this.multiple && this.showToggleBtn){
8560 if (this.caret != false) {
8563 cls: 'fa fa-' + this.caret
8570 cls : 'input-group-addon btn dropdown-toggle',
8575 cls: 'combobox-clear',
8589 combobox.cls += ' select2-container-multi';
8592 if (align ==='left' && this.fieldLabel.length) {
8594 Roo.log("left and has label");
8600 cls : 'control-label col-sm-' + this.labelWidth,
8601 html : this.fieldLabel
8605 cls : "col-sm-" + (12 - this.labelWidth),
8612 } else if ( this.fieldLabel.length) {
8618 //cls : 'input-group-addon',
8619 html : this.fieldLabel
8629 Roo.log(" no label && no align");
8636 ['xs','sm','md','lg'].map(function(size){
8637 if (settings[size]) {
8638 cfg.cls += ' col-' + size + '-' + settings[size];
8649 onResize : function(w, h){
8650 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8651 // if(typeof w == 'number'){
8652 // var x = w - this.trigger.getWidth();
8653 // this.inputEl().setWidth(this.adjustWidth('input', x));
8654 // this.trigger.setStyle('left', x+'px');
8659 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8662 getResizeEl : function(){
8663 return this.inputEl();
8667 getPositionEl : function(){
8668 return this.inputEl();
8672 alignErrorIcon : function(){
8673 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8677 initEvents : function(){
8681 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8682 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8683 if(!this.multiple && this.showToggleBtn){
8684 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8685 if(this.hideTrigger){
8686 this.trigger.setDisplayed(false);
8688 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8692 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8695 //this.trigger.addClassOnOver('x-form-trigger-over');
8696 //this.trigger.addClassOnClick('x-form-trigger-click');
8699 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8703 createList : function()
8705 this.list = Roo.get(document.body).createChild({
8707 cls: 'typeahead typeahead-long dropdown-menu',
8708 style: 'display:none'
8711 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8716 initTrigger : function(){
8721 onDestroy : function(){
8723 this.trigger.removeAllListeners();
8724 // this.trigger.remove();
8727 // this.wrap.remove();
8729 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8733 onFocus : function(){
8734 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8737 this.wrap.addClass('x-trigger-wrap-focus');
8738 this.mimicing = true;
8739 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8740 if(this.monitorTab){
8741 this.el.on("keydown", this.checkTab, this);
8748 checkTab : function(e){
8749 if(e.getKey() == e.TAB){
8755 onBlur : function(){
8760 mimicBlur : function(e, t){
8762 if(!this.wrap.contains(t) && this.validateBlur()){
8769 triggerBlur : function(){
8770 this.mimicing = false;
8771 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8772 if(this.monitorTab){
8773 this.el.un("keydown", this.checkTab, this);
8775 //this.wrap.removeClass('x-trigger-wrap-focus');
8776 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8780 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8781 validateBlur : function(e, t){
8786 onDisable : function(){
8787 this.inputEl().dom.disabled = true;
8788 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8790 // this.wrap.addClass('x-item-disabled');
8795 onEnable : function(){
8796 this.inputEl().dom.disabled = false;
8797 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8799 // this.el.removeClass('x-item-disabled');
8804 onShow : function(){
8805 var ae = this.getActionEl();
8808 ae.dom.style.display = '';
8809 ae.dom.style.visibility = 'visible';
8815 onHide : function(){
8816 var ae = this.getActionEl();
8817 ae.dom.style.display = 'none';
8821 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8822 * by an implementing function.
8824 * @param {EventObject} e
8826 onTriggerClick : Roo.emptyFn
8830 * Ext JS Library 1.1.1
8831 * Copyright(c) 2006-2007, Ext JS, LLC.
8833 * Originally Released Under LGPL - original licence link has changed is not relivant.
8836 * <script type="text/javascript">
8841 * @class Roo.data.SortTypes
8843 * Defines the default sorting (casting?) comparison functions used when sorting data.
8845 Roo.data.SortTypes = {
8847 * Default sort that does nothing
8848 * @param {Mixed} s The value being converted
8849 * @return {Mixed} The comparison value
8856 * The regular expression used to strip tags
8860 stripTagsRE : /<\/?[^>]+>/gi,
8863 * Strips all HTML tags to sort on text only
8864 * @param {Mixed} s The value being converted
8865 * @return {String} The comparison value
8867 asText : function(s){
8868 return String(s).replace(this.stripTagsRE, "");
8872 * Strips all HTML tags to sort on text only - Case insensitive
8873 * @param {Mixed} s The value being converted
8874 * @return {String} The comparison value
8876 asUCText : function(s){
8877 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8881 * Case insensitive string
8882 * @param {Mixed} s The value being converted
8883 * @return {String} The comparison value
8885 asUCString : function(s) {
8886 return String(s).toUpperCase();
8891 * @param {Mixed} s The value being converted
8892 * @return {Number} The comparison value
8894 asDate : function(s) {
8898 if(s instanceof Date){
8901 return Date.parse(String(s));
8906 * @param {Mixed} s The value being converted
8907 * @return {Float} The comparison value
8909 asFloat : function(s) {
8910 var val = parseFloat(String(s).replace(/,/g, ""));
8911 if(isNaN(val)) val = 0;
8917 * @param {Mixed} s The value being converted
8918 * @return {Number} The comparison value
8920 asInt : function(s) {
8921 var val = parseInt(String(s).replace(/,/g, ""));
8922 if(isNaN(val)) val = 0;
8927 * Ext JS Library 1.1.1
8928 * Copyright(c) 2006-2007, Ext JS, LLC.
8930 * Originally Released Under LGPL - original licence link has changed is not relivant.
8933 * <script type="text/javascript">
8937 * @class Roo.data.Record
8938 * Instances of this class encapsulate both record <em>definition</em> information, and record
8939 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8940 * to access Records cached in an {@link Roo.data.Store} object.<br>
8942 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8943 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8946 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8948 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8949 * {@link #create}. The parameters are the same.
8950 * @param {Array} data An associative Array of data values keyed by the field name.
8951 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8952 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8953 * not specified an integer id is generated.
8955 Roo.data.Record = function(data, id){
8956 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8961 * Generate a constructor for a specific record layout.
8962 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8963 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8964 * Each field definition object may contain the following properties: <ul>
8965 * <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,
8966 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8967 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8968 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8969 * is being used, then this is a string containing the javascript expression to reference the data relative to
8970 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8971 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8972 * this may be omitted.</p></li>
8973 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8974 * <ul><li>auto (Default, implies no conversion)</li>
8979 * <li>date</li></ul></p></li>
8980 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8981 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8982 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8983 * by the Reader into an object that will be stored in the Record. It is passed the
8984 * following parameters:<ul>
8985 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8987 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8989 * <br>usage:<br><pre><code>
8990 var TopicRecord = Roo.data.Record.create(
8991 {name: 'title', mapping: 'topic_title'},
8992 {name: 'author', mapping: 'username'},
8993 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8994 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8995 {name: 'lastPoster', mapping: 'user2'},
8996 {name: 'excerpt', mapping: 'post_text'}
8999 var myNewRecord = new TopicRecord({
9000 title: 'Do my job please',
9003 lastPost: new Date(),
9004 lastPoster: 'Animal',
9005 excerpt: 'No way dude!'
9007 myStore.add(myNewRecord);
9012 Roo.data.Record.create = function(o){
9014 f.superclass.constructor.apply(this, arguments);
9016 Roo.extend(f, Roo.data.Record);
9017 var p = f.prototype;
9018 p.fields = new Roo.util.MixedCollection(false, function(field){
9021 for(var i = 0, len = o.length; i < len; i++){
9022 p.fields.add(new Roo.data.Field(o[i]));
9024 f.getField = function(name){
9025 return p.fields.get(name);
9030 Roo.data.Record.AUTO_ID = 1000;
9031 Roo.data.Record.EDIT = 'edit';
9032 Roo.data.Record.REJECT = 'reject';
9033 Roo.data.Record.COMMIT = 'commit';
9035 Roo.data.Record.prototype = {
9037 * Readonly flag - true if this record has been modified.
9046 join : function(store){
9051 * Set the named field to the specified value.
9052 * @param {String} name The name of the field to set.
9053 * @param {Object} value The value to set the field to.
9055 set : function(name, value){
9056 if(this.data[name] == value){
9063 if(typeof this.modified[name] == 'undefined'){
9064 this.modified[name] = this.data[name];
9066 this.data[name] = value;
9067 if(!this.editing && this.store){
9068 this.store.afterEdit(this);
9073 * Get the value of the named field.
9074 * @param {String} name The name of the field to get the value of.
9075 * @return {Object} The value of the field.
9077 get : function(name){
9078 return this.data[name];
9082 beginEdit : function(){
9083 this.editing = true;
9088 cancelEdit : function(){
9089 this.editing = false;
9090 delete this.modified;
9094 endEdit : function(){
9095 this.editing = false;
9096 if(this.dirty && this.store){
9097 this.store.afterEdit(this);
9102 * Usually called by the {@link Roo.data.Store} which owns the Record.
9103 * Rejects all changes made to the Record since either creation, or the last commit operation.
9104 * Modified fields are reverted to their original values.
9106 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9107 * of reject operations.
9109 reject : function(){
9110 var m = this.modified;
9112 if(typeof m[n] != "function"){
9113 this.data[n] = m[n];
9117 delete this.modified;
9118 this.editing = false;
9120 this.store.afterReject(this);
9125 * Usually called by the {@link Roo.data.Store} which owns the Record.
9126 * Commits all changes made to the Record since either creation, or the last commit operation.
9128 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9129 * of commit operations.
9131 commit : function(){
9133 delete this.modified;
9134 this.editing = false;
9136 this.store.afterCommit(this);
9141 hasError : function(){
9142 return this.error != null;
9146 clearError : function(){
9151 * Creates a copy of this record.
9152 * @param {String} id (optional) A new record id if you don't want to use this record's id
9155 copy : function(newId) {
9156 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9160 * Ext JS Library 1.1.1
9161 * Copyright(c) 2006-2007, Ext JS, LLC.
9163 * Originally Released Under LGPL - original licence link has changed is not relivant.
9166 * <script type="text/javascript">
9172 * @class Roo.data.Store
9173 * @extends Roo.util.Observable
9174 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9175 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9177 * 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
9178 * has no knowledge of the format of the data returned by the Proxy.<br>
9180 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9181 * instances from the data object. These records are cached and made available through accessor functions.
9183 * Creates a new Store.
9184 * @param {Object} config A config object containing the objects needed for the Store to access data,
9185 * and read the data into Records.
9187 Roo.data.Store = function(config){
9188 this.data = new Roo.util.MixedCollection(false);
9189 this.data.getKey = function(o){
9192 this.baseParams = {};
9199 "multisort" : "_multisort"
9202 if(config && config.data){
9203 this.inlineData = config.data;
9207 Roo.apply(this, config);
9209 if(this.reader){ // reader passed
9210 this.reader = Roo.factory(this.reader, Roo.data);
9211 this.reader.xmodule = this.xmodule || false;
9212 if(!this.recordType){
9213 this.recordType = this.reader.recordType;
9215 if(this.reader.onMetaChange){
9216 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9220 if(this.recordType){
9221 this.fields = this.recordType.prototype.fields;
9227 * @event datachanged
9228 * Fires when the data cache has changed, and a widget which is using this Store
9229 * as a Record cache should refresh its view.
9230 * @param {Store} this
9235 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9236 * @param {Store} this
9237 * @param {Object} meta The JSON metadata
9242 * Fires when Records have been added to the Store
9243 * @param {Store} this
9244 * @param {Roo.data.Record[]} records The array of Records added
9245 * @param {Number} index The index at which the record(s) were added
9250 * Fires when a Record has been removed from the Store
9251 * @param {Store} this
9252 * @param {Roo.data.Record} record The Record that was removed
9253 * @param {Number} index The index at which the record was removed
9258 * Fires when a Record has been updated
9259 * @param {Store} this
9260 * @param {Roo.data.Record} record The Record that was updated
9261 * @param {String} operation The update operation being performed. Value may be one of:
9263 Roo.data.Record.EDIT
9264 Roo.data.Record.REJECT
9265 Roo.data.Record.COMMIT
9271 * Fires when the data cache has been cleared.
9272 * @param {Store} this
9277 * Fires before a request is made for a new data object. If the beforeload handler returns false
9278 * the load action will be canceled.
9279 * @param {Store} this
9280 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9284 * @event beforeloadadd
9285 * Fires after a new set of Records has been loaded.
9286 * @param {Store} this
9287 * @param {Roo.data.Record[]} records The Records that were loaded
9288 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9290 beforeloadadd : true,
9293 * Fires after a new set of Records has been loaded, before they are added to the store.
9294 * @param {Store} this
9295 * @param {Roo.data.Record[]} records The Records that were loaded
9296 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9297 * @params {Object} return from reader
9301 * @event loadexception
9302 * Fires if an exception occurs in the Proxy during loading.
9303 * Called with the signature of the Proxy's "loadexception" event.
9304 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9307 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9308 * @param {Object} load options
9309 * @param {Object} jsonData from your request (normally this contains the Exception)
9311 loadexception : true
9315 this.proxy = Roo.factory(this.proxy, Roo.data);
9316 this.proxy.xmodule = this.xmodule || false;
9317 this.relayEvents(this.proxy, ["loadexception"]);
9319 this.sortToggle = {};
9320 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9322 Roo.data.Store.superclass.constructor.call(this);
9324 if(this.inlineData){
9325 this.loadData(this.inlineData);
9326 delete this.inlineData;
9330 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9332 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9333 * without a remote query - used by combo/forms at present.
9337 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9340 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9343 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9344 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9347 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9348 * on any HTTP request
9351 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9354 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9358 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9359 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9364 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9365 * loaded or when a record is removed. (defaults to false).
9367 pruneModifiedRecords : false,
9373 * Add Records to the Store and fires the add event.
9374 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9376 add : function(records){
9377 records = [].concat(records);
9378 for(var i = 0, len = records.length; i < len; i++){
9379 records[i].join(this);
9381 var index = this.data.length;
9382 this.data.addAll(records);
9383 this.fireEvent("add", this, records, index);
9387 * Remove a Record from the Store and fires the remove event.
9388 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9390 remove : function(record){
9391 var index = this.data.indexOf(record);
9392 this.data.removeAt(index);
9393 if(this.pruneModifiedRecords){
9394 this.modified.remove(record);
9396 this.fireEvent("remove", this, record, index);
9400 * Remove all Records from the Store and fires the clear event.
9402 removeAll : function(){
9404 if(this.pruneModifiedRecords){
9407 this.fireEvent("clear", this);
9411 * Inserts Records to the Store at the given index and fires the add event.
9412 * @param {Number} index The start index at which to insert the passed Records.
9413 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9415 insert : function(index, records){
9416 records = [].concat(records);
9417 for(var i = 0, len = records.length; i < len; i++){
9418 this.data.insert(index, records[i]);
9419 records[i].join(this);
9421 this.fireEvent("add", this, records, index);
9425 * Get the index within the cache of the passed Record.
9426 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9427 * @return {Number} The index of the passed Record. Returns -1 if not found.
9429 indexOf : function(record){
9430 return this.data.indexOf(record);
9434 * Get the index within the cache of the Record with the passed id.
9435 * @param {String} id The id of the Record to find.
9436 * @return {Number} The index of the Record. Returns -1 if not found.
9438 indexOfId : function(id){
9439 return this.data.indexOfKey(id);
9443 * Get the Record with the specified id.
9444 * @param {String} id The id of the Record to find.
9445 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9447 getById : function(id){
9448 return this.data.key(id);
9452 * Get the Record at the specified index.
9453 * @param {Number} index The index of the Record to find.
9454 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9456 getAt : function(index){
9457 return this.data.itemAt(index);
9461 * Returns a range of Records between specified indices.
9462 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9463 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9464 * @return {Roo.data.Record[]} An array of Records
9466 getRange : function(start, end){
9467 return this.data.getRange(start, end);
9471 storeOptions : function(o){
9472 o = Roo.apply({}, o);
9475 this.lastOptions = o;
9479 * Loads the Record cache from the configured Proxy using the configured Reader.
9481 * If using remote paging, then the first load call must specify the <em>start</em>
9482 * and <em>limit</em> properties in the options.params property to establish the initial
9483 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9485 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9486 * and this call will return before the new data has been loaded. Perform any post-processing
9487 * in a callback function, or in a "load" event handler.</strong>
9489 * @param {Object} options An object containing properties which control loading options:<ul>
9490 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9491 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9492 * passed the following arguments:<ul>
9493 * <li>r : Roo.data.Record[]</li>
9494 * <li>options: Options object from the load call</li>
9495 * <li>success: Boolean success indicator</li></ul></li>
9496 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9497 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9500 load : function(options){
9501 options = options || {};
9502 if(this.fireEvent("beforeload", this, options) !== false){
9503 this.storeOptions(options);
9504 var p = Roo.apply(options.params || {}, this.baseParams);
9505 // if meta was not loaded from remote source.. try requesting it.
9506 if (!this.reader.metaFromRemote) {
9509 if(this.sortInfo && this.remoteSort){
9510 var pn = this.paramNames;
9511 p[pn["sort"]] = this.sortInfo.field;
9512 p[pn["dir"]] = this.sortInfo.direction;
9514 if (this.multiSort) {
9515 var pn = this.paramNames;
9516 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9519 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9524 * Reloads the Record cache from the configured Proxy using the configured Reader and
9525 * the options from the last load operation performed.
9526 * @param {Object} options (optional) An object containing properties which may override the options
9527 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9528 * the most recently used options are reused).
9530 reload : function(options){
9531 this.load(Roo.applyIf(options||{}, this.lastOptions));
9535 // Called as a callback by the Reader during a load operation.
9536 loadRecords : function(o, options, success){
9537 if(!o || success === false){
9538 if(success !== false){
9539 this.fireEvent("load", this, [], options, o);
9541 if(options.callback){
9542 options.callback.call(options.scope || this, [], options, false);
9546 // if data returned failure - throw an exception.
9547 if (o.success === false) {
9548 // show a message if no listener is registered.
9549 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9550 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9552 // loadmask wil be hooked into this..
9553 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9556 var r = o.records, t = o.totalRecords || r.length;
9558 this.fireEvent("beforeloadadd", this, r, options, o);
9560 if(!options || options.add !== true){
9561 if(this.pruneModifiedRecords){
9564 for(var i = 0, len = r.length; i < len; i++){
9568 this.data = this.snapshot;
9569 delete this.snapshot;
9572 this.data.addAll(r);
9573 this.totalLength = t;
9575 this.fireEvent("datachanged", this);
9577 this.totalLength = Math.max(t, this.data.length+r.length);
9580 this.fireEvent("load", this, r, options, o);
9581 if(options.callback){
9582 options.callback.call(options.scope || this, r, options, true);
9588 * Loads data from a passed data block. A Reader which understands the format of the data
9589 * must have been configured in the constructor.
9590 * @param {Object} data The data block from which to read the Records. The format of the data expected
9591 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9592 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9594 loadData : function(o, append){
9595 var r = this.reader.readRecords(o);
9596 this.loadRecords(r, {add: append}, true);
9600 * Gets the number of cached records.
9602 * <em>If using paging, this may not be the total size of the dataset. If the data object
9603 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9604 * the data set size</em>
9606 getCount : function(){
9607 return this.data.length || 0;
9611 * Gets the total number of records in the dataset as returned by the server.
9613 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9614 * the dataset size</em>
9616 getTotalCount : function(){
9617 return this.totalLength || 0;
9621 * Returns the sort state of the Store as an object with two properties:
9623 field {String} The name of the field by which the Records are sorted
9624 direction {String} The sort order, "ASC" or "DESC"
9627 getSortState : function(){
9628 return this.sortInfo;
9632 applySort : function(){
9633 if(this.sortInfo && !this.remoteSort){
9634 var s = this.sortInfo, f = s.field;
9635 var st = this.fields.get(f).sortType;
9636 var fn = function(r1, r2){
9637 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9638 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9640 this.data.sort(s.direction, fn);
9641 if(this.snapshot && this.snapshot != this.data){
9642 this.snapshot.sort(s.direction, fn);
9648 * Sets the default sort column and order to be used by the next load operation.
9649 * @param {String} fieldName The name of the field to sort by.
9650 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9652 setDefaultSort : function(field, dir){
9653 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9658 * If remote sorting is used, the sort is performed on the server, and the cache is
9659 * reloaded. If local sorting is used, the cache is sorted internally.
9660 * @param {String} fieldName The name of the field to sort by.
9661 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9663 sort : function(fieldName, dir){
9664 var f = this.fields.get(fieldName);
9666 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9668 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9669 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9674 this.sortToggle[f.name] = dir;
9675 this.sortInfo = {field: f.name, direction: dir};
9676 if(!this.remoteSort){
9678 this.fireEvent("datachanged", this);
9680 this.load(this.lastOptions);
9685 * Calls the specified function for each of the Records in the cache.
9686 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9687 * Returning <em>false</em> aborts and exits the iteration.
9688 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9690 each : function(fn, scope){
9691 this.data.each(fn, scope);
9695 * Gets all records modified since the last commit. Modified records are persisted across load operations
9696 * (e.g., during paging).
9697 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9699 getModifiedRecords : function(){
9700 return this.modified;
9704 createFilterFn : function(property, value, anyMatch){
9705 if(!value.exec){ // not a regex
9706 value = String(value);
9707 if(value.length == 0){
9710 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9713 return value.test(r.data[property]);
9718 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9719 * @param {String} property A field on your records
9720 * @param {Number} start The record index to start at (defaults to 0)
9721 * @param {Number} end The last record index to include (defaults to length - 1)
9722 * @return {Number} The sum
9724 sum : function(property, start, end){
9725 var rs = this.data.items, v = 0;
9727 end = (end || end === 0) ? end : rs.length-1;
9729 for(var i = start; i <= end; i++){
9730 v += (rs[i].data[property] || 0);
9736 * Filter the records by a specified property.
9737 * @param {String} field A field on your records
9738 * @param {String/RegExp} value Either a string that the field
9739 * should start with or a RegExp to test against the field
9740 * @param {Boolean} anyMatch True to match any part not just the beginning
9742 filter : function(property, value, anyMatch){
9743 var fn = this.createFilterFn(property, value, anyMatch);
9744 return fn ? this.filterBy(fn) : this.clearFilter();
9748 * Filter by a function. The specified function will be called with each
9749 * record in this data source. If the function returns true the record is included,
9750 * otherwise it is filtered.
9751 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9752 * @param {Object} scope (optional) The scope of the function (defaults to this)
9754 filterBy : function(fn, scope){
9755 this.snapshot = this.snapshot || this.data;
9756 this.data = this.queryBy(fn, scope||this);
9757 this.fireEvent("datachanged", this);
9761 * Query the records by a specified property.
9762 * @param {String} field A field on your records
9763 * @param {String/RegExp} value Either a string that the field
9764 * should start with or a RegExp to test against the field
9765 * @param {Boolean} anyMatch True to match any part not just the beginning
9766 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9768 query : function(property, value, anyMatch){
9769 var fn = this.createFilterFn(property, value, anyMatch);
9770 return fn ? this.queryBy(fn) : this.data.clone();
9774 * Query by a function. The specified function will be called with each
9775 * record in this data source. If the function returns true the record is included
9777 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9778 * @param {Object} scope (optional) The scope of the function (defaults to this)
9779 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9781 queryBy : function(fn, scope){
9782 var data = this.snapshot || this.data;
9783 return data.filterBy(fn, scope||this);
9787 * Collects unique values for a particular dataIndex from this store.
9788 * @param {String} dataIndex The property to collect
9789 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9790 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9791 * @return {Array} An array of the unique values
9793 collect : function(dataIndex, allowNull, bypassFilter){
9794 var d = (bypassFilter === true && this.snapshot) ?
9795 this.snapshot.items : this.data.items;
9796 var v, sv, r = [], l = {};
9797 for(var i = 0, len = d.length; i < len; i++){
9798 v = d[i].data[dataIndex];
9800 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9809 * Revert to a view of the Record cache with no filtering applied.
9810 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9812 clearFilter : function(suppressEvent){
9813 if(this.snapshot && this.snapshot != this.data){
9814 this.data = this.snapshot;
9815 delete this.snapshot;
9816 if(suppressEvent !== true){
9817 this.fireEvent("datachanged", this);
9823 afterEdit : function(record){
9824 if(this.modified.indexOf(record) == -1){
9825 this.modified.push(record);
9827 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9831 afterReject : function(record){
9832 this.modified.remove(record);
9833 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9837 afterCommit : function(record){
9838 this.modified.remove(record);
9839 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9843 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9844 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9846 commitChanges : function(){
9847 var m = this.modified.slice(0);
9849 for(var i = 0, len = m.length; i < len; i++){
9855 * Cancel outstanding changes on all changed records.
9857 rejectChanges : function(){
9858 var m = this.modified.slice(0);
9860 for(var i = 0, len = m.length; i < len; i++){
9865 onMetaChange : function(meta, rtype, o){
9866 this.recordType = rtype;
9867 this.fields = rtype.prototype.fields;
9868 delete this.snapshot;
9869 this.sortInfo = meta.sortInfo || this.sortInfo;
9871 this.fireEvent('metachange', this, this.reader.meta);
9874 moveIndex : function(data, type)
9876 var index = this.indexOf(data);
9878 var newIndex = index + type;
9882 this.insert(newIndex, data);
9887 * Ext JS Library 1.1.1
9888 * Copyright(c) 2006-2007, Ext JS, LLC.
9890 * Originally Released Under LGPL - original licence link has changed is not relivant.
9893 * <script type="text/javascript">
9897 * @class Roo.data.SimpleStore
9898 * @extends Roo.data.Store
9899 * Small helper class to make creating Stores from Array data easier.
9900 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9901 * @cfg {Array} fields An array of field definition objects, or field name strings.
9902 * @cfg {Array} data The multi-dimensional array of data
9904 * @param {Object} config
9906 Roo.data.SimpleStore = function(config){
9907 Roo.data.SimpleStore.superclass.constructor.call(this, {
9909 reader: new Roo.data.ArrayReader({
9912 Roo.data.Record.create(config.fields)
9914 proxy : new Roo.data.MemoryProxy(config.data)
9918 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9920 * Ext JS Library 1.1.1
9921 * Copyright(c) 2006-2007, Ext JS, LLC.
9923 * Originally Released Under LGPL - original licence link has changed is not relivant.
9926 * <script type="text/javascript">
9931 * @extends Roo.data.Store
9932 * @class Roo.data.JsonStore
9933 * Small helper class to make creating Stores for JSON data easier. <br/>
9935 var store = new Roo.data.JsonStore({
9936 url: 'get-images.php',
9938 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9941 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9942 * JsonReader and HttpProxy (unless inline data is provided).</b>
9943 * @cfg {Array} fields An array of field definition objects, or field name strings.
9945 * @param {Object} config
9947 Roo.data.JsonStore = function(c){
9948 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9949 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9950 reader: new Roo.data.JsonReader(c, c.fields)
9953 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9955 * Ext JS Library 1.1.1
9956 * Copyright(c) 2006-2007, Ext JS, LLC.
9958 * Originally Released Under LGPL - original licence link has changed is not relivant.
9961 * <script type="text/javascript">
9965 Roo.data.Field = function(config){
9966 if(typeof config == "string"){
9967 config = {name: config};
9969 Roo.apply(this, config);
9975 var st = Roo.data.SortTypes;
9976 // named sortTypes are supported, here we look them up
9977 if(typeof this.sortType == "string"){
9978 this.sortType = st[this.sortType];
9981 // set default sortType for strings and dates
9985 this.sortType = st.asUCString;
9988 this.sortType = st.asDate;
9991 this.sortType = st.none;
9996 var stripRe = /[\$,%]/g;
9998 // prebuilt conversion function for this field, instead of
9999 // switching every time we're reading a value
10001 var cv, dateFormat = this.dateFormat;
10006 cv = function(v){ return v; };
10009 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10013 return v !== undefined && v !== null && v !== '' ?
10014 parseInt(String(v).replace(stripRe, ""), 10) : '';
10019 return v !== undefined && v !== null && v !== '' ?
10020 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10025 cv = function(v){ return v === true || v === "true" || v == 1; };
10032 if(v instanceof Date){
10036 if(dateFormat == "timestamp"){
10037 return new Date(v*1000);
10039 return Date.parseDate(v, dateFormat);
10041 var parsed = Date.parse(v);
10042 return parsed ? new Date(parsed) : null;
10051 Roo.data.Field.prototype = {
10059 * Ext JS Library 1.1.1
10060 * Copyright(c) 2006-2007, Ext JS, LLC.
10062 * Originally Released Under LGPL - original licence link has changed is not relivant.
10065 * <script type="text/javascript">
10068 // Base class for reading structured data from a data source. This class is intended to be
10069 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10072 * @class Roo.data.DataReader
10073 * Base class for reading structured data from a data source. This class is intended to be
10074 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10077 Roo.data.DataReader = function(meta, recordType){
10081 this.recordType = recordType instanceof Array ?
10082 Roo.data.Record.create(recordType) : recordType;
10085 Roo.data.DataReader.prototype = {
10087 * Create an empty record
10088 * @param {Object} data (optional) - overlay some values
10089 * @return {Roo.data.Record} record created.
10091 newRow : function(d) {
10093 this.recordType.prototype.fields.each(function(c) {
10095 case 'int' : da[c.name] = 0; break;
10096 case 'date' : da[c.name] = new Date(); break;
10097 case 'float' : da[c.name] = 0.0; break;
10098 case 'boolean' : da[c.name] = false; break;
10099 default : da[c.name] = ""; break;
10103 return new this.recordType(Roo.apply(da, d));
10108 * Ext JS Library 1.1.1
10109 * Copyright(c) 2006-2007, Ext JS, LLC.
10111 * Originally Released Under LGPL - original licence link has changed is not relivant.
10114 * <script type="text/javascript">
10118 * @class Roo.data.DataProxy
10119 * @extends Roo.data.Observable
10120 * This class is an abstract base class for implementations which provide retrieval of
10121 * unformatted data objects.<br>
10123 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10124 * (of the appropriate type which knows how to parse the data object) to provide a block of
10125 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10127 * Custom implementations must implement the load method as described in
10128 * {@link Roo.data.HttpProxy#load}.
10130 Roo.data.DataProxy = function(){
10133 * @event beforeload
10134 * Fires before a network request is made to retrieve a data object.
10135 * @param {Object} This DataProxy object.
10136 * @param {Object} params The params parameter to the load function.
10141 * Fires before the load method's callback is called.
10142 * @param {Object} This DataProxy object.
10143 * @param {Object} o The data object.
10144 * @param {Object} arg The callback argument object passed to the load function.
10148 * @event loadexception
10149 * Fires if an Exception occurs during data retrieval.
10150 * @param {Object} This DataProxy object.
10151 * @param {Object} o The data object.
10152 * @param {Object} arg The callback argument object passed to the load function.
10153 * @param {Object} e The Exception.
10155 loadexception : true
10157 Roo.data.DataProxy.superclass.constructor.call(this);
10160 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10163 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10167 * Ext JS Library 1.1.1
10168 * Copyright(c) 2006-2007, Ext JS, LLC.
10170 * Originally Released Under LGPL - original licence link has changed is not relivant.
10173 * <script type="text/javascript">
10176 * @class Roo.data.MemoryProxy
10177 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10178 * to the Reader when its load method is called.
10180 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10182 Roo.data.MemoryProxy = function(data){
10186 Roo.data.MemoryProxy.superclass.constructor.call(this);
10190 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10192 * Load data from the requested source (in this case an in-memory
10193 * data object passed to the constructor), read the data object into
10194 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10195 * process that block using the passed callback.
10196 * @param {Object} params This parameter is not used by the MemoryProxy class.
10197 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10198 * object into a block of Roo.data.Records.
10199 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10200 * The function must be passed <ul>
10201 * <li>The Record block object</li>
10202 * <li>The "arg" argument from the load function</li>
10203 * <li>A boolean success indicator</li>
10205 * @param {Object} scope The scope in which to call the callback
10206 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10208 load : function(params, reader, callback, scope, arg){
10209 params = params || {};
10212 result = reader.readRecords(this.data);
10214 this.fireEvent("loadexception", this, arg, null, e);
10215 callback.call(scope, null, arg, false);
10218 callback.call(scope, result, arg, true);
10222 update : function(params, records){
10227 * Ext JS Library 1.1.1
10228 * Copyright(c) 2006-2007, Ext JS, LLC.
10230 * Originally Released Under LGPL - original licence link has changed is not relivant.
10233 * <script type="text/javascript">
10236 * @class Roo.data.HttpProxy
10237 * @extends Roo.data.DataProxy
10238 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10239 * configured to reference a certain URL.<br><br>
10241 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10242 * from which the running page was served.<br><br>
10244 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10246 * Be aware that to enable the browser to parse an XML document, the server must set
10247 * the Content-Type header in the HTTP response to "text/xml".
10249 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10250 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10251 * will be used to make the request.
10253 Roo.data.HttpProxy = function(conn){
10254 Roo.data.HttpProxy.superclass.constructor.call(this);
10255 // is conn a conn config or a real conn?
10257 this.useAjax = !conn || !conn.events;
10261 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10262 // thse are take from connection...
10265 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10268 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10269 * extra parameters to each request made by this object. (defaults to undefined)
10272 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10273 * to each request made by this object. (defaults to undefined)
10276 * @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)
10279 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10282 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10288 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10292 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10293 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10294 * a finer-grained basis than the DataProxy events.
10296 getConnection : function(){
10297 return this.useAjax ? Roo.Ajax : this.conn;
10301 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10302 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10303 * process that block using the passed callback.
10304 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10305 * for the request to the remote server.
10306 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10307 * object into a block of Roo.data.Records.
10308 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10309 * The function must be passed <ul>
10310 * <li>The Record block object</li>
10311 * <li>The "arg" argument from the load function</li>
10312 * <li>A boolean success indicator</li>
10314 * @param {Object} scope The scope in which to call the callback
10315 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10317 load : function(params, reader, callback, scope, arg){
10318 if(this.fireEvent("beforeload", this, params) !== false){
10320 params : params || {},
10322 callback : callback,
10327 callback : this.loadResponse,
10331 Roo.applyIf(o, this.conn);
10332 if(this.activeRequest){
10333 Roo.Ajax.abort(this.activeRequest);
10335 this.activeRequest = Roo.Ajax.request(o);
10337 this.conn.request(o);
10340 callback.call(scope||this, null, arg, false);
10345 loadResponse : function(o, success, response){
10346 delete this.activeRequest;
10348 this.fireEvent("loadexception", this, o, response);
10349 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10354 result = o.reader.read(response);
10356 this.fireEvent("loadexception", this, o, response, e);
10357 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10361 this.fireEvent("load", this, o, o.request.arg);
10362 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10366 update : function(dataSet){
10371 updateResponse : function(dataSet){
10376 * Ext JS Library 1.1.1
10377 * Copyright(c) 2006-2007, Ext JS, LLC.
10379 * Originally Released Under LGPL - original licence link has changed is not relivant.
10382 * <script type="text/javascript">
10386 * @class Roo.data.ScriptTagProxy
10387 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10388 * other than the originating domain of the running page.<br><br>
10390 * <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
10391 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10393 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10394 * source code that is used as the source inside a <script> tag.<br><br>
10396 * In order for the browser to process the returned data, the server must wrap the data object
10397 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10398 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10399 * depending on whether the callback name was passed:
10402 boolean scriptTag = false;
10403 String cb = request.getParameter("callback");
10406 response.setContentType("text/javascript");
10408 response.setContentType("application/x-json");
10410 Writer out = response.getWriter();
10412 out.write(cb + "(");
10414 out.print(dataBlock.toJsonString());
10421 * @param {Object} config A configuration object.
10423 Roo.data.ScriptTagProxy = function(config){
10424 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10425 Roo.apply(this, config);
10426 this.head = document.getElementsByTagName("head")[0];
10429 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10431 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10433 * @cfg {String} url The URL from which to request the data object.
10436 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10440 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10441 * the server the name of the callback function set up by the load call to process the returned data object.
10442 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10443 * javascript output which calls this named function passing the data object as its only parameter.
10445 callbackParam : "callback",
10447 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10448 * name to the request.
10453 * Load data from the configured URL, read the data object into
10454 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10455 * process that block using the passed callback.
10456 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10457 * for the request to the remote server.
10458 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10459 * object into a block of Roo.data.Records.
10460 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10461 * The function must be passed <ul>
10462 * <li>The Record block object</li>
10463 * <li>The "arg" argument from the load function</li>
10464 * <li>A boolean success indicator</li>
10466 * @param {Object} scope The scope in which to call the callback
10467 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10469 load : function(params, reader, callback, scope, arg){
10470 if(this.fireEvent("beforeload", this, params) !== false){
10472 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10474 var url = this.url;
10475 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10477 url += "&_dc=" + (new Date().getTime());
10479 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10482 cb : "stcCallback"+transId,
10483 scriptId : "stcScript"+transId,
10487 callback : callback,
10493 window[trans.cb] = function(o){
10494 conn.handleResponse(o, trans);
10497 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10499 if(this.autoAbort !== false){
10503 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10505 var script = document.createElement("script");
10506 script.setAttribute("src", url);
10507 script.setAttribute("type", "text/javascript");
10508 script.setAttribute("id", trans.scriptId);
10509 this.head.appendChild(script);
10511 this.trans = trans;
10513 callback.call(scope||this, null, arg, false);
10518 isLoading : function(){
10519 return this.trans ? true : false;
10523 * Abort the current server request.
10525 abort : function(){
10526 if(this.isLoading()){
10527 this.destroyTrans(this.trans);
10532 destroyTrans : function(trans, isLoaded){
10533 this.head.removeChild(document.getElementById(trans.scriptId));
10534 clearTimeout(trans.timeoutId);
10536 window[trans.cb] = undefined;
10538 delete window[trans.cb];
10541 // if hasn't been loaded, wait for load to remove it to prevent script error
10542 window[trans.cb] = function(){
10543 window[trans.cb] = undefined;
10545 delete window[trans.cb];
10552 handleResponse : function(o, trans){
10553 this.trans = false;
10554 this.destroyTrans(trans, true);
10557 result = trans.reader.readRecords(o);
10559 this.fireEvent("loadexception", this, o, trans.arg, e);
10560 trans.callback.call(trans.scope||window, null, trans.arg, false);
10563 this.fireEvent("load", this, o, trans.arg);
10564 trans.callback.call(trans.scope||window, result, trans.arg, true);
10568 handleFailure : function(trans){
10569 this.trans = false;
10570 this.destroyTrans(trans, false);
10571 this.fireEvent("loadexception", this, null, trans.arg);
10572 trans.callback.call(trans.scope||window, null, trans.arg, false);
10576 * Ext JS Library 1.1.1
10577 * Copyright(c) 2006-2007, Ext JS, LLC.
10579 * Originally Released Under LGPL - original licence link has changed is not relivant.
10582 * <script type="text/javascript">
10586 * @class Roo.data.JsonReader
10587 * @extends Roo.data.DataReader
10588 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10589 * based on mappings in a provided Roo.data.Record constructor.
10591 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10592 * in the reply previously.
10597 var RecordDef = Roo.data.Record.create([
10598 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10599 {name: 'occupation'} // This field will use "occupation" as the mapping.
10601 var myReader = new Roo.data.JsonReader({
10602 totalProperty: "results", // The property which contains the total dataset size (optional)
10603 root: "rows", // The property which contains an Array of row objects
10604 id: "id" // The property within each row object that provides an ID for the record (optional)
10608 * This would consume a JSON file like this:
10610 { 'results': 2, 'rows': [
10611 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10612 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10615 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10616 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10617 * paged from the remote server.
10618 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10619 * @cfg {String} root name of the property which contains the Array of row objects.
10620 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10622 * Create a new JsonReader
10623 * @param {Object} meta Metadata configuration options
10624 * @param {Object} recordType Either an Array of field definition objects,
10625 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10627 Roo.data.JsonReader = function(meta, recordType){
10630 // set some defaults:
10631 Roo.applyIf(meta, {
10632 totalProperty: 'total',
10633 successProperty : 'success',
10638 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10640 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10643 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10644 * Used by Store query builder to append _requestMeta to params.
10647 metaFromRemote : false,
10649 * This method is only used by a DataProxy which has retrieved data from a remote server.
10650 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10651 * @return {Object} data A data block which is used by an Roo.data.Store object as
10652 * a cache of Roo.data.Records.
10654 read : function(response){
10655 var json = response.responseText;
10657 var o = /* eval:var:o */ eval("("+json+")");
10659 throw {message: "JsonReader.read: Json object not found"};
10665 this.metaFromRemote = true;
10666 this.meta = o.metaData;
10667 this.recordType = Roo.data.Record.create(o.metaData.fields);
10668 this.onMetaChange(this.meta, this.recordType, o);
10670 return this.readRecords(o);
10673 // private function a store will implement
10674 onMetaChange : function(meta, recordType, o){
10681 simpleAccess: function(obj, subsc) {
10688 getJsonAccessor: function(){
10690 return function(expr) {
10692 return(re.test(expr))
10693 ? new Function("obj", "return obj." + expr)
10698 return Roo.emptyFn;
10703 * Create a data block containing Roo.data.Records from an XML document.
10704 * @param {Object} o An object which contains an Array of row objects in the property specified
10705 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10706 * which contains the total size of the dataset.
10707 * @return {Object} data A data block which is used by an Roo.data.Store object as
10708 * a cache of Roo.data.Records.
10710 readRecords : function(o){
10712 * After any data loads, the raw JSON data is available for further custom processing.
10716 var s = this.meta, Record = this.recordType,
10717 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10719 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10721 if(s.totalProperty) {
10722 this.getTotal = this.getJsonAccessor(s.totalProperty);
10724 if(s.successProperty) {
10725 this.getSuccess = this.getJsonAccessor(s.successProperty);
10727 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10729 var g = this.getJsonAccessor(s.id);
10730 this.getId = function(rec) {
10732 return (r === undefined || r === "") ? null : r;
10735 this.getId = function(){return null;};
10738 for(var jj = 0; jj < fl; jj++){
10740 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10741 this.ef[jj] = this.getJsonAccessor(map);
10745 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10746 if(s.totalProperty){
10747 var vt = parseInt(this.getTotal(o), 10);
10752 if(s.successProperty){
10753 var vs = this.getSuccess(o);
10754 if(vs === false || vs === 'false'){
10759 for(var i = 0; i < c; i++){
10762 var id = this.getId(n);
10763 for(var j = 0; j < fl; j++){
10765 var v = this.ef[j](n);
10767 Roo.log('missing convert for ' + f.name);
10771 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10773 var record = new Record(values, id);
10775 records[i] = record;
10781 totalRecords : totalRecords
10786 * Ext JS Library 1.1.1
10787 * Copyright(c) 2006-2007, Ext JS, LLC.
10789 * Originally Released Under LGPL - original licence link has changed is not relivant.
10792 * <script type="text/javascript">
10796 * @class Roo.data.ArrayReader
10797 * @extends Roo.data.DataReader
10798 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10799 * Each element of that Array represents a row of data fields. The
10800 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10801 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10805 var RecordDef = Roo.data.Record.create([
10806 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10807 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10809 var myReader = new Roo.data.ArrayReader({
10810 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10814 * This would consume an Array like this:
10816 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10818 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10820 * Create a new JsonReader
10821 * @param {Object} meta Metadata configuration options.
10822 * @param {Object} recordType Either an Array of field definition objects
10823 * as specified to {@link Roo.data.Record#create},
10824 * or an {@link Roo.data.Record} object
10825 * created using {@link Roo.data.Record#create}.
10827 Roo.data.ArrayReader = function(meta, recordType){
10828 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10831 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10833 * Create a data block containing Roo.data.Records from an XML document.
10834 * @param {Object} o An Array of row objects which represents the dataset.
10835 * @return {Object} data A data block which is used by an Roo.data.Store object as
10836 * a cache of Roo.data.Records.
10838 readRecords : function(o){
10839 var sid = this.meta ? this.meta.id : null;
10840 var recordType = this.recordType, fields = recordType.prototype.fields;
10843 for(var i = 0; i < root.length; i++){
10846 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10847 for(var j = 0, jlen = fields.length; j < jlen; j++){
10848 var f = fields.items[j];
10849 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10850 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10852 values[f.name] = v;
10854 var record = new recordType(values, id);
10856 records[records.length] = record;
10860 totalRecords : records.length
10869 * @class Roo.bootstrap.ComboBox
10870 * @extends Roo.bootstrap.TriggerField
10871 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10872 * @cfg {Boolean} append (true|false) default false
10873 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10874 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10875 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10876 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10877 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10879 * Create a new ComboBox.
10880 * @param {Object} config Configuration options
10882 Roo.bootstrap.ComboBox = function(config){
10883 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10887 * Fires when the dropdown list is expanded
10888 * @param {Roo.bootstrap.ComboBox} combo This combo box
10893 * Fires when the dropdown list is collapsed
10894 * @param {Roo.bootstrap.ComboBox} combo This combo box
10898 * @event beforeselect
10899 * Fires before a list item is selected. Return false to cancel the selection.
10900 * @param {Roo.bootstrap.ComboBox} combo This combo box
10901 * @param {Roo.data.Record} record The data record returned from the underlying store
10902 * @param {Number} index The index of the selected item in the dropdown list
10904 'beforeselect' : true,
10907 * Fires when a list item is selected
10908 * @param {Roo.bootstrap.ComboBox} combo This combo box
10909 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10910 * @param {Number} index The index of the selected item in the dropdown list
10914 * @event beforequery
10915 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10916 * The event object passed has these properties:
10917 * @param {Roo.bootstrap.ComboBox} combo This combo box
10918 * @param {String} query The query
10919 * @param {Boolean} forceAll true to force "all" query
10920 * @param {Boolean} cancel true to cancel the query
10921 * @param {Object} e The query event object
10923 'beforequery': true,
10926 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10927 * @param {Roo.bootstrap.ComboBox} combo This combo box
10932 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10933 * @param {Roo.bootstrap.ComboBox} combo This combo box
10934 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10939 * Fires when the remove value from the combobox array
10940 * @param {Roo.bootstrap.ComboBox} combo This combo box
10944 * @event specialfilter
10945 * Fires when specialfilter
10946 * @param {Roo.bootstrap.ComboBox} combo This combo box
10948 'specialfilter' : true
10953 this.tickItems = [];
10955 this.selectedIndex = -1;
10956 if(this.mode == 'local'){
10957 if(config.queryDelay === undefined){
10958 this.queryDelay = 10;
10960 if(config.minChars === undefined){
10966 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10969 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10970 * rendering into an Roo.Editor, defaults to false)
10973 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10974 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10977 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10980 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10981 * the dropdown list (defaults to undefined, with no header element)
10985 * @cfg {String/Roo.Template} tpl The template to use to render the output
10989 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10991 listWidth: undefined,
10993 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10994 * mode = 'remote' or 'text' if mode = 'local')
10996 displayField: undefined,
10999 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11000 * mode = 'remote' or 'value' if mode = 'local').
11001 * Note: use of a valueField requires the user make a selection
11002 * in order for a value to be mapped.
11004 valueField: undefined,
11008 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11009 * field's data value (defaults to the underlying DOM element's name)
11011 hiddenName: undefined,
11013 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11017 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11019 selectedClass: 'active',
11022 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11026 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11027 * anchor positions (defaults to 'tl-bl')
11029 listAlign: 'tl-bl?',
11031 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11035 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11036 * query specified by the allQuery config option (defaults to 'query')
11038 triggerAction: 'query',
11040 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11041 * (defaults to 4, does not apply if editable = false)
11045 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11046 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11050 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11051 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11055 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11056 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11060 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11061 * when editable = true (defaults to false)
11063 selectOnFocus:false,
11065 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11067 queryParam: 'query',
11069 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11070 * when mode = 'remote' (defaults to 'Loading...')
11072 loadingText: 'Loading...',
11074 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11078 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11082 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11083 * traditional select (defaults to true)
11087 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11091 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11095 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11096 * listWidth has a higher value)
11100 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11101 * allow the user to set arbitrary text into the field (defaults to false)
11103 forceSelection:false,
11105 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11106 * if typeAhead = true (defaults to 250)
11108 typeAheadDelay : 250,
11110 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11111 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11113 valueNotFoundText : undefined,
11115 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11117 blockFocus : false,
11120 * @cfg {Boolean} disableClear Disable showing of clear button.
11122 disableClear : false,
11124 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11126 alwaysQuery : false,
11129 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11134 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11136 invalidClass : "has-warning",
11139 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11141 validClass : "has-success",
11144 * @cfg {Boolean} specialFilter (true|false) special filter default false
11146 specialFilter : false,
11158 btnPosition : 'right',
11159 triggerList : true,
11160 showToggleBtn : true,
11161 // element that contains real text value.. (when hidden is used..)
11163 getAutoCreate : function()
11170 if(!this.tickable){
11171 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11176 * ComboBox with tickable selections
11179 var align = this.labelAlign || this.parentLabelAlign();
11182 cls : 'form-group roo-combobox-tickable' //input-group
11187 cls : 'tickable-buttons',
11192 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11199 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11206 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11213 buttons.cn.unshift({
11215 cls: 'select2-search-field-input'
11221 Roo.each(buttons.cn, function(c){
11223 c.cls += ' btn-' + _this.size;
11226 if (_this.disabled) {
11237 cls: 'form-hidden-field'
11241 cls: 'select2-choices',
11245 cls: 'select2-search-field',
11257 cls: 'select2-container input-group select2-container-multi',
11262 // cls: 'typeahead typeahead-long dropdown-menu',
11263 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11268 if(this.hasFeedback && !this.allowBlank){
11272 cls: 'glyphicon form-control-feedback'
11275 combobox.cn.push(feedback);
11278 if (align ==='left' && this.fieldLabel.length) {
11280 Roo.log("left and has label");
11286 cls : 'control-label col-sm-' + this.labelWidth,
11287 html : this.fieldLabel
11291 cls : "col-sm-" + (12 - this.labelWidth),
11298 } else if ( this.fieldLabel.length) {
11304 //cls : 'input-group-addon',
11305 html : this.fieldLabel
11315 Roo.log(" no label && no align");
11322 ['xs','sm','md','lg'].map(function(size){
11323 if (settings[size]) {
11324 cfg.cls += ' col-' + size + '-' + settings[size];
11333 initEvents: function()
11337 throw "can not find store for combo";
11339 this.store = Roo.factory(this.store, Roo.data);
11342 this.initTickableEvents();
11346 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11348 if(this.hiddenName){
11350 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11352 this.hiddenField.dom.value =
11353 this.hiddenValue !== undefined ? this.hiddenValue :
11354 this.value !== undefined ? this.value : '';
11356 // prevent input submission
11357 this.el.dom.removeAttribute('name');
11358 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11363 // this.el.dom.setAttribute('autocomplete', 'off');
11366 var cls = 'x-combo-list';
11368 //this.list = new Roo.Layer({
11369 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11375 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11376 _this.list.setWidth(lw);
11379 this.list.on('mouseover', this.onViewOver, this);
11380 this.list.on('mousemove', this.onViewMove, this);
11382 this.list.on('scroll', this.onViewScroll, this);
11385 this.list.swallowEvent('mousewheel');
11386 this.assetHeight = 0;
11389 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11390 this.assetHeight += this.header.getHeight();
11393 this.innerList = this.list.createChild({cls:cls+'-inner'});
11394 this.innerList.on('mouseover', this.onViewOver, this);
11395 this.innerList.on('mousemove', this.onViewMove, this);
11396 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11398 if(this.allowBlank && !this.pageSize && !this.disableClear){
11399 this.footer = this.list.createChild({cls:cls+'-ft'});
11400 this.pageTb = new Roo.Toolbar(this.footer);
11404 this.footer = this.list.createChild({cls:cls+'-ft'});
11405 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11406 {pageSize: this.pageSize});
11410 if (this.pageTb && this.allowBlank && !this.disableClear) {
11412 this.pageTb.add(new Roo.Toolbar.Fill(), {
11413 cls: 'x-btn-icon x-btn-clear',
11415 handler: function()
11418 _this.clearValue();
11419 _this.onSelect(false, -1);
11424 this.assetHeight += this.footer.getHeight();
11429 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11432 this.view = new Roo.View(this.list, this.tpl, {
11433 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11435 //this.view.wrapEl.setDisplayed(false);
11436 this.view.on('click', this.onViewClick, this);
11440 this.store.on('beforeload', this.onBeforeLoad, this);
11441 this.store.on('load', this.onLoad, this);
11442 this.store.on('loadexception', this.onLoadException, this);
11444 if(this.resizable){
11445 this.resizer = new Roo.Resizable(this.list, {
11446 pinned:true, handles:'se'
11448 this.resizer.on('resize', function(r, w, h){
11449 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11450 this.listWidth = w;
11451 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11452 this.restrictHeight();
11454 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11457 if(!this.editable){
11458 this.editable = true;
11459 this.setEditable(false);
11464 if (typeof(this.events.add.listeners) != 'undefined') {
11466 this.addicon = this.wrap.createChild(
11467 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11469 this.addicon.on('click', function(e) {
11470 this.fireEvent('add', this);
11473 if (typeof(this.events.edit.listeners) != 'undefined') {
11475 this.editicon = this.wrap.createChild(
11476 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11477 if (this.addicon) {
11478 this.editicon.setStyle('margin-left', '40px');
11480 this.editicon.on('click', function(e) {
11482 // we fire even if inothing is selected..
11483 this.fireEvent('edit', this, this.lastData );
11489 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11490 "up" : function(e){
11491 this.inKeyMode = true;
11495 "down" : function(e){
11496 if(!this.isExpanded()){
11497 this.onTriggerClick();
11499 this.inKeyMode = true;
11504 "enter" : function(e){
11505 // this.onViewClick();
11509 if(this.fireEvent("specialkey", this, e)){
11510 this.onViewClick(false);
11516 "esc" : function(e){
11520 "tab" : function(e){
11523 if(this.fireEvent("specialkey", this, e)){
11524 this.onViewClick(false);
11532 doRelay : function(foo, bar, hname){
11533 if(hname == 'down' || this.scope.isExpanded()){
11534 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11543 this.queryDelay = Math.max(this.queryDelay || 10,
11544 this.mode == 'local' ? 10 : 250);
11547 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11549 if(this.typeAhead){
11550 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11552 if(this.editable !== false){
11553 this.inputEl().on("keyup", this.onKeyUp, this);
11555 if(this.forceSelection){
11556 this.inputEl().on('blur', this.doForce, this);
11560 this.choices = this.el.select('ul.select2-choices', true).first();
11561 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11565 initTickableEvents: function()
11569 if(this.hiddenName){
11571 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11573 this.hiddenField.dom.value =
11574 this.hiddenValue !== undefined ? this.hiddenValue :
11575 this.value !== undefined ? this.value : '';
11577 // prevent input submission
11578 this.el.dom.removeAttribute('name');
11579 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11584 // this.list = this.el.select('ul.dropdown-menu',true).first();
11586 this.choices = this.el.select('ul.select2-choices', true).first();
11587 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11588 if(this.triggerList){
11589 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11592 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11593 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11595 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11596 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11598 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11599 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11601 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11602 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11603 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11606 this.cancelBtn.hide();
11611 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11612 _this.list.setWidth(lw);
11615 this.list.on('mouseover', this.onViewOver, this);
11616 this.list.on('mousemove', this.onViewMove, this);
11618 this.list.on('scroll', this.onViewScroll, this);
11621 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>';
11624 this.view = new Roo.View(this.list, this.tpl, {
11625 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11628 //this.view.wrapEl.setDisplayed(false);
11629 this.view.on('click', this.onViewClick, this);
11633 this.store.on('beforeload', this.onBeforeLoad, this);
11634 this.store.on('load', this.onLoad, this);
11635 this.store.on('loadexception', this.onLoadException, this);
11638 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11639 "up" : function(e){
11640 this.inKeyMode = true;
11644 "down" : function(e){
11645 this.inKeyMode = true;
11649 "enter" : function(e){
11650 if(this.fireEvent("specialkey", this, e)){
11651 this.onViewClick(false);
11657 "esc" : function(e){
11658 this.onTickableFooterButtonClick(e, false, false);
11661 "tab" : function(e){
11662 this.fireEvent("specialkey", this, e);
11664 this.onTickableFooterButtonClick(e, false, false);
11671 doRelay : function(e, fn, key){
11672 if(this.scope.isExpanded()){
11673 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11682 this.queryDelay = Math.max(this.queryDelay || 10,
11683 this.mode == 'local' ? 10 : 250);
11686 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11688 if(this.typeAhead){
11689 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11692 if(this.editable !== false){
11693 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11698 onDestroy : function(){
11700 this.view.setStore(null);
11701 this.view.el.removeAllListeners();
11702 this.view.el.remove();
11703 this.view.purgeListeners();
11706 this.list.dom.innerHTML = '';
11710 this.store.un('beforeload', this.onBeforeLoad, this);
11711 this.store.un('load', this.onLoad, this);
11712 this.store.un('loadexception', this.onLoadException, this);
11714 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11718 fireKey : function(e){
11719 if(e.isNavKeyPress() && !this.list.isVisible()){
11720 this.fireEvent("specialkey", this, e);
11725 onResize: function(w, h){
11726 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11728 // if(typeof w != 'number'){
11729 // // we do not handle it!?!?
11732 // var tw = this.trigger.getWidth();
11733 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11734 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11736 // this.inputEl().setWidth( this.adjustWidth('input', x));
11738 // //this.trigger.setStyle('left', x+'px');
11740 // if(this.list && this.listWidth === undefined){
11741 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11742 // this.list.setWidth(lw);
11743 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11751 * Allow or prevent the user from directly editing the field text. If false is passed,
11752 * the user will only be able to select from the items defined in the dropdown list. This method
11753 * is the runtime equivalent of setting the 'editable' config option at config time.
11754 * @param {Boolean} value True to allow the user to directly edit the field text
11756 setEditable : function(value){
11757 if(value == this.editable){
11760 this.editable = value;
11762 this.inputEl().dom.setAttribute('readOnly', true);
11763 this.inputEl().on('mousedown', this.onTriggerClick, this);
11764 this.inputEl().addClass('x-combo-noedit');
11766 this.inputEl().dom.setAttribute('readOnly', false);
11767 this.inputEl().un('mousedown', this.onTriggerClick, this);
11768 this.inputEl().removeClass('x-combo-noedit');
11774 onBeforeLoad : function(combo,opts){
11775 if(!this.hasFocus){
11779 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11781 this.restrictHeight();
11782 this.selectedIndex = -1;
11786 onLoad : function(){
11788 this.hasQuery = false;
11790 if(!this.hasFocus){
11794 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11795 this.loading.hide();
11798 if(this.store.getCount() > 0){
11800 this.restrictHeight();
11801 if(this.lastQuery == this.allQuery){
11802 if(this.editable && !this.tickable){
11803 this.inputEl().dom.select();
11807 !this.selectByValue(this.value, true) &&
11810 !this.store.lastOptions ||
11811 typeof(this.store.lastOptions.add) == 'undefined' ||
11812 this.store.lastOptions.add != true
11815 this.select(0, true);
11818 if(this.autoFocus){
11821 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11822 this.taTask.delay(this.typeAheadDelay);
11826 this.onEmptyResults();
11832 onLoadException : function()
11834 this.hasQuery = false;
11836 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11837 this.loading.hide();
11840 if(this.tickable && this.editable){
11846 Roo.log(this.store.reader.jsonData);
11847 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11849 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11855 onTypeAhead : function(){
11856 if(this.store.getCount() > 0){
11857 var r = this.store.getAt(0);
11858 var newValue = r.data[this.displayField];
11859 var len = newValue.length;
11860 var selStart = this.getRawValue().length;
11862 if(selStart != len){
11863 this.setRawValue(newValue);
11864 this.selectText(selStart, newValue.length);
11870 onSelect : function(record, index){
11872 if(this.fireEvent('beforeselect', this, record, index) !== false){
11874 this.setFromData(index > -1 ? record.data : false);
11877 this.fireEvent('select', this, record, index);
11882 * Returns the currently selected field value or empty string if no value is set.
11883 * @return {String} value The selected value
11885 getValue : function(){
11888 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11891 if(this.valueField){
11892 return typeof this.value != 'undefined' ? this.value : '';
11894 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11899 * Clears any text/value currently set in the field
11901 clearValue : function(){
11902 if(this.hiddenField){
11903 this.hiddenField.dom.value = '';
11906 this.setRawValue('');
11907 this.lastSelectionText = '';
11908 this.lastData = false;
11913 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11914 * will be displayed in the field. If the value does not match the data value of an existing item,
11915 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11916 * Otherwise the field will be blank (although the value will still be set).
11917 * @param {String} value The value to match
11919 setValue : function(v){
11926 if(this.valueField){
11927 var r = this.findRecord(this.valueField, v);
11929 text = r.data[this.displayField];
11930 }else if(this.valueNotFoundText !== undefined){
11931 text = this.valueNotFoundText;
11934 this.lastSelectionText = text;
11935 if(this.hiddenField){
11936 this.hiddenField.dom.value = v;
11938 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11942 * @property {Object} the last set data for the element
11947 * Sets the value of the field based on a object which is related to the record format for the store.
11948 * @param {Object} value the value to set as. or false on reset?
11950 setFromData : function(o){
11957 var dv = ''; // display value
11958 var vv = ''; // value value..
11960 if (this.displayField) {
11961 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11963 // this is an error condition!!!
11964 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11967 if(this.valueField){
11968 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11971 if(this.hiddenField){
11972 this.hiddenField.dom.value = vv;
11974 this.lastSelectionText = dv;
11975 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11979 // no hidden field.. - we store the value in 'value', but still display
11980 // display field!!!!
11981 this.lastSelectionText = dv;
11982 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11988 reset : function(){
11989 // overridden so that last data is reset..
11996 this.setValue(this.originalValue);
11997 this.clearInvalid();
11998 this.lastData = false;
12000 this.view.clearSelections();
12004 findRecord : function(prop, value){
12006 if(this.store.getCount() > 0){
12007 this.store.each(function(r){
12008 if(r.data[prop] == value){
12018 getName: function()
12020 // returns hidden if it's set..
12021 if (!this.rendered) {return ''};
12022 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12026 onViewMove : function(e, t){
12027 this.inKeyMode = false;
12031 onViewOver : function(e, t){
12032 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12035 var item = this.view.findItemFromChild(t);
12038 var index = this.view.indexOf(item);
12039 this.select(index, false);
12044 onViewClick : function(view, doFocus, el, e)
12046 var index = this.view.getSelectedIndexes()[0];
12048 var r = this.store.getAt(index);
12052 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12059 Roo.each(this.tickItems, function(v,k){
12061 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12062 _this.tickItems.splice(k, 1);
12064 if(typeof(e) == 'undefined' && view == false){
12065 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12077 this.tickItems.push(r.data);
12079 if(typeof(e) == 'undefined' && view == false){
12080 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12087 this.onSelect(r, index);
12089 if(doFocus !== false && !this.blockFocus){
12090 this.inputEl().focus();
12095 restrictHeight : function(){
12096 //this.innerList.dom.style.height = '';
12097 //var inner = this.innerList.dom;
12098 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12099 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12100 //this.list.beginUpdate();
12101 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12102 this.list.alignTo(this.inputEl(), this.listAlign);
12103 this.list.alignTo(this.inputEl(), this.listAlign);
12104 //this.list.endUpdate();
12108 onEmptyResults : function(){
12110 if(this.tickable && this.editable){
12111 this.restrictHeight();
12119 * Returns true if the dropdown list is expanded, else false.
12121 isExpanded : function(){
12122 return this.list.isVisible();
12126 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12127 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12128 * @param {String} value The data value of the item to select
12129 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12130 * selected item if it is not currently in view (defaults to true)
12131 * @return {Boolean} True if the value matched an item in the list, else false
12133 selectByValue : function(v, scrollIntoView){
12134 if(v !== undefined && v !== null){
12135 var r = this.findRecord(this.valueField || this.displayField, v);
12137 this.select(this.store.indexOf(r), scrollIntoView);
12145 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12146 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12147 * @param {Number} index The zero-based index of the list item to select
12148 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12149 * selected item if it is not currently in view (defaults to true)
12151 select : function(index, scrollIntoView){
12152 this.selectedIndex = index;
12153 this.view.select(index);
12154 if(scrollIntoView !== false){
12155 var el = this.view.getNode(index);
12157 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12160 this.list.scrollChildIntoView(el, false);
12166 selectNext : function(){
12167 var ct = this.store.getCount();
12169 if(this.selectedIndex == -1){
12171 }else if(this.selectedIndex < ct-1){
12172 this.select(this.selectedIndex+1);
12178 selectPrev : function(){
12179 var ct = this.store.getCount();
12181 if(this.selectedIndex == -1){
12183 }else if(this.selectedIndex != 0){
12184 this.select(this.selectedIndex-1);
12190 onKeyUp : function(e){
12191 if(this.editable !== false && !e.isSpecialKey()){
12192 this.lastKey = e.getKey();
12193 this.dqTask.delay(this.queryDelay);
12198 validateBlur : function(){
12199 return !this.list || !this.list.isVisible();
12203 initQuery : function(){
12205 var v = this.getRawValue();
12207 if(this.tickable && this.editable){
12208 v = this.tickableInputEl().getValue();
12215 doForce : function(){
12216 if(this.inputEl().dom.value.length > 0){
12217 this.inputEl().dom.value =
12218 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12224 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12225 * query allowing the query action to be canceled if needed.
12226 * @param {String} query The SQL query to execute
12227 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12228 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12229 * saved in the current store (defaults to false)
12231 doQuery : function(q, forceAll){
12233 if(q === undefined || q === null){
12238 forceAll: forceAll,
12242 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12247 forceAll = qe.forceAll;
12248 if(forceAll === true || (q.length >= this.minChars)){
12250 this.hasQuery = true;
12252 if(this.lastQuery != q || this.alwaysQuery){
12253 this.lastQuery = q;
12254 if(this.mode == 'local'){
12255 this.selectedIndex = -1;
12257 this.store.clearFilter();
12260 if(this.specialFilter){
12261 this.fireEvent('specialfilter', this);
12266 this.store.filter(this.displayField, q);
12269 this.store.fireEvent("datachanged", this.store);
12276 this.store.baseParams[this.queryParam] = q;
12278 var options = {params : this.getParams(q)};
12281 options.add = true;
12282 options.params.start = this.page * this.pageSize;
12285 this.store.load(options);
12288 * this code will make the page width larger, at the beginning, the list not align correctly,
12289 * we should expand the list on onLoad
12290 * so command out it
12295 this.selectedIndex = -1;
12300 this.loadNext = false;
12304 getParams : function(q){
12306 //p[this.queryParam] = q;
12310 p.limit = this.pageSize;
12316 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12318 collapse : function(){
12319 if(!this.isExpanded()){
12326 this.hasFocus = false;
12328 this.cancelBtn.hide();
12329 this.trigger.show();
12332 this.tickableInputEl().dom.value = '';
12333 this.tickableInputEl().blur();
12338 Roo.get(document).un('mousedown', this.collapseIf, this);
12339 Roo.get(document).un('mousewheel', this.collapseIf, this);
12340 if (!this.editable) {
12341 Roo.get(document).un('keydown', this.listKeyPress, this);
12343 this.fireEvent('collapse', this);
12347 collapseIf : function(e){
12348 var in_combo = e.within(this.el);
12349 var in_list = e.within(this.list);
12350 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12352 if (in_combo || in_list || is_list) {
12353 //e.stopPropagation();
12358 this.onTickableFooterButtonClick(e, false, false);
12366 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12368 expand : function(){
12370 if(this.isExpanded() || !this.hasFocus){
12374 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12375 this.list.setWidth(lw);
12382 this.restrictHeight();
12386 this.tickItems = Roo.apply([], this.item);
12389 this.cancelBtn.show();
12390 this.trigger.hide();
12393 this.tickableInputEl().focus();
12398 Roo.get(document).on('mousedown', this.collapseIf, this);
12399 Roo.get(document).on('mousewheel', this.collapseIf, this);
12400 if (!this.editable) {
12401 Roo.get(document).on('keydown', this.listKeyPress, this);
12404 this.fireEvent('expand', this);
12408 // Implements the default empty TriggerField.onTriggerClick function
12409 onTriggerClick : function(e)
12411 Roo.log('trigger click');
12413 if(this.disabled || !this.triggerList){
12418 this.loadNext = false;
12420 if(this.isExpanded()){
12422 if (!this.blockFocus) {
12423 this.inputEl().focus();
12427 this.hasFocus = true;
12428 if(this.triggerAction == 'all') {
12429 this.doQuery(this.allQuery, true);
12431 this.doQuery(this.getRawValue());
12433 if (!this.blockFocus) {
12434 this.inputEl().focus();
12439 onTickableTriggerClick : function(e)
12446 this.loadNext = false;
12447 this.hasFocus = true;
12449 if(this.triggerAction == 'all') {
12450 this.doQuery(this.allQuery, true);
12452 this.doQuery(this.getRawValue());
12456 onSearchFieldClick : function(e)
12458 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12459 this.onTickableFooterButtonClick(e, false, false);
12463 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12468 this.loadNext = false;
12469 this.hasFocus = true;
12471 if(this.triggerAction == 'all') {
12472 this.doQuery(this.allQuery, true);
12474 this.doQuery(this.getRawValue());
12478 listKeyPress : function(e)
12480 //Roo.log('listkeypress');
12481 // scroll to first matching element based on key pres..
12482 if (e.isSpecialKey()) {
12485 var k = String.fromCharCode(e.getKey()).toUpperCase();
12488 var csel = this.view.getSelectedNodes();
12489 var cselitem = false;
12491 var ix = this.view.indexOf(csel[0]);
12492 cselitem = this.store.getAt(ix);
12493 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12499 this.store.each(function(v) {
12501 // start at existing selection.
12502 if (cselitem.id == v.id) {
12508 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12509 match = this.store.indexOf(v);
12515 if (match === false) {
12516 return true; // no more action?
12519 this.view.select(match);
12520 var sn = Roo.get(this.view.getSelectedNodes()[0])
12521 sn.scrollIntoView(sn.dom.parentNode, false);
12524 onViewScroll : function(e, t){
12526 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){
12530 this.hasQuery = true;
12532 this.loading = this.list.select('.loading', true).first();
12534 if(this.loading === null){
12535 this.list.createChild({
12537 cls: 'loading select2-more-results select2-active',
12538 html: 'Loading more results...'
12541 this.loading = this.list.select('.loading', true).first();
12543 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12545 this.loading.hide();
12548 this.loading.show();
12553 this.loadNext = true;
12555 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12560 addItem : function(o)
12562 var dv = ''; // display value
12564 if (this.displayField) {
12565 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12567 // this is an error condition!!!
12568 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12575 var choice = this.choices.createChild({
12577 cls: 'select2-search-choice',
12586 cls: 'select2-search-choice-close',
12591 }, this.searchField);
12593 var close = choice.select('a.select2-search-choice-close', true).first()
12595 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12603 this.inputEl().dom.value = '';
12608 onRemoveItem : function(e, _self, o)
12610 e.preventDefault();
12612 this.lastItem = Roo.apply([], this.item);
12614 var index = this.item.indexOf(o.data) * 1;
12617 Roo.log('not this item?!');
12621 this.item.splice(index, 1);
12626 this.fireEvent('remove', this, e);
12632 syncValue : function()
12634 if(!this.item.length){
12641 Roo.each(this.item, function(i){
12642 if(_this.valueField){
12643 value.push(i[_this.valueField]);
12650 this.value = value.join(',');
12652 if(this.hiddenField){
12653 this.hiddenField.dom.value = this.value;
12656 this.store.fireEvent("datachanged", this.store);
12659 clearItem : function()
12661 if(!this.multiple){
12667 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12676 inputEl: function ()
12679 return this.searchField;
12681 return this.el.select('input.form-control',true).first();
12685 onTickableFooterButtonClick : function(e, btn, el)
12687 e.preventDefault();
12689 this.lastItem = Roo.apply([], this.item);
12691 if(btn && btn.name == 'cancel'){
12692 this.tickItems = Roo.apply([], this.item);
12701 Roo.each(this.tickItems, function(o){
12709 validate : function()
12711 var v = this.getRawValue();
12714 v = this.getValue();
12717 if(this.disabled || this.allowBlank || v.length){
12722 this.markInvalid();
12726 tickableInputEl : function()
12728 if(!this.tickable || !this.editable){
12729 return this.inputEl();
12732 return this.inputEl().select('.select2-search-field-input', true).first();
12738 * @cfg {Boolean} grow
12742 * @cfg {Number} growMin
12746 * @cfg {Number} growMax
12756 * Ext JS Library 1.1.1
12757 * Copyright(c) 2006-2007, Ext JS, LLC.
12759 * Originally Released Under LGPL - original licence link has changed is not relivant.
12762 * <script type="text/javascript">
12767 * @extends Roo.util.Observable
12768 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12769 * This class also supports single and multi selection modes. <br>
12770 * Create a data model bound view:
12772 var store = new Roo.data.Store(...);
12774 var view = new Roo.View({
12776 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12778 singleSelect: true,
12779 selectedClass: "ydataview-selected",
12783 // listen for node click?
12784 view.on("click", function(vw, index, node, e){
12785 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12789 dataModel.load("foobar.xml");
12791 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12793 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12794 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12796 * Note: old style constructor is still suported (container, template, config)
12799 * Create a new View
12800 * @param {Object} config The config object
12803 Roo.View = function(config, depreciated_tpl, depreciated_config){
12805 this.parent = false;
12807 if (typeof(depreciated_tpl) == 'undefined') {
12808 // new way.. - universal constructor.
12809 Roo.apply(this, config);
12810 this.el = Roo.get(this.el);
12813 this.el = Roo.get(config);
12814 this.tpl = depreciated_tpl;
12815 Roo.apply(this, depreciated_config);
12817 this.wrapEl = this.el.wrap().wrap();
12818 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12821 if(typeof(this.tpl) == "string"){
12822 this.tpl = new Roo.Template(this.tpl);
12824 // support xtype ctors..
12825 this.tpl = new Roo.factory(this.tpl, Roo);
12829 this.tpl.compile();
12834 * @event beforeclick
12835 * Fires before a click is processed. Returns false to cancel the default action.
12836 * @param {Roo.View} this
12837 * @param {Number} index The index of the target node
12838 * @param {HTMLElement} node The target node
12839 * @param {Roo.EventObject} e The raw event object
12841 "beforeclick" : true,
12844 * Fires when a template node is clicked.
12845 * @param {Roo.View} this
12846 * @param {Number} index The index of the target node
12847 * @param {HTMLElement} node The target node
12848 * @param {Roo.EventObject} e The raw event object
12853 * Fires when a template node is double clicked.
12854 * @param {Roo.View} this
12855 * @param {Number} index The index of the target node
12856 * @param {HTMLElement} node The target node
12857 * @param {Roo.EventObject} e The raw event object
12861 * @event contextmenu
12862 * Fires when a template node is right clicked.
12863 * @param {Roo.View} this
12864 * @param {Number} index The index of the target node
12865 * @param {HTMLElement} node The target node
12866 * @param {Roo.EventObject} e The raw event object
12868 "contextmenu" : true,
12870 * @event selectionchange
12871 * Fires when the selected nodes change.
12872 * @param {Roo.View} this
12873 * @param {Array} selections Array of the selected nodes
12875 "selectionchange" : true,
12878 * @event beforeselect
12879 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12880 * @param {Roo.View} this
12881 * @param {HTMLElement} node The node to be selected
12882 * @param {Array} selections Array of currently selected nodes
12884 "beforeselect" : true,
12886 * @event preparedata
12887 * Fires on every row to render, to allow you to change the data.
12888 * @param {Roo.View} this
12889 * @param {Object} data to be rendered (change this)
12891 "preparedata" : true
12899 "click": this.onClick,
12900 "dblclick": this.onDblClick,
12901 "contextmenu": this.onContextMenu,
12905 this.selections = [];
12907 this.cmp = new Roo.CompositeElementLite([]);
12909 this.store = Roo.factory(this.store, Roo.data);
12910 this.setStore(this.store, true);
12913 if ( this.footer && this.footer.xtype) {
12915 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12917 this.footer.dataSource = this.store
12918 this.footer.container = fctr;
12919 this.footer = Roo.factory(this.footer, Roo);
12920 fctr.insertFirst(this.el);
12922 // this is a bit insane - as the paging toolbar seems to detach the el..
12923 // dom.parentNode.parentNode.parentNode
12924 // they get detached?
12928 Roo.View.superclass.constructor.call(this);
12933 Roo.extend(Roo.View, Roo.util.Observable, {
12936 * @cfg {Roo.data.Store} store Data store to load data from.
12941 * @cfg {String|Roo.Element} el The container element.
12946 * @cfg {String|Roo.Template} tpl The template used by this View
12950 * @cfg {String} dataName the named area of the template to use as the data area
12951 * Works with domtemplates roo-name="name"
12955 * @cfg {String} selectedClass The css class to add to selected nodes
12957 selectedClass : "x-view-selected",
12959 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12964 * @cfg {String} text to display on mask (default Loading)
12968 * @cfg {Boolean} multiSelect Allow multiple selection
12970 multiSelect : false,
12972 * @cfg {Boolean} singleSelect Allow single selection
12974 singleSelect: false,
12977 * @cfg {Boolean} toggleSelect - selecting
12979 toggleSelect : false,
12982 * @cfg {Boolean} tickable - selecting
12987 * Returns the element this view is bound to.
12988 * @return {Roo.Element}
12990 getEl : function(){
12991 return this.wrapEl;
12997 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12999 refresh : function(){
13000 //Roo.log('refresh');
13003 // if we are using something like 'domtemplate', then
13004 // the what gets used is:
13005 // t.applySubtemplate(NAME, data, wrapping data..)
13006 // the outer template then get' applied with
13007 // the store 'extra data'
13008 // and the body get's added to the
13009 // roo-name="data" node?
13010 // <span class='roo-tpl-{name}'></span> ?????
13014 this.clearSelections();
13015 this.el.update("");
13017 var records = this.store.getRange();
13018 if(records.length < 1) {
13020 // is this valid?? = should it render a template??
13022 this.el.update(this.emptyText);
13026 if (this.dataName) {
13027 this.el.update(t.apply(this.store.meta)); //????
13028 el = this.el.child('.roo-tpl-' + this.dataName);
13031 for(var i = 0, len = records.length; i < len; i++){
13032 var data = this.prepareData(records[i].data, i, records[i]);
13033 this.fireEvent("preparedata", this, data, i, records[i]);
13035 var d = Roo.apply({}, data);
13038 Roo.apply(d, {'roo-id' : Roo.id()});
13042 Roo.each(this.parent.item, function(item){
13043 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
13046 Roo.apply(d, {'roo-data-checked' : 'checked'});
13050 html[html.length] = Roo.util.Format.trim(
13052 t.applySubtemplate(this.dataName, d, this.store.meta) :
13059 el.update(html.join(""));
13060 this.nodes = el.dom.childNodes;
13061 this.updateIndexes(0);
13066 * Function to override to reformat the data that is sent to
13067 * the template for each node.
13068 * DEPRICATED - use the preparedata event handler.
13069 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
13070 * a JSON object for an UpdateManager bound view).
13072 prepareData : function(data, index, record)
13074 this.fireEvent("preparedata", this, data, index, record);
13078 onUpdate : function(ds, record){
13079 // Roo.log('on update');
13080 this.clearSelections();
13081 var index = this.store.indexOf(record);
13082 var n = this.nodes[index];
13083 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
13084 n.parentNode.removeChild(n);
13085 this.updateIndexes(index, index);
13091 onAdd : function(ds, records, index)
13093 //Roo.log(['on Add', ds, records, index] );
13094 this.clearSelections();
13095 if(this.nodes.length == 0){
13099 var n = this.nodes[index];
13100 for(var i = 0, len = records.length; i < len; i++){
13101 var d = this.prepareData(records[i].data, i, records[i]);
13103 this.tpl.insertBefore(n, d);
13106 this.tpl.append(this.el, d);
13109 this.updateIndexes(index);
13112 onRemove : function(ds, record, index){
13113 // Roo.log('onRemove');
13114 this.clearSelections();
13115 var el = this.dataName ?
13116 this.el.child('.roo-tpl-' + this.dataName) :
13119 el.dom.removeChild(this.nodes[index]);
13120 this.updateIndexes(index);
13124 * Refresh an individual node.
13125 * @param {Number} index
13127 refreshNode : function(index){
13128 this.onUpdate(this.store, this.store.getAt(index));
13131 updateIndexes : function(startIndex, endIndex){
13132 var ns = this.nodes;
13133 startIndex = startIndex || 0;
13134 endIndex = endIndex || ns.length - 1;
13135 for(var i = startIndex; i <= endIndex; i++){
13136 ns[i].nodeIndex = i;
13141 * Changes the data store this view uses and refresh the view.
13142 * @param {Store} store
13144 setStore : function(store, initial){
13145 if(!initial && this.store){
13146 this.store.un("datachanged", this.refresh);
13147 this.store.un("add", this.onAdd);
13148 this.store.un("remove", this.onRemove);
13149 this.store.un("update", this.onUpdate);
13150 this.store.un("clear", this.refresh);
13151 this.store.un("beforeload", this.onBeforeLoad);
13152 this.store.un("load", this.onLoad);
13153 this.store.un("loadexception", this.onLoad);
13157 store.on("datachanged", this.refresh, this);
13158 store.on("add", this.onAdd, this);
13159 store.on("remove", this.onRemove, this);
13160 store.on("update", this.onUpdate, this);
13161 store.on("clear", this.refresh, this);
13162 store.on("beforeload", this.onBeforeLoad, this);
13163 store.on("load", this.onLoad, this);
13164 store.on("loadexception", this.onLoad, this);
13172 * onbeforeLoad - masks the loading area.
13175 onBeforeLoad : function(store,opts)
13177 //Roo.log('onBeforeLoad');
13179 this.el.update("");
13181 this.el.mask(this.mask ? this.mask : "Loading" );
13183 onLoad : function ()
13190 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13191 * @param {HTMLElement} node
13192 * @return {HTMLElement} The template node
13194 findItemFromChild : function(node){
13195 var el = this.dataName ?
13196 this.el.child('.roo-tpl-' + this.dataName,true) :
13199 if(!node || node.parentNode == el){
13202 var p = node.parentNode;
13203 while(p && p != el){
13204 if(p.parentNode == el){
13213 onClick : function(e){
13214 var item = this.findItemFromChild(e.getTarget());
13216 var index = this.indexOf(item);
13217 if(this.onItemClick(item, index, e) !== false){
13218 this.fireEvent("click", this, index, item, e);
13221 this.clearSelections();
13226 onContextMenu : function(e){
13227 var item = this.findItemFromChild(e.getTarget());
13229 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13234 onDblClick : function(e){
13235 var item = this.findItemFromChild(e.getTarget());
13237 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13241 onItemClick : function(item, index, e)
13243 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13246 if (this.toggleSelect) {
13247 var m = this.isSelected(item) ? 'unselect' : 'select';
13250 _t[m](item, true, false);
13253 if(this.multiSelect || this.singleSelect){
13254 if(this.multiSelect && e.shiftKey && this.lastSelection){
13255 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13257 this.select(item, this.multiSelect && e.ctrlKey);
13258 this.lastSelection = item;
13261 if(!this.tickable){
13262 e.preventDefault();
13270 * Get the number of selected nodes.
13273 getSelectionCount : function(){
13274 return this.selections.length;
13278 * Get the currently selected nodes.
13279 * @return {Array} An array of HTMLElements
13281 getSelectedNodes : function(){
13282 return this.selections;
13286 * Get the indexes of the selected nodes.
13289 getSelectedIndexes : function(){
13290 var indexes = [], s = this.selections;
13291 for(var i = 0, len = s.length; i < len; i++){
13292 indexes.push(s[i].nodeIndex);
13298 * Clear all selections
13299 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13301 clearSelections : function(suppressEvent){
13302 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13303 this.cmp.elements = this.selections;
13304 this.cmp.removeClass(this.selectedClass);
13305 this.selections = [];
13306 if(!suppressEvent){
13307 this.fireEvent("selectionchange", this, this.selections);
13313 * Returns true if the passed node is selected
13314 * @param {HTMLElement/Number} node The node or node index
13315 * @return {Boolean}
13317 isSelected : function(node){
13318 var s = this.selections;
13322 node = this.getNode(node);
13323 return s.indexOf(node) !== -1;
13328 * @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
13329 * @param {Boolean} keepExisting (optional) true to keep existing selections
13330 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13332 select : function(nodeInfo, keepExisting, suppressEvent){
13333 if(nodeInfo instanceof Array){
13335 this.clearSelections(true);
13337 for(var i = 0, len = nodeInfo.length; i < len; i++){
13338 this.select(nodeInfo[i], true, true);
13342 var node = this.getNode(nodeInfo);
13343 if(!node || this.isSelected(node)){
13344 return; // already selected.
13347 this.clearSelections(true);
13350 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13351 Roo.fly(node).addClass(this.selectedClass);
13352 this.selections.push(node);
13353 if(!suppressEvent){
13354 this.fireEvent("selectionchange", this, this.selections);
13362 * @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
13363 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13364 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13366 unselect : function(nodeInfo, keepExisting, suppressEvent)
13368 if(nodeInfo instanceof Array){
13369 Roo.each(this.selections, function(s) {
13370 this.unselect(s, nodeInfo);
13374 var node = this.getNode(nodeInfo);
13375 if(!node || !this.isSelected(node)){
13376 //Roo.log("not selected");
13377 return; // not selected.
13381 Roo.each(this.selections, function(s) {
13383 Roo.fly(node).removeClass(this.selectedClass);
13390 this.selections= ns;
13391 this.fireEvent("selectionchange", this, this.selections);
13395 * Gets a template node.
13396 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13397 * @return {HTMLElement} The node or null if it wasn't found
13399 getNode : function(nodeInfo){
13400 if(typeof nodeInfo == "string"){
13401 return document.getElementById(nodeInfo);
13402 }else if(typeof nodeInfo == "number"){
13403 return this.nodes[nodeInfo];
13409 * Gets a range template nodes.
13410 * @param {Number} startIndex
13411 * @param {Number} endIndex
13412 * @return {Array} An array of nodes
13414 getNodes : function(start, end){
13415 var ns = this.nodes;
13416 start = start || 0;
13417 end = typeof end == "undefined" ? ns.length - 1 : end;
13420 for(var i = start; i <= end; i++){
13424 for(var i = start; i >= end; i--){
13432 * Finds the index of the passed node
13433 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13434 * @return {Number} The index of the node or -1
13436 indexOf : function(node){
13437 node = this.getNode(node);
13438 if(typeof node.nodeIndex == "number"){
13439 return node.nodeIndex;
13441 var ns = this.nodes;
13442 for(var i = 0, len = ns.length; i < len; i++){
13453 * based on jquery fullcalendar
13457 Roo.bootstrap = Roo.bootstrap || {};
13459 * @class Roo.bootstrap.Calendar
13460 * @extends Roo.bootstrap.Component
13461 * Bootstrap Calendar class
13462 * @cfg {Boolean} loadMask (true|false) default false
13463 * @cfg {Object} header generate the user specific header of the calendar, default false
13466 * Create a new Container
13467 * @param {Object} config The config object
13472 Roo.bootstrap.Calendar = function(config){
13473 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13477 * Fires when a date is selected
13478 * @param {DatePicker} this
13479 * @param {Date} date The selected date
13483 * @event monthchange
13484 * Fires when the displayed month changes
13485 * @param {DatePicker} this
13486 * @param {Date} date The selected month
13488 'monthchange': true,
13490 * @event evententer
13491 * Fires when mouse over an event
13492 * @param {Calendar} this
13493 * @param {event} Event
13495 'evententer': true,
13497 * @event eventleave
13498 * Fires when the mouse leaves an
13499 * @param {Calendar} this
13502 'eventleave': true,
13504 * @event eventclick
13505 * Fires when the mouse click an
13506 * @param {Calendar} this
13515 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13518 * @cfg {Number} startDay
13519 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13527 getAutoCreate : function(){
13530 var fc_button = function(name, corner, style, content ) {
13531 return Roo.apply({},{
13533 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13535 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13538 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13549 style : 'width:100%',
13556 cls : 'fc-header-left',
13558 fc_button('prev', 'left', 'arrow', '‹' ),
13559 fc_button('next', 'right', 'arrow', '›' ),
13560 { tag: 'span', cls: 'fc-header-space' },
13561 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13569 cls : 'fc-header-center',
13573 cls: 'fc-header-title',
13576 html : 'month / year'
13584 cls : 'fc-header-right',
13586 /* fc_button('month', 'left', '', 'month' ),
13587 fc_button('week', '', '', 'week' ),
13588 fc_button('day', 'right', '', 'day' )
13600 header = this.header;
13603 var cal_heads = function() {
13605 // fixme - handle this.
13607 for (var i =0; i < Date.dayNames.length; i++) {
13608 var d = Date.dayNames[i];
13611 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13612 html : d.substring(0,3)
13616 ret[0].cls += ' fc-first';
13617 ret[6].cls += ' fc-last';
13620 var cal_cell = function(n) {
13623 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13628 cls: 'fc-day-number',
13632 cls: 'fc-day-content',
13636 style: 'position: relative;' // height: 17px;
13648 var cal_rows = function() {
13651 for (var r = 0; r < 6; r++) {
13658 for (var i =0; i < Date.dayNames.length; i++) {
13659 var d = Date.dayNames[i];
13660 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13663 row.cn[0].cls+=' fc-first';
13664 row.cn[0].cn[0].style = 'min-height:90px';
13665 row.cn[6].cls+=' fc-last';
13669 ret[0].cls += ' fc-first';
13670 ret[4].cls += ' fc-prev-last';
13671 ret[5].cls += ' fc-last';
13678 cls: 'fc-border-separate',
13679 style : 'width:100%',
13687 cls : 'fc-first fc-last',
13705 cls : 'fc-content',
13706 style : "position: relative;",
13709 cls : 'fc-view fc-view-month fc-grid',
13710 style : 'position: relative',
13711 unselectable : 'on',
13714 cls : 'fc-event-container',
13715 style : 'position:absolute;z-index:8;top:0;left:0;'
13733 initEvents : function()
13736 throw "can not find store for calendar";
13742 style: "text-align:center",
13746 style: "background-color:white;width:50%;margin:250 auto",
13750 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13761 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13763 var size = this.el.select('.fc-content', true).first().getSize();
13764 this.maskEl.setSize(size.width, size.height);
13765 this.maskEl.enableDisplayMode("block");
13766 if(!this.loadMask){
13767 this.maskEl.hide();
13770 this.store = Roo.factory(this.store, Roo.data);
13771 this.store.on('load', this.onLoad, this);
13772 this.store.on('beforeload', this.onBeforeLoad, this);
13776 this.cells = this.el.select('.fc-day',true);
13777 //Roo.log(this.cells);
13778 this.textNodes = this.el.query('.fc-day-number');
13779 this.cells.addClassOnOver('fc-state-hover');
13781 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13782 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13783 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13784 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13786 this.on('monthchange', this.onMonthChange, this);
13788 this.update(new Date().clearTime());
13791 resize : function() {
13792 var sz = this.el.getSize();
13794 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13795 this.el.select('.fc-day-content div',true).setHeight(34);
13800 showPrevMonth : function(e){
13801 this.update(this.activeDate.add("mo", -1));
13803 showToday : function(e){
13804 this.update(new Date().clearTime());
13807 showNextMonth : function(e){
13808 this.update(this.activeDate.add("mo", 1));
13812 showPrevYear : function(){
13813 this.update(this.activeDate.add("y", -1));
13817 showNextYear : function(){
13818 this.update(this.activeDate.add("y", 1));
13823 update : function(date)
13825 var vd = this.activeDate;
13826 this.activeDate = date;
13827 // if(vd && this.el){
13828 // var t = date.getTime();
13829 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13830 // Roo.log('using add remove');
13832 // this.fireEvent('monthchange', this, date);
13834 // this.cells.removeClass("fc-state-highlight");
13835 // this.cells.each(function(c){
13836 // if(c.dateValue == t){
13837 // c.addClass("fc-state-highlight");
13838 // setTimeout(function(){
13839 // try{c.dom.firstChild.focus();}catch(e){}
13849 var days = date.getDaysInMonth();
13851 var firstOfMonth = date.getFirstDateOfMonth();
13852 var startingPos = firstOfMonth.getDay()-this.startDay;
13854 if(startingPos < this.startDay){
13858 var pm = date.add(Date.MONTH, -1);
13859 var prevStart = pm.getDaysInMonth()-startingPos;
13861 this.cells = this.el.select('.fc-day',true);
13862 this.textNodes = this.el.query('.fc-day-number');
13863 this.cells.addClassOnOver('fc-state-hover');
13865 var cells = this.cells.elements;
13866 var textEls = this.textNodes;
13868 Roo.each(cells, function(cell){
13869 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13872 days += startingPos;
13874 // convert everything to numbers so it's fast
13875 var day = 86400000;
13876 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13879 //Roo.log(prevStart);
13881 var today = new Date().clearTime().getTime();
13882 var sel = date.clearTime().getTime();
13883 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13884 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13885 var ddMatch = this.disabledDatesRE;
13886 var ddText = this.disabledDatesText;
13887 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13888 var ddaysText = this.disabledDaysText;
13889 var format = this.format;
13891 var setCellClass = function(cal, cell){
13895 //Roo.log('set Cell Class');
13897 var t = d.getTime();
13901 cell.dateValue = t;
13903 cell.className += " fc-today";
13904 cell.className += " fc-state-highlight";
13905 cell.title = cal.todayText;
13908 // disable highlight in other month..
13909 //cell.className += " fc-state-highlight";
13914 cell.className = " fc-state-disabled";
13915 cell.title = cal.minText;
13919 cell.className = " fc-state-disabled";
13920 cell.title = cal.maxText;
13924 if(ddays.indexOf(d.getDay()) != -1){
13925 cell.title = ddaysText;
13926 cell.className = " fc-state-disabled";
13929 if(ddMatch && format){
13930 var fvalue = d.dateFormat(format);
13931 if(ddMatch.test(fvalue)){
13932 cell.title = ddText.replace("%0", fvalue);
13933 cell.className = " fc-state-disabled";
13937 if (!cell.initialClassName) {
13938 cell.initialClassName = cell.dom.className;
13941 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13946 for(; i < startingPos; i++) {
13947 textEls[i].innerHTML = (++prevStart);
13948 d.setDate(d.getDate()+1);
13950 cells[i].className = "fc-past fc-other-month";
13951 setCellClass(this, cells[i]);
13956 for(; i < days; i++){
13957 intDay = i - startingPos + 1;
13958 textEls[i].innerHTML = (intDay);
13959 d.setDate(d.getDate()+1);
13961 cells[i].className = ''; // "x-date-active";
13962 setCellClass(this, cells[i]);
13966 for(; i < 42; i++) {
13967 textEls[i].innerHTML = (++extraDays);
13968 d.setDate(d.getDate()+1);
13970 cells[i].className = "fc-future fc-other-month";
13971 setCellClass(this, cells[i]);
13974 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13976 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13978 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13979 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13981 if(totalRows != 6){
13982 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13983 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13986 this.fireEvent('monthchange', this, date);
13990 if(!this.internalRender){
13991 var main = this.el.dom.firstChild;
13992 var w = main.offsetWidth;
13993 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13994 Roo.fly(main).setWidth(w);
13995 this.internalRender = true;
13996 // opera does not respect the auto grow header center column
13997 // then, after it gets a width opera refuses to recalculate
13998 // without a second pass
13999 if(Roo.isOpera && !this.secondPass){
14000 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
14001 this.secondPass = true;
14002 this.update.defer(10, this, [date]);
14009 findCell : function(dt) {
14010 dt = dt.clearTime().getTime();
14012 this.cells.each(function(c){
14013 //Roo.log("check " +c.dateValue + '?=' + dt);
14014 if(c.dateValue == dt){
14024 findCells : function(ev) {
14025 var s = ev.start.clone().clearTime().getTime();
14027 var e= ev.end.clone().clearTime().getTime();
14030 this.cells.each(function(c){
14031 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
14033 if(c.dateValue > e){
14036 if(c.dateValue < s){
14045 // findBestRow: function(cells)
14049 // for (var i =0 ; i < cells.length;i++) {
14050 // ret = Math.max(cells[i].rows || 0,ret);
14057 addItem : function(ev)
14059 // look for vertical location slot in
14060 var cells = this.findCells(ev);
14062 // ev.row = this.findBestRow(cells);
14064 // work out the location.
14068 for(var i =0; i < cells.length; i++) {
14070 cells[i].row = cells[0].row;
14073 cells[i].row = cells[i].row + 1;
14083 if (crow.start.getY() == cells[i].getY()) {
14085 crow.end = cells[i];
14102 cells[0].events.push(ev);
14104 this.calevents.push(ev);
14107 clearEvents: function() {
14109 if(!this.calevents){
14113 Roo.each(this.cells.elements, function(c){
14119 Roo.each(this.calevents, function(e) {
14120 Roo.each(e.els, function(el) {
14121 el.un('mouseenter' ,this.onEventEnter, this);
14122 el.un('mouseleave' ,this.onEventLeave, this);
14127 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14133 renderEvents: function()
14137 this.cells.each(function(c) {
14146 if(c.row != c.events.length){
14147 r = 4 - (4 - (c.row - c.events.length));
14150 c.events = ev.slice(0, r);
14151 c.more = ev.slice(r);
14153 if(c.more.length && c.more.length == 1){
14154 c.events.push(c.more.pop());
14157 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14161 this.cells.each(function(c) {
14163 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14166 for (var e = 0; e < c.events.length; e++){
14167 var ev = c.events[e];
14168 var rows = ev.rows;
14170 for(var i = 0; i < rows.length; i++) {
14172 // how many rows should it span..
14175 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14176 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14178 unselectable : "on",
14181 cls: 'fc-event-inner',
14185 // cls: 'fc-event-time',
14186 // html : cells.length > 1 ? '' : ev.time
14190 cls: 'fc-event-title',
14191 html : String.format('{0}', ev.title)
14198 cls: 'ui-resizable-handle ui-resizable-e',
14199 html : '  '
14206 cfg.cls += ' fc-event-start';
14208 if ((i+1) == rows.length) {
14209 cfg.cls += ' fc-event-end';
14212 var ctr = _this.el.select('.fc-event-container',true).first();
14213 var cg = ctr.createChild(cfg);
14215 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14216 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14218 var r = (c.more.length) ? 1 : 0;
14219 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14220 cg.setWidth(ebox.right - sbox.x -2);
14222 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14223 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14224 cg.on('click', _this.onEventClick, _this, ev);
14235 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14236 style : 'position: absolute',
14237 unselectable : "on",
14240 cls: 'fc-event-inner',
14244 cls: 'fc-event-title',
14252 cls: 'ui-resizable-handle ui-resizable-e',
14253 html : '  '
14259 var ctr = _this.el.select('.fc-event-container',true).first();
14260 var cg = ctr.createChild(cfg);
14262 var sbox = c.select('.fc-day-content',true).first().getBox();
14263 var ebox = c.select('.fc-day-content',true).first().getBox();
14265 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14266 cg.setWidth(ebox.right - sbox.x -2);
14268 cg.on('click', _this.onMoreEventClick, _this, c.more);
14278 onEventEnter: function (e, el,event,d) {
14279 this.fireEvent('evententer', this, el, event);
14282 onEventLeave: function (e, el,event,d) {
14283 this.fireEvent('eventleave', this, el, event);
14286 onEventClick: function (e, el,event,d) {
14287 this.fireEvent('eventclick', this, el, event);
14290 onMonthChange: function () {
14294 onMoreEventClick: function(e, el, more)
14298 this.calpopover.placement = 'right';
14299 this.calpopover.setTitle('More');
14301 this.calpopover.setContent('');
14303 var ctr = this.calpopover.el.select('.popover-content', true).first();
14305 Roo.each(more, function(m){
14307 cls : 'fc-event-hori fc-event-draggable',
14310 var cg = ctr.createChild(cfg);
14312 cg.on('click', _this.onEventClick, _this, m);
14315 this.calpopover.show(el);
14320 onLoad: function ()
14322 this.calevents = [];
14325 if(this.store.getCount() > 0){
14326 this.store.data.each(function(d){
14329 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14330 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14331 time : d.data.start_time,
14332 title : d.data.title,
14333 description : d.data.description,
14334 venue : d.data.venue
14339 this.renderEvents();
14341 if(this.calevents.length && this.loadMask){
14342 this.maskEl.hide();
14346 onBeforeLoad: function()
14348 this.clearEvents();
14350 this.maskEl.show();
14364 * @class Roo.bootstrap.Popover
14365 * @extends Roo.bootstrap.Component
14366 * Bootstrap Popover class
14367 * @cfg {String} html contents of the popover (or false to use children..)
14368 * @cfg {String} title of popover (or false to hide)
14369 * @cfg {String} placement how it is placed
14370 * @cfg {String} trigger click || hover (or false to trigger manually)
14371 * @cfg {String} over what (parent or false to trigger manually.)
14372 * @cfg {Number} delay - delay before showing
14375 * Create a new Popover
14376 * @param {Object} config The config object
14379 Roo.bootstrap.Popover = function(config){
14380 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14383 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14385 title: 'Fill in a title',
14388 placement : 'right',
14389 trigger : 'hover', // hover
14395 can_build_overlaid : false,
14397 getChildContainer : function()
14399 return this.el.select('.popover-content',true).first();
14402 getAutoCreate : function(){
14403 Roo.log('make popover?');
14405 cls : 'popover roo-dynamic',
14406 style: 'display:block',
14412 cls : 'popover-inner',
14416 cls: 'popover-title',
14420 cls : 'popover-content',
14431 setTitle: function(str)
14433 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14435 setContent: function(str)
14437 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14439 // as it get's added to the bottom of the page.
14440 onRender : function(ct, position)
14442 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14444 var cfg = Roo.apply({}, this.getAutoCreate());
14448 cfg.cls += ' ' + this.cls;
14451 cfg.style = this.style;
14453 Roo.log("adding to ")
14454 this.el = Roo.get(document.body).createChild(cfg, position);
14460 initEvents : function()
14462 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14463 this.el.enableDisplayMode('block');
14465 if (this.over === false) {
14468 if (this.triggers === false) {
14471 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14472 var triggers = this.trigger ? this.trigger.split(' ') : [];
14473 Roo.each(triggers, function(trigger) {
14475 if (trigger == 'click') {
14476 on_el.on('click', this.toggle, this);
14477 } else if (trigger != 'manual') {
14478 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14479 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14481 on_el.on(eventIn ,this.enter, this);
14482 on_el.on(eventOut, this.leave, this);
14493 toggle : function () {
14494 this.hoverState == 'in' ? this.leave() : this.enter();
14497 enter : function () {
14500 clearTimeout(this.timeout);
14502 this.hoverState = 'in';
14504 if (!this.delay || !this.delay.show) {
14509 this.timeout = setTimeout(function () {
14510 if (_t.hoverState == 'in') {
14513 }, this.delay.show)
14515 leave : function() {
14516 clearTimeout(this.timeout);
14518 this.hoverState = 'out';
14520 if (!this.delay || !this.delay.hide) {
14525 this.timeout = setTimeout(function () {
14526 if (_t.hoverState == 'out') {
14529 }, this.delay.hide)
14532 show : function (on_el)
14535 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14538 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14539 if (this.html !== false) {
14540 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14542 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14543 if (!this.title.length) {
14544 this.el.select('.popover-title',true).hide();
14547 var placement = typeof this.placement == 'function' ?
14548 this.placement.call(this, this.el, on_el) :
14551 var autoToken = /\s?auto?\s?/i;
14552 var autoPlace = autoToken.test(placement);
14554 placement = placement.replace(autoToken, '') || 'top';
14558 //this.el.setXY([0,0]);
14560 this.el.dom.style.display='block';
14561 this.el.addClass(placement);
14563 //this.el.appendTo(on_el);
14565 var p = this.getPosition();
14566 var box = this.el.getBox();
14571 var align = Roo.bootstrap.Popover.alignment[placement];
14572 this.el.alignTo(on_el, align[0],align[1]);
14573 //var arrow = this.el.select('.arrow',true).first();
14574 //arrow.set(align[2],
14576 this.el.addClass('in');
14577 this.hoverState = null;
14579 if (this.el.hasClass('fade')) {
14586 this.el.setXY([0,0]);
14587 this.el.removeClass('in');
14594 Roo.bootstrap.Popover.alignment = {
14595 'left' : ['r-l', [-10,0], 'right'],
14596 'right' : ['l-r', [10,0], 'left'],
14597 'bottom' : ['t-b', [0,10], 'top'],
14598 'top' : [ 'b-t', [0,-10], 'bottom']
14609 * @class Roo.bootstrap.Progress
14610 * @extends Roo.bootstrap.Component
14611 * Bootstrap Progress class
14612 * @cfg {Boolean} striped striped of the progress bar
14613 * @cfg {Boolean} active animated of the progress bar
14617 * Create a new Progress
14618 * @param {Object} config The config object
14621 Roo.bootstrap.Progress = function(config){
14622 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14625 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14630 getAutoCreate : function(){
14638 cfg.cls += ' progress-striped';
14642 cfg.cls += ' active';
14661 * @class Roo.bootstrap.ProgressBar
14662 * @extends Roo.bootstrap.Component
14663 * Bootstrap ProgressBar class
14664 * @cfg {Number} aria_valuenow aria-value now
14665 * @cfg {Number} aria_valuemin aria-value min
14666 * @cfg {Number} aria_valuemax aria-value max
14667 * @cfg {String} label label for the progress bar
14668 * @cfg {String} panel (success | info | warning | danger )
14669 * @cfg {String} role role of the progress bar
14670 * @cfg {String} sr_only text
14674 * Create a new ProgressBar
14675 * @param {Object} config The config object
14678 Roo.bootstrap.ProgressBar = function(config){
14679 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14682 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14686 aria_valuemax : 100,
14692 getAutoCreate : function()
14697 cls: 'progress-bar',
14698 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14710 cfg.role = this.role;
14713 if(this.aria_valuenow){
14714 cfg['aria-valuenow'] = this.aria_valuenow;
14717 if(this.aria_valuemin){
14718 cfg['aria-valuemin'] = this.aria_valuemin;
14721 if(this.aria_valuemax){
14722 cfg['aria-valuemax'] = this.aria_valuemax;
14725 if(this.label && !this.sr_only){
14726 cfg.html = this.label;
14730 cfg.cls += ' progress-bar-' + this.panel;
14736 update : function(aria_valuenow)
14738 this.aria_valuenow = aria_valuenow;
14740 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14755 * @class Roo.bootstrap.TabGroup
14756 * @extends Roo.bootstrap.Column
14757 * Bootstrap Column class
14758 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14759 * @cfg {Boolean} carousel true to make the group behave like a carousel
14760 * @cfg {Number} bullets show the panel pointer.. default 0
14761 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
14762 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
14763 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14766 * Create a new TabGroup
14767 * @param {Object} config The config object
14770 Roo.bootstrap.TabGroup = function(config){
14771 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14773 this.navId = Roo.id();
14776 Roo.bootstrap.TabGroup.register(this);
14780 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14783 transition : false,
14788 slideOnTouch : false,
14790 getAutoCreate : function()
14792 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14794 cfg.cls += ' tab-content';
14796 Roo.log('get auto create...............');
14798 if (this.carousel) {
14799 cfg.cls += ' carousel slide';
14802 cls : 'carousel-inner'
14805 if(this.bullets > 0 && !Roo.isTouch){
14808 cls : 'carousel-bullets',
14812 if(this.bullets_cls){
14813 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14816 for (var i = 0; i < this.bullets; i++){
14818 cls : 'bullet bullet-' + i
14826 cfg.cn[0].cn = bullets;
14833 initEvents: function()
14835 Roo.log('-------- init events on tab group ---------');
14837 if(this.bullets > 0 && !Roo.isTouch){
14843 if(Roo.isTouch && this.slideOnTouch){
14844 this.el.on("touchstart", this.onTouchStart, this);
14847 if(this.autoslide){
14850 this.slideFn = window.setInterval(function() {
14851 _this.showPanelNext();
14857 onTouchStart : function(e, el, o)
14859 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
14863 this.showPanelNext();
14866 getChildContainer : function()
14868 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14872 * register a Navigation item
14873 * @param {Roo.bootstrap.NavItem} the navitem to add
14875 register : function(item)
14877 this.tabs.push( item);
14878 item.navId = this.navId; // not really needed..
14882 getActivePanel : function()
14885 Roo.each(this.tabs, function(t) {
14895 getPanelByName : function(n)
14898 Roo.each(this.tabs, function(t) {
14899 if (t.tabId == n) {
14907 indexOfPanel : function(p)
14910 Roo.each(this.tabs, function(t,i) {
14911 if (t.tabId == p.tabId) {
14920 * show a specific panel
14921 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14922 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14924 showPanel : function (pan)
14926 if(this.transition){
14927 Roo.log("waiting for the transitionend");
14931 if (typeof(pan) == 'number') {
14932 pan = this.tabs[pan];
14934 if (typeof(pan) == 'string') {
14935 pan = this.getPanelByName(pan);
14937 if (pan.tabId == this.getActivePanel().tabId) {
14940 var cur = this.getActivePanel();
14942 if (false === cur.fireEvent('beforedeactivate')) {
14946 if(this.bullets > 0 && !Roo.isTouch){
14947 this.setActiveBullet(this.indexOfPanel(pan));
14950 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14952 this.transition = true;
14953 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14954 var lr = dir == 'next' ? 'left' : 'right';
14955 pan.el.addClass(dir); // or prev
14956 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14957 cur.el.addClass(lr); // or right
14958 pan.el.addClass(lr);
14961 cur.el.on('transitionend', function() {
14962 Roo.log("trans end?");
14964 pan.el.removeClass([lr,dir]);
14965 pan.setActive(true);
14967 cur.el.removeClass([lr]);
14968 cur.setActive(false);
14970 _this.transition = false;
14972 }, this, { single: true } );
14977 cur.setActive(false);
14978 pan.setActive(true);
14983 showPanelNext : function()
14985 var i = this.indexOfPanel(this.getActivePanel());
14987 if (i >= this.tabs.length - 1 && !this.autoslide) {
14991 if (i >= this.tabs.length - 1 && this.autoslide) {
14995 this.showPanel(this.tabs[i+1]);
14998 showPanelPrev : function()
15000 var i = this.indexOfPanel(this.getActivePanel());
15002 if (i < 1 && !this.autoslide) {
15006 if (i < 1 && this.autoslide) {
15007 i = this.tabs.length;
15010 this.showPanel(this.tabs[i-1]);
15013 initBullet : function()
15021 for (var i = 0; i < this.bullets; i++){
15022 var bullet = this.el.select('.bullet-' + i, true).first();
15028 bullet.on('click', (function(e, el, o, ii, t){
15030 e.preventDefault();
15032 _this.showPanel(ii);
15034 if(_this.autoslide && _this.slideFn){
15035 clearInterval(_this.slideFn);
15036 _this.slideFn = window.setInterval(function() {
15037 _this.showPanelNext();
15041 }).createDelegate(this, [i, bullet], true));
15045 setActiveBullet : function(i)
15051 Roo.each(this.el.select('.bullet', true).elements, function(el){
15052 el.removeClass('selected');
15055 var bullet = this.el.select('.bullet-' + i, true).first();
15061 bullet.addClass('selected');
15072 Roo.apply(Roo.bootstrap.TabGroup, {
15076 * register a Navigation Group
15077 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15079 register : function(navgrp)
15081 this.groups[navgrp.navId] = navgrp;
15085 * fetch a Navigation Group based on the navigation ID
15086 * if one does not exist , it will get created.
15087 * @param {string} the navgroup to add
15088 * @returns {Roo.bootstrap.NavGroup} the navgroup
15090 get: function(navId) {
15091 if (typeof(this.groups[navId]) == 'undefined') {
15092 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15094 return this.groups[navId] ;
15109 * @class Roo.bootstrap.TabPanel
15110 * @extends Roo.bootstrap.Component
15111 * Bootstrap TabPanel class
15112 * @cfg {Boolean} active panel active
15113 * @cfg {String} html panel content
15114 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15115 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15119 * Create a new TabPanel
15120 * @param {Object} config The config object
15123 Roo.bootstrap.TabPanel = function(config){
15124 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15128 * Fires when the active status changes
15129 * @param {Roo.bootstrap.TabPanel} this
15130 * @param {Boolean} state the new state
15135 * @event beforedeactivate
15136 * Fires before a tab is de-activated - can be used to do validation on a form.
15137 * @param {Roo.bootstrap.TabPanel} this
15138 * @return {Boolean} false if there is an error
15141 'beforedeactivate': true
15144 this.tabId = this.tabId || Roo.id();
15148 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15155 getAutoCreate : function(){
15158 // item is needed for carousel - not sure if it has any effect otherwise
15159 cls: 'tab-pane item',
15160 html: this.html || ''
15164 cfg.cls += ' active';
15168 cfg.tabId = this.tabId;
15175 initEvents: function()
15177 Roo.log('-------- init events on tab panel ---------');
15179 var p = this.parent();
15180 this.navId = this.navId || p.navId;
15182 if (typeof(this.navId) != 'undefined') {
15183 // not really needed.. but just in case.. parent should be a NavGroup.
15184 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15185 Roo.log(['register', tg, this]);
15188 var i = tg.tabs.length - 1;
15190 if(this.active && tg.bullets > 0 && i < tg.bullets){
15191 tg.setActiveBullet(i);
15198 onRender : function(ct, position)
15200 // Roo.log("Call onRender: " + this.xtype);
15202 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15210 setActive: function(state)
15212 Roo.log("panel - set active " + this.tabId + "=" + state);
15214 this.active = state;
15216 this.el.removeClass('active');
15218 } else if (!this.el.hasClass('active')) {
15219 this.el.addClass('active');
15222 this.fireEvent('changed', this, state);
15239 * @class Roo.bootstrap.DateField
15240 * @extends Roo.bootstrap.Input
15241 * Bootstrap DateField class
15242 * @cfg {Number} weekStart default 0
15243 * @cfg {String} viewMode default empty, (months|years)
15244 * @cfg {String} minViewMode default empty, (months|years)
15245 * @cfg {Number} startDate default -Infinity
15246 * @cfg {Number} endDate default Infinity
15247 * @cfg {Boolean} todayHighlight default false
15248 * @cfg {Boolean} todayBtn default false
15249 * @cfg {Boolean} calendarWeeks default false
15250 * @cfg {Object} daysOfWeekDisabled default empty
15251 * @cfg {Boolean} singleMode default false (true | false)
15253 * @cfg {Boolean} keyboardNavigation default true
15254 * @cfg {String} language default en
15257 * Create a new DateField
15258 * @param {Object} config The config object
15261 Roo.bootstrap.DateField = function(config){
15262 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15266 * Fires when this field show.
15267 * @param {Roo.bootstrap.DateField} this
15268 * @param {Mixed} date The date value
15273 * Fires when this field hide.
15274 * @param {Roo.bootstrap.DateField} this
15275 * @param {Mixed} date The date value
15280 * Fires when select a date.
15281 * @param {Roo.bootstrap.DateField} this
15282 * @param {Mixed} date The date value
15288 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15291 * @cfg {String} format
15292 * The default date format string which can be overriden for localization support. The format must be
15293 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15297 * @cfg {String} altFormats
15298 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15299 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15301 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15309 todayHighlight : false,
15315 keyboardNavigation: true,
15317 calendarWeeks: false,
15319 startDate: -Infinity,
15323 daysOfWeekDisabled: [],
15327 singleMode : false,
15329 UTCDate: function()
15331 return new Date(Date.UTC.apply(Date, arguments));
15334 UTCToday: function()
15336 var today = new Date();
15337 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15340 getDate: function() {
15341 var d = this.getUTCDate();
15342 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15345 getUTCDate: function() {
15349 setDate: function(d) {
15350 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15353 setUTCDate: function(d) {
15355 this.setValue(this.formatDate(this.date));
15358 onRender: function(ct, position)
15361 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15363 this.language = this.language || 'en';
15364 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15365 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15367 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15368 this.format = this.format || 'm/d/y';
15369 this.isInline = false;
15370 this.isInput = true;
15371 this.component = this.el.select('.add-on', true).first() || false;
15372 this.component = (this.component && this.component.length === 0) ? false : this.component;
15373 this.hasInput = this.component && this.inputEL().length;
15375 if (typeof(this.minViewMode === 'string')) {
15376 switch (this.minViewMode) {
15378 this.minViewMode = 1;
15381 this.minViewMode = 2;
15384 this.minViewMode = 0;
15389 if (typeof(this.viewMode === 'string')) {
15390 switch (this.viewMode) {
15403 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15405 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15407 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15409 this.picker().on('mousedown', this.onMousedown, this);
15410 this.picker().on('click', this.onClick, this);
15412 this.picker().addClass('datepicker-dropdown');
15414 this.startViewMode = this.viewMode;
15416 if(this.singleMode){
15417 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15418 v.setVisibilityMode(Roo.Element.DISPLAY)
15422 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15423 v.setStyle('width', '189px');
15427 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15428 if(!this.calendarWeeks){
15433 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15434 v.attr('colspan', function(i, val){
15435 return parseInt(val) + 1;
15440 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15442 this.setStartDate(this.startDate);
15443 this.setEndDate(this.endDate);
15445 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15452 if(this.isInline) {
15457 picker : function()
15459 return this.pickerEl;
15460 // return this.el.select('.datepicker', true).first();
15463 fillDow: function()
15465 var dowCnt = this.weekStart;
15474 if(this.calendarWeeks){
15482 while (dowCnt < this.weekStart + 7) {
15486 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15490 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15493 fillMonths: function()
15496 var months = this.picker().select('>.datepicker-months td', true).first();
15498 months.dom.innerHTML = '';
15504 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15507 months.createChild(month);
15514 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;
15516 if (this.date < this.startDate) {
15517 this.viewDate = new Date(this.startDate);
15518 } else if (this.date > this.endDate) {
15519 this.viewDate = new Date(this.endDate);
15521 this.viewDate = new Date(this.date);
15529 var d = new Date(this.viewDate),
15530 year = d.getUTCFullYear(),
15531 month = d.getUTCMonth(),
15532 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15533 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15534 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15535 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15536 currentDate = this.date && this.date.valueOf(),
15537 today = this.UTCToday();
15539 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15541 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15543 // this.picker.select('>tfoot th.today').
15544 // .text(dates[this.language].today)
15545 // .toggle(this.todayBtn !== false);
15547 this.updateNavArrows();
15550 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15552 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15554 prevMonth.setUTCDate(day);
15556 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15558 var nextMonth = new Date(prevMonth);
15560 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15562 nextMonth = nextMonth.valueOf();
15564 var fillMonths = false;
15566 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15568 while(prevMonth.valueOf() < nextMonth) {
15571 if (prevMonth.getUTCDay() === this.weekStart) {
15573 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15581 if(this.calendarWeeks){
15582 // ISO 8601: First week contains first thursday.
15583 // ISO also states week starts on Monday, but we can be more abstract here.
15585 // Start of current week: based on weekstart/current date
15586 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15587 // Thursday of this week
15588 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15589 // First Thursday of year, year from thursday
15590 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15591 // Calendar week: ms between thursdays, div ms per day, div 7 days
15592 calWeek = (th - yth) / 864e5 / 7 + 1;
15594 fillMonths.cn.push({
15602 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15604 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15607 if (this.todayHighlight &&
15608 prevMonth.getUTCFullYear() == today.getFullYear() &&
15609 prevMonth.getUTCMonth() == today.getMonth() &&
15610 prevMonth.getUTCDate() == today.getDate()) {
15611 clsName += ' today';
15614 if (currentDate && prevMonth.valueOf() === currentDate) {
15615 clsName += ' active';
15618 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15619 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15620 clsName += ' disabled';
15623 fillMonths.cn.push({
15625 cls: 'day ' + clsName,
15626 html: prevMonth.getDate()
15629 prevMonth.setDate(prevMonth.getDate()+1);
15632 var currentYear = this.date && this.date.getUTCFullYear();
15633 var currentMonth = this.date && this.date.getUTCMonth();
15635 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15637 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15638 v.removeClass('active');
15640 if(currentYear === year && k === currentMonth){
15641 v.addClass('active');
15644 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15645 v.addClass('disabled');
15651 year = parseInt(year/10, 10) * 10;
15653 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15655 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15658 for (var i = -1; i < 11; i++) {
15659 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15661 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15669 showMode: function(dir)
15672 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15675 Roo.each(this.picker().select('>div',true).elements, function(v){
15676 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15679 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15684 if(this.isInline) return;
15686 this.picker().removeClass(['bottom', 'top']);
15688 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15690 * place to the top of element!
15694 this.picker().addClass('top');
15695 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15700 this.picker().addClass('bottom');
15702 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15705 parseDate : function(value)
15707 if(!value || value instanceof Date){
15710 var v = Date.parseDate(value, this.format);
15711 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15712 v = Date.parseDate(value, 'Y-m-d');
15714 if(!v && this.altFormats){
15715 if(!this.altFormatsArray){
15716 this.altFormatsArray = this.altFormats.split("|");
15718 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15719 v = Date.parseDate(value, this.altFormatsArray[i]);
15725 formatDate : function(date, fmt)
15727 return (!date || !(date instanceof Date)) ?
15728 date : date.dateFormat(fmt || this.format);
15731 onFocus : function()
15733 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15737 onBlur : function()
15739 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15741 var d = this.inputEl().getValue();
15750 this.picker().show();
15754 this.fireEvent('show', this, this.date);
15759 if(this.isInline) return;
15760 this.picker().hide();
15761 this.viewMode = this.startViewMode;
15764 this.fireEvent('hide', this, this.date);
15768 onMousedown: function(e)
15770 e.stopPropagation();
15771 e.preventDefault();
15776 Roo.bootstrap.DateField.superclass.keyup.call(this);
15780 setValue: function(v)
15783 // v can be a string or a date..
15786 var d = new Date(this.parseDate(v) ).clearTime();
15788 if(isNaN(d.getTime())){
15789 this.date = this.viewDate = '';
15790 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15794 v = this.formatDate(d);
15796 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15798 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15802 this.fireEvent('select', this, this.date);
15806 getValue: function()
15808 return this.formatDate(this.date);
15811 fireKey: function(e)
15813 if (!this.picker().isVisible()){
15814 if (e.keyCode == 27) // allow escape to hide and re-show picker
15819 var dateChanged = false,
15821 newDate, newViewDate;
15826 e.preventDefault();
15830 if (!this.keyboardNavigation) break;
15831 dir = e.keyCode == 37 ? -1 : 1;
15834 newDate = this.moveYear(this.date, dir);
15835 newViewDate = this.moveYear(this.viewDate, dir);
15836 } else if (e.shiftKey){
15837 newDate = this.moveMonth(this.date, dir);
15838 newViewDate = this.moveMonth(this.viewDate, dir);
15840 newDate = new Date(this.date);
15841 newDate.setUTCDate(this.date.getUTCDate() + dir);
15842 newViewDate = new Date(this.viewDate);
15843 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15845 if (this.dateWithinRange(newDate)){
15846 this.date = newDate;
15847 this.viewDate = newViewDate;
15848 this.setValue(this.formatDate(this.date));
15850 e.preventDefault();
15851 dateChanged = true;
15856 if (!this.keyboardNavigation) break;
15857 dir = e.keyCode == 38 ? -1 : 1;
15859 newDate = this.moveYear(this.date, dir);
15860 newViewDate = this.moveYear(this.viewDate, dir);
15861 } else if (e.shiftKey){
15862 newDate = this.moveMonth(this.date, dir);
15863 newViewDate = this.moveMonth(this.viewDate, dir);
15865 newDate = new Date(this.date);
15866 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15867 newViewDate = new Date(this.viewDate);
15868 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15870 if (this.dateWithinRange(newDate)){
15871 this.date = newDate;
15872 this.viewDate = newViewDate;
15873 this.setValue(this.formatDate(this.date));
15875 e.preventDefault();
15876 dateChanged = true;
15880 this.setValue(this.formatDate(this.date));
15882 e.preventDefault();
15885 this.setValue(this.formatDate(this.date));
15899 onClick: function(e)
15901 e.stopPropagation();
15902 e.preventDefault();
15904 var target = e.getTarget();
15906 if(target.nodeName.toLowerCase() === 'i'){
15907 target = Roo.get(target).dom.parentNode;
15910 var nodeName = target.nodeName;
15911 var className = target.className;
15912 var html = target.innerHTML;
15913 //Roo.log(nodeName);
15915 switch(nodeName.toLowerCase()) {
15917 switch(className) {
15923 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15924 switch(this.viewMode){
15926 this.viewDate = this.moveMonth(this.viewDate, dir);
15930 this.viewDate = this.moveYear(this.viewDate, dir);
15936 var date = new Date();
15937 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15939 this.setValue(this.formatDate(this.date));
15946 if (className.indexOf('disabled') < 0) {
15947 this.viewDate.setUTCDate(1);
15948 if (className.indexOf('month') > -1) {
15949 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15951 var year = parseInt(html, 10) || 0;
15952 this.viewDate.setUTCFullYear(year);
15956 if(this.singleMode){
15957 this.setValue(this.formatDate(this.viewDate));
15968 //Roo.log(className);
15969 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15970 var day = parseInt(html, 10) || 1;
15971 var year = this.viewDate.getUTCFullYear(),
15972 month = this.viewDate.getUTCMonth();
15974 if (className.indexOf('old') > -1) {
15981 } else if (className.indexOf('new') > -1) {
15989 //Roo.log([year,month,day]);
15990 this.date = this.UTCDate(year, month, day,0,0,0,0);
15991 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15993 //Roo.log(this.formatDate(this.date));
15994 this.setValue(this.formatDate(this.date));
16001 setStartDate: function(startDate)
16003 this.startDate = startDate || -Infinity;
16004 if (this.startDate !== -Infinity) {
16005 this.startDate = this.parseDate(this.startDate);
16008 this.updateNavArrows();
16011 setEndDate: function(endDate)
16013 this.endDate = endDate || Infinity;
16014 if (this.endDate !== Infinity) {
16015 this.endDate = this.parseDate(this.endDate);
16018 this.updateNavArrows();
16021 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16023 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16024 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16025 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16027 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16028 return parseInt(d, 10);
16031 this.updateNavArrows();
16034 updateNavArrows: function()
16036 if(this.singleMode){
16040 var d = new Date(this.viewDate),
16041 year = d.getUTCFullYear(),
16042 month = d.getUTCMonth();
16044 Roo.each(this.picker().select('.prev', true).elements, function(v){
16046 switch (this.viewMode) {
16049 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16055 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16062 Roo.each(this.picker().select('.next', true).elements, function(v){
16064 switch (this.viewMode) {
16067 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16073 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16081 moveMonth: function(date, dir)
16083 if (!dir) return date;
16084 var new_date = new Date(date.valueOf()),
16085 day = new_date.getUTCDate(),
16086 month = new_date.getUTCMonth(),
16087 mag = Math.abs(dir),
16089 dir = dir > 0 ? 1 : -1;
16092 // If going back one month, make sure month is not current month
16093 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16095 return new_date.getUTCMonth() == month;
16097 // If going forward one month, make sure month is as expected
16098 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16100 return new_date.getUTCMonth() != new_month;
16102 new_month = month + dir;
16103 new_date.setUTCMonth(new_month);
16104 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16105 if (new_month < 0 || new_month > 11)
16106 new_month = (new_month + 12) % 12;
16108 // For magnitudes >1, move one month at a time...
16109 for (var i=0; i<mag; i++)
16110 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16111 new_date = this.moveMonth(new_date, dir);
16112 // ...then reset the day, keeping it in the new month
16113 new_month = new_date.getUTCMonth();
16114 new_date.setUTCDate(day);
16116 return new_month != new_date.getUTCMonth();
16119 // Common date-resetting loop -- if date is beyond end of month, make it
16122 new_date.setUTCDate(--day);
16123 new_date.setUTCMonth(new_month);
16128 moveYear: function(date, dir)
16130 return this.moveMonth(date, dir*12);
16133 dateWithinRange: function(date)
16135 return date >= this.startDate && date <= this.endDate;
16141 this.picker().remove();
16146 Roo.apply(Roo.bootstrap.DateField, {
16157 html: '<i class="fa fa-arrow-left"/>'
16167 html: '<i class="fa fa-arrow-right"/>'
16209 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16210 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16211 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16212 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16213 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16226 navFnc: 'FullYear',
16231 navFnc: 'FullYear',
16236 Roo.apply(Roo.bootstrap.DateField, {
16240 cls: 'datepicker dropdown-menu roo-dynamic',
16244 cls: 'datepicker-days',
16248 cls: 'table-condensed',
16250 Roo.bootstrap.DateField.head,
16254 Roo.bootstrap.DateField.footer
16261 cls: 'datepicker-months',
16265 cls: 'table-condensed',
16267 Roo.bootstrap.DateField.head,
16268 Roo.bootstrap.DateField.content,
16269 Roo.bootstrap.DateField.footer
16276 cls: 'datepicker-years',
16280 cls: 'table-condensed',
16282 Roo.bootstrap.DateField.head,
16283 Roo.bootstrap.DateField.content,
16284 Roo.bootstrap.DateField.footer
16303 * @class Roo.bootstrap.TimeField
16304 * @extends Roo.bootstrap.Input
16305 * Bootstrap DateField class
16309 * Create a new TimeField
16310 * @param {Object} config The config object
16313 Roo.bootstrap.TimeField = function(config){
16314 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16318 * Fires when this field show.
16319 * @param {Roo.bootstrap.DateField} thisthis
16320 * @param {Mixed} date The date value
16325 * Fires when this field hide.
16326 * @param {Roo.bootstrap.DateField} this
16327 * @param {Mixed} date The date value
16332 * Fires when select a date.
16333 * @param {Roo.bootstrap.DateField} this
16334 * @param {Mixed} date The date value
16340 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16343 * @cfg {String} format
16344 * The default time format string which can be overriden for localization support. The format must be
16345 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16349 onRender: function(ct, position)
16352 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16354 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16356 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16358 this.pop = this.picker().select('>.datepicker-time',true).first();
16359 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16361 this.picker().on('mousedown', this.onMousedown, this);
16362 this.picker().on('click', this.onClick, this);
16364 this.picker().addClass('datepicker-dropdown');
16369 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16370 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16371 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16372 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16373 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16374 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16378 fireKey: function(e){
16379 if (!this.picker().isVisible()){
16380 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16386 e.preventDefault();
16394 this.onTogglePeriod();
16397 this.onIncrementMinutes();
16400 this.onDecrementMinutes();
16409 onClick: function(e) {
16410 e.stopPropagation();
16411 e.preventDefault();
16414 picker : function()
16416 return this.el.select('.datepicker', true).first();
16419 fillTime: function()
16421 var time = this.pop.select('tbody', true).first();
16423 time.dom.innerHTML = '';
16438 cls: 'hours-up glyphicon glyphicon-chevron-up'
16458 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16479 cls: 'timepicker-hour',
16494 cls: 'timepicker-minute',
16509 cls: 'btn btn-primary period',
16531 cls: 'hours-down glyphicon glyphicon-chevron-down'
16551 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16569 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16576 var hours = this.time.getHours();
16577 var minutes = this.time.getMinutes();
16590 hours = hours - 12;
16594 hours = '0' + hours;
16598 minutes = '0' + minutes;
16601 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16602 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16603 this.pop.select('button', true).first().dom.innerHTML = period;
16609 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16611 var cls = ['bottom'];
16613 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16620 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16625 this.picker().addClass(cls.join('-'));
16629 Roo.each(cls, function(c){
16631 _this.picker().setTop(_this.inputEl().getHeight());
16635 _this.picker().setTop(0 - _this.picker().getHeight());
16640 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16644 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16651 onFocus : function()
16653 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16657 onBlur : function()
16659 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16665 this.picker().show();
16670 this.fireEvent('show', this, this.date);
16675 this.picker().hide();
16678 this.fireEvent('hide', this, this.date);
16681 setTime : function()
16684 this.setValue(this.time.format(this.format));
16686 this.fireEvent('select', this, this.date);
16691 onMousedown: function(e){
16692 e.stopPropagation();
16693 e.preventDefault();
16696 onIncrementHours: function()
16698 Roo.log('onIncrementHours');
16699 this.time = this.time.add(Date.HOUR, 1);
16704 onDecrementHours: function()
16706 Roo.log('onDecrementHours');
16707 this.time = this.time.add(Date.HOUR, -1);
16711 onIncrementMinutes: function()
16713 Roo.log('onIncrementMinutes');
16714 this.time = this.time.add(Date.MINUTE, 1);
16718 onDecrementMinutes: function()
16720 Roo.log('onDecrementMinutes');
16721 this.time = this.time.add(Date.MINUTE, -1);
16725 onTogglePeriod: function()
16727 Roo.log('onTogglePeriod');
16728 this.time = this.time.add(Date.HOUR, 12);
16735 Roo.apply(Roo.bootstrap.TimeField, {
16765 cls: 'btn btn-info ok',
16777 Roo.apply(Roo.bootstrap.TimeField, {
16781 cls: 'datepicker dropdown-menu',
16785 cls: 'datepicker-time',
16789 cls: 'table-condensed',
16791 Roo.bootstrap.TimeField.content,
16792 Roo.bootstrap.TimeField.footer
16811 * @class Roo.bootstrap.MonthField
16812 * @extends Roo.bootstrap.Input
16813 * Bootstrap MonthField class
16815 * @cfg {String} language default en
16818 * Create a new MonthField
16819 * @param {Object} config The config object
16822 Roo.bootstrap.MonthField = function(config){
16823 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16828 * Fires when this field show.
16829 * @param {Roo.bootstrap.MonthField} this
16830 * @param {Mixed} date The date value
16835 * Fires when this field hide.
16836 * @param {Roo.bootstrap.MonthField} this
16837 * @param {Mixed} date The date value
16842 * Fires when select a date.
16843 * @param {Roo.bootstrap.MonthField} this
16844 * @param {String} oldvalue The old value
16845 * @param {String} newvalue The new value
16851 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16853 onRender: function(ct, position)
16856 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16858 this.language = this.language || 'en';
16859 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16860 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16862 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16863 this.isInline = false;
16864 this.isInput = true;
16865 this.component = this.el.select('.add-on', true).first() || false;
16866 this.component = (this.component && this.component.length === 0) ? false : this.component;
16867 this.hasInput = this.component && this.inputEL().length;
16869 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16871 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16873 this.picker().on('mousedown', this.onMousedown, this);
16874 this.picker().on('click', this.onClick, this);
16876 this.picker().addClass('datepicker-dropdown');
16878 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16879 v.setStyle('width', '189px');
16886 if(this.isInline) {
16892 setValue: function(v, suppressEvent)
16894 var o = this.getValue();
16896 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16900 if(suppressEvent !== true){
16901 this.fireEvent('select', this, o, v);
16906 getValue: function()
16911 onClick: function(e)
16913 e.stopPropagation();
16914 e.preventDefault();
16916 var target = e.getTarget();
16918 if(target.nodeName.toLowerCase() === 'i'){
16919 target = Roo.get(target).dom.parentNode;
16922 var nodeName = target.nodeName;
16923 var className = target.className;
16924 var html = target.innerHTML;
16926 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16930 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16932 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16938 picker : function()
16940 return this.pickerEl;
16943 fillMonths: function()
16946 var months = this.picker().select('>.datepicker-months td', true).first();
16948 months.dom.innerHTML = '';
16954 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16957 months.createChild(month);
16966 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16967 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16970 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16971 e.removeClass('active');
16973 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16974 e.addClass('active');
16981 if(this.isInline) return;
16983 this.picker().removeClass(['bottom', 'top']);
16985 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16987 * place to the top of element!
16991 this.picker().addClass('top');
16992 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16997 this.picker().addClass('bottom');
16999 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17002 onFocus : function()
17004 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17008 onBlur : function()
17010 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17012 var d = this.inputEl().getValue();
17021 this.picker().show();
17022 this.picker().select('>.datepicker-months', true).first().show();
17026 this.fireEvent('show', this, this.date);
17031 if(this.isInline) return;
17032 this.picker().hide();
17033 this.fireEvent('hide', this, this.date);
17037 onMousedown: function(e)
17039 e.stopPropagation();
17040 e.preventDefault();
17045 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17049 fireKey: function(e)
17051 if (!this.picker().isVisible()){
17052 if (e.keyCode == 27) // allow escape to hide and re-show picker
17062 e.preventDefault();
17066 dir = e.keyCode == 37 ? -1 : 1;
17068 this.vIndex = this.vIndex + dir;
17070 if(this.vIndex < 0){
17074 if(this.vIndex > 11){
17078 if(isNaN(this.vIndex)){
17082 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17088 dir = e.keyCode == 38 ? -1 : 1;
17090 this.vIndex = this.vIndex + dir * 4;
17092 if(this.vIndex < 0){
17096 if(this.vIndex > 11){
17100 if(isNaN(this.vIndex)){
17104 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17109 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17110 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17114 e.preventDefault();
17117 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17118 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17134 this.picker().remove();
17139 Roo.apply(Roo.bootstrap.MonthField, {
17158 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17159 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17164 Roo.apply(Roo.bootstrap.MonthField, {
17168 cls: 'datepicker dropdown-menu roo-dynamic',
17172 cls: 'datepicker-months',
17176 cls: 'table-condensed',
17178 Roo.bootstrap.DateField.content
17198 * @class Roo.bootstrap.CheckBox
17199 * @extends Roo.bootstrap.Input
17200 * Bootstrap CheckBox class
17202 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17203 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17204 * @cfg {String} boxLabel The text that appears beside the checkbox
17205 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17206 * @cfg {Boolean} checked initnal the element
17207 * @cfg {Boolean} inline inline the element (default false)
17208 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17211 * Create a new CheckBox
17212 * @param {Object} config The config object
17215 Roo.bootstrap.CheckBox = function(config){
17216 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17221 * Fires when the element is checked or unchecked.
17222 * @param {Roo.bootstrap.CheckBox} this This input
17223 * @param {Boolean} checked The new checked value
17230 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17232 inputType: 'checkbox',
17240 getAutoCreate : function()
17242 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17248 cfg.cls = 'form-group ' + this.inputType; //input-group
17251 cfg.cls += ' ' + this.inputType + '-inline';
17257 type : this.inputType,
17258 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17259 cls : 'roo-' + this.inputType, //'form-box',
17260 placeholder : this.placeholder || ''
17264 if (this.weight) { // Validity check?
17265 cfg.cls += " " + this.inputType + "-" + this.weight;
17268 if (this.disabled) {
17269 input.disabled=true;
17273 input.checked = this.checked;
17277 input.name = this.name;
17281 input.cls += ' input-' + this.size;
17286 ['xs','sm','md','lg'].map(function(size){
17287 if (settings[size]) {
17288 cfg.cls += ' col-' + size + '-' + settings[size];
17292 var inputblock = input;
17294 if (this.before || this.after) {
17297 cls : 'input-group',
17302 inputblock.cn.push({
17304 cls : 'input-group-addon',
17309 inputblock.cn.push(input);
17312 inputblock.cn.push({
17314 cls : 'input-group-addon',
17321 if (align ==='left' && this.fieldLabel.length) {
17322 Roo.log("left and has label");
17328 cls : 'control-label col-md-' + this.labelWidth,
17329 html : this.fieldLabel
17333 cls : "col-md-" + (12 - this.labelWidth),
17340 } else if ( this.fieldLabel.length) {
17345 tag: this.boxLabel ? 'span' : 'label',
17347 cls: 'control-label box-input-label',
17348 //cls : 'input-group-addon',
17349 html : this.fieldLabel
17359 Roo.log(" no label && no align");
17360 cfg.cn = [ inputblock ] ;
17365 var boxLabelCfg = {
17367 //'for': id, // box label is handled by onclick - so no for...
17369 html: this.boxLabel
17373 boxLabelCfg.tooltip = this.tooltip;
17376 cfg.cn.push(boxLabelCfg);
17386 * return the real input element.
17388 inputEl: function ()
17390 return this.el.select('input.roo-' + this.inputType,true).first();
17393 labelEl: function()
17395 return this.el.select('label.control-label',true).first();
17397 /* depricated... */
17401 return this.labelEl();
17404 initEvents : function()
17406 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17408 this.inputEl().on('click', this.onClick, this);
17410 if (this.boxLabel) {
17411 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17414 this.startValue = this.getValue();
17417 Roo.bootstrap.CheckBox.register(this);
17421 onClick : function()
17423 this.setChecked(!this.checked);
17426 setChecked : function(state,suppressEvent)
17428 this.startValue = this.getValue();
17430 if(this.inputType == 'radio'){
17432 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17433 e.dom.checked = false;
17436 this.inputEl().dom.checked = true;
17438 this.inputEl().dom.value = this.inputValue;
17440 if(suppressEvent !== true){
17441 this.fireEvent('check', this, true);
17449 this.checked = state;
17451 this.inputEl().dom.checked = state;
17453 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17455 if(suppressEvent !== true){
17456 this.fireEvent('check', this, state);
17462 getValue : function()
17464 if(this.inputType == 'radio'){
17465 return this.getGroupValue();
17468 return this.inputEl().getValue();
17472 getGroupValue : function()
17474 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17478 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17481 setValue : function(v,suppressEvent)
17483 if(this.inputType == 'radio'){
17484 this.setGroupValue(v, suppressEvent);
17488 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17493 setGroupValue : function(v, suppressEvent)
17495 this.startValue = this.getValue();
17497 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17498 e.dom.checked = false;
17500 if(e.dom.value == v){
17501 e.dom.checked = true;
17505 if(suppressEvent !== true){
17506 this.fireEvent('check', this, true);
17514 validate : function()
17518 (this.inputType == 'radio' && this.validateRadio()) ||
17519 (this.inputType == 'checkbox' && this.validateCheckbox())
17525 this.markInvalid();
17529 validateRadio : function()
17533 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17534 if(!e.dom.checked){
17546 validateCheckbox : function()
17549 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17552 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17560 for(var i in group){
17565 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17572 * Mark this field as valid
17574 markValid : function()
17576 if(this.allowBlank){
17582 this.fireEvent('valid', this);
17584 if(this.inputType == 'radio'){
17585 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17586 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17587 e.findParent('.form-group', false, true).addClass(_this.validClass);
17594 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17595 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17599 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17605 for(var i in group){
17606 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17607 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17612 * Mark this field as invalid
17613 * @param {String} msg The validation message
17615 markInvalid : function(msg)
17617 if(this.allowBlank){
17623 this.fireEvent('invalid', this, msg);
17625 if(this.inputType == 'radio'){
17626 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17627 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17628 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17635 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17636 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17640 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17646 for(var i in group){
17647 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17648 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17655 Roo.apply(Roo.bootstrap.CheckBox, {
17660 * register a CheckBox Group
17661 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17663 register : function(checkbox)
17665 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17666 this.groups[checkbox.groupId] = {};
17669 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17673 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17677 * fetch a CheckBox Group based on the group ID
17678 * @param {string} the group ID
17679 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17681 get: function(groupId) {
17682 if (typeof(this.groups[groupId]) == 'undefined') {
17686 return this.groups[groupId] ;
17698 *<div class="radio">
17700 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17701 Option one is this and that—be sure to include why it's great
17708 *<label class="radio-inline">fieldLabel</label>
17709 *<label class="radio-inline">
17710 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17718 * @class Roo.bootstrap.Radio
17719 * @extends Roo.bootstrap.CheckBox
17720 * Bootstrap Radio class
17723 * Create a new Radio
17724 * @param {Object} config The config object
17727 Roo.bootstrap.Radio = function(config){
17728 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17732 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17734 inputType: 'radio',
17738 getAutoCreate : function()
17740 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17741 align = align || 'left'; // default...
17748 tag : this.inline ? 'span' : 'div',
17753 var inline = this.inline ? ' radio-inline' : '';
17757 // does not need for, as we wrap the input with it..
17759 cls : 'control-label box-label' + inline,
17762 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17766 //cls : 'control-label' + inline,
17767 html : this.fieldLabel,
17768 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17777 type : this.inputType,
17778 //value : (!this.checked) ? this.valueOff : this.inputValue,
17779 value : this.inputValue,
17781 placeholder : this.placeholder || '' // ?? needed????
17784 if (this.weight) { // Validity check?
17785 input.cls += " radio-" + this.weight;
17787 if (this.disabled) {
17788 input.disabled=true;
17792 input.checked = this.checked;
17796 input.name = this.name;
17800 input.cls += ' input-' + this.size;
17803 //?? can span's inline have a width??
17806 ['xs','sm','md','lg'].map(function(size){
17807 if (settings[size]) {
17808 cfg.cls += ' col-' + size + '-' + settings[size];
17812 var inputblock = input;
17814 if (this.before || this.after) {
17817 cls : 'input-group',
17822 inputblock.cn.push({
17824 cls : 'input-group-addon',
17828 inputblock.cn.push(input);
17830 inputblock.cn.push({
17832 cls : 'input-group-addon',
17840 if (this.fieldLabel && this.fieldLabel.length) {
17841 cfg.cn.push(fieldLabel);
17844 // normal bootstrap puts the input inside the label.
17845 // however with our styled version - it has to go after the input.
17847 //lbl.cn.push(inputblock);
17851 cls: 'radio' + inline,
17858 cfg.cn.push( lblwrap);
17863 html: this.boxLabel
17872 initEvents : function()
17874 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17876 this.inputEl().on('click', this.onClick, this);
17877 if (this.boxLabel) {
17878 Roo.log('find label')
17879 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17884 inputEl: function ()
17886 return this.el.select('input.roo-radio',true).first();
17888 onClick : function()
17891 this.setChecked(true);
17894 setChecked : function(state,suppressEvent)
17897 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17898 v.dom.checked = false;
17901 Roo.log(this.inputEl().dom);
17902 this.checked = state;
17903 this.inputEl().dom.checked = state;
17905 if(suppressEvent !== true){
17906 this.fireEvent('check', this, state);
17909 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17913 getGroupValue : function()
17916 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17917 if(v.dom.checked == true){
17918 value = v.dom.value;
17926 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17927 * @return {Mixed} value The field value
17929 getValue : function(){
17930 return this.getGroupValue();
17936 //<script type="text/javascript">
17939 * Based Ext JS Library 1.1.1
17940 * Copyright(c) 2006-2007, Ext JS, LLC.
17946 * @class Roo.HtmlEditorCore
17947 * @extends Roo.Component
17948 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17950 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17953 Roo.HtmlEditorCore = function(config){
17956 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17961 * @event initialize
17962 * Fires when the editor is fully initialized (including the iframe)
17963 * @param {Roo.HtmlEditorCore} this
17968 * Fires when the editor is first receives the focus. Any insertion must wait
17969 * until after this event.
17970 * @param {Roo.HtmlEditorCore} this
17974 * @event beforesync
17975 * Fires before the textarea is updated with content from the editor iframe. Return false
17976 * to cancel the sync.
17977 * @param {Roo.HtmlEditorCore} this
17978 * @param {String} html
17982 * @event beforepush
17983 * Fires before the iframe editor is updated with content from the textarea. Return false
17984 * to cancel the push.
17985 * @param {Roo.HtmlEditorCore} this
17986 * @param {String} html
17991 * Fires when the textarea is updated with content from the editor iframe.
17992 * @param {Roo.HtmlEditorCore} this
17993 * @param {String} html
17998 * Fires when the iframe editor is updated with content from the textarea.
17999 * @param {Roo.HtmlEditorCore} this
18000 * @param {String} html
18005 * @event editorevent
18006 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18007 * @param {Roo.HtmlEditorCore} this
18013 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18015 // defaults : white / black...
18016 this.applyBlacklists();
18023 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18027 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18033 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18038 * @cfg {Number} height (in pixels)
18042 * @cfg {Number} width (in pixels)
18047 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18050 stylesheets: false,
18055 // private properties
18056 validationEvent : false,
18058 initialized : false,
18060 sourceEditMode : false,
18061 onFocus : Roo.emptyFn,
18063 hideMode:'offsets',
18067 // blacklist + whitelisted elements..
18074 * Protected method that will not generally be called directly. It
18075 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18076 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18078 getDocMarkup : function(){
18082 // inherit styels from page...??
18083 if (this.stylesheets === false) {
18085 Roo.get(document.head).select('style').each(function(node) {
18086 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18089 Roo.get(document.head).select('link').each(function(node) {
18090 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18093 } else if (!this.stylesheets.length) {
18095 st = '<style type="text/css">' +
18096 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18102 st += '<style type="text/css">' +
18103 'IMG { cursor: pointer } ' +
18107 return '<html><head>' + st +
18108 //<style type="text/css">' +
18109 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18111 ' </head><body class="roo-htmleditor-body"></body></html>';
18115 onRender : function(ct, position)
18118 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18119 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18122 this.el.dom.style.border = '0 none';
18123 this.el.dom.setAttribute('tabIndex', -1);
18124 this.el.addClass('x-hidden hide');
18128 if(Roo.isIE){ // fix IE 1px bogus margin
18129 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18133 this.frameId = Roo.id();
18137 var iframe = this.owner.wrap.createChild({
18139 cls: 'form-control', // bootstrap..
18141 name: this.frameId,
18142 frameBorder : 'no',
18143 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18148 this.iframe = iframe.dom;
18150 this.assignDocWin();
18152 this.doc.designMode = 'on';
18155 this.doc.write(this.getDocMarkup());
18159 var task = { // must defer to wait for browser to be ready
18161 //console.log("run task?" + this.doc.readyState);
18162 this.assignDocWin();
18163 if(this.doc.body || this.doc.readyState == 'complete'){
18165 this.doc.designMode="on";
18169 Roo.TaskMgr.stop(task);
18170 this.initEditor.defer(10, this);
18177 Roo.TaskMgr.start(task);
18182 onResize : function(w, h)
18184 Roo.log('resize: ' +w + ',' + h );
18185 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18189 if(typeof w == 'number'){
18191 this.iframe.style.width = w + 'px';
18193 if(typeof h == 'number'){
18195 this.iframe.style.height = h + 'px';
18197 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18204 * Toggles the editor between standard and source edit mode.
18205 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18207 toggleSourceEdit : function(sourceEditMode){
18209 this.sourceEditMode = sourceEditMode === true;
18211 if(this.sourceEditMode){
18213 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18216 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18217 //this.iframe.className = '';
18220 //this.setSize(this.owner.wrap.getSize());
18221 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18228 * Protected method that will not generally be called directly. If you need/want
18229 * custom HTML cleanup, this is the method you should override.
18230 * @param {String} html The HTML to be cleaned
18231 * return {String} The cleaned HTML
18233 cleanHtml : function(html){
18234 html = String(html);
18235 if(html.length > 5){
18236 if(Roo.isSafari){ // strip safari nonsense
18237 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18240 if(html == ' '){
18247 * HTML Editor -> Textarea
18248 * Protected method that will not generally be called directly. Syncs the contents
18249 * of the editor iframe with the textarea.
18251 syncValue : function(){
18252 if(this.initialized){
18253 var bd = (this.doc.body || this.doc.documentElement);
18254 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18255 var html = bd.innerHTML;
18257 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18258 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18260 html = '<div style="'+m[0]+'">' + html + '</div>';
18263 html = this.cleanHtml(html);
18264 // fix up the special chars.. normaly like back quotes in word...
18265 // however we do not want to do this with chinese..
18266 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18267 var cc = b.charCodeAt();
18269 (cc >= 0x4E00 && cc < 0xA000 ) ||
18270 (cc >= 0x3400 && cc < 0x4E00 ) ||
18271 (cc >= 0xf900 && cc < 0xfb00 )
18277 if(this.owner.fireEvent('beforesync', this, html) !== false){
18278 this.el.dom.value = html;
18279 this.owner.fireEvent('sync', this, html);
18285 * Protected method that will not generally be called directly. Pushes the value of the textarea
18286 * into the iframe editor.
18288 pushValue : function(){
18289 if(this.initialized){
18290 var v = this.el.dom.value.trim();
18292 // if(v.length < 1){
18296 if(this.owner.fireEvent('beforepush', this, v) !== false){
18297 var d = (this.doc.body || this.doc.documentElement);
18299 this.cleanUpPaste();
18300 this.el.dom.value = d.innerHTML;
18301 this.owner.fireEvent('push', this, v);
18307 deferFocus : function(){
18308 this.focus.defer(10, this);
18312 focus : function(){
18313 if(this.win && !this.sourceEditMode){
18320 assignDocWin: function()
18322 var iframe = this.iframe;
18325 this.doc = iframe.contentWindow.document;
18326 this.win = iframe.contentWindow;
18328 // if (!Roo.get(this.frameId)) {
18331 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18332 // this.win = Roo.get(this.frameId).dom.contentWindow;
18334 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18338 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18339 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18344 initEditor : function(){
18345 //console.log("INIT EDITOR");
18346 this.assignDocWin();
18350 this.doc.designMode="on";
18352 this.doc.write(this.getDocMarkup());
18355 var dbody = (this.doc.body || this.doc.documentElement);
18356 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18357 // this copies styles from the containing element into thsi one..
18358 // not sure why we need all of this..
18359 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18361 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18362 //ss['background-attachment'] = 'fixed'; // w3c
18363 dbody.bgProperties = 'fixed'; // ie
18364 //Roo.DomHelper.applyStyles(dbody, ss);
18365 Roo.EventManager.on(this.doc, {
18366 //'mousedown': this.onEditorEvent,
18367 'mouseup': this.onEditorEvent,
18368 'dblclick': this.onEditorEvent,
18369 'click': this.onEditorEvent,
18370 'keyup': this.onEditorEvent,
18375 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18377 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18378 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18380 this.initialized = true;
18382 this.owner.fireEvent('initialize', this);
18387 onDestroy : function(){
18393 //for (var i =0; i < this.toolbars.length;i++) {
18394 // // fixme - ask toolbars for heights?
18395 // this.toolbars[i].onDestroy();
18398 //this.wrap.dom.innerHTML = '';
18399 //this.wrap.remove();
18404 onFirstFocus : function(){
18406 this.assignDocWin();
18409 this.activated = true;
18412 if(Roo.isGecko){ // prevent silly gecko errors
18414 var s = this.win.getSelection();
18415 if(!s.focusNode || s.focusNode.nodeType != 3){
18416 var r = s.getRangeAt(0);
18417 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18422 this.execCmd('useCSS', true);
18423 this.execCmd('styleWithCSS', false);
18426 this.owner.fireEvent('activate', this);
18430 adjustFont: function(btn){
18431 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18432 //if(Roo.isSafari){ // safari
18435 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18436 if(Roo.isSafari){ // safari
18437 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18438 v = (v < 10) ? 10 : v;
18439 v = (v > 48) ? 48 : v;
18440 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18445 v = Math.max(1, v+adjust);
18447 this.execCmd('FontSize', v );
18450 onEditorEvent : function(e){
18451 this.owner.fireEvent('editorevent', this, e);
18452 // this.updateToolbar();
18453 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18456 insertTag : function(tg)
18458 // could be a bit smarter... -> wrap the current selected tRoo..
18459 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18461 range = this.createRange(this.getSelection());
18462 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18463 wrappingNode.appendChild(range.extractContents());
18464 range.insertNode(wrappingNode);
18471 this.execCmd("formatblock", tg);
18475 insertText : function(txt)
18479 var range = this.createRange();
18480 range.deleteContents();
18481 //alert(Sender.getAttribute('label'));
18483 range.insertNode(this.doc.createTextNode(txt));
18489 * Executes a Midas editor command on the editor document and performs necessary focus and
18490 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18491 * @param {String} cmd The Midas command
18492 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18494 relayCmd : function(cmd, value){
18496 this.execCmd(cmd, value);
18497 this.owner.fireEvent('editorevent', this);
18498 //this.updateToolbar();
18499 this.owner.deferFocus();
18503 * Executes a Midas editor command directly on the editor document.
18504 * For visual commands, you should use {@link #relayCmd} instead.
18505 * <b>This should only be called after the editor is initialized.</b>
18506 * @param {String} cmd The Midas command
18507 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18509 execCmd : function(cmd, value){
18510 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18517 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18519 * @param {String} text | dom node..
18521 insertAtCursor : function(text)
18526 if(!this.activated){
18532 var r = this.doc.selection.createRange();
18543 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18547 // from jquery ui (MIT licenced)
18549 var win = this.win;
18551 if (win.getSelection && win.getSelection().getRangeAt) {
18552 range = win.getSelection().getRangeAt(0);
18553 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18554 range.insertNode(node);
18555 } else if (win.document.selection && win.document.selection.createRange) {
18556 // no firefox support
18557 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18558 win.document.selection.createRange().pasteHTML(txt);
18560 // no firefox support
18561 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18562 this.execCmd('InsertHTML', txt);
18571 mozKeyPress : function(e){
18573 var c = e.getCharCode(), cmd;
18576 c = String.fromCharCode(c).toLowerCase();
18590 this.cleanUpPaste.defer(100, this);
18598 e.preventDefault();
18606 fixKeys : function(){ // load time branching for fastest keydown performance
18608 return function(e){
18609 var k = e.getKey(), r;
18612 r = this.doc.selection.createRange();
18615 r.pasteHTML('    ');
18622 r = this.doc.selection.createRange();
18624 var target = r.parentElement();
18625 if(!target || target.tagName.toLowerCase() != 'li'){
18627 r.pasteHTML('<br />');
18633 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18634 this.cleanUpPaste.defer(100, this);
18640 }else if(Roo.isOpera){
18641 return function(e){
18642 var k = e.getKey();
18646 this.execCmd('InsertHTML','    ');
18649 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18650 this.cleanUpPaste.defer(100, this);
18655 }else if(Roo.isSafari){
18656 return function(e){
18657 var k = e.getKey();
18661 this.execCmd('InsertText','\t');
18665 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18666 this.cleanUpPaste.defer(100, this);
18674 getAllAncestors: function()
18676 var p = this.getSelectedNode();
18679 a.push(p); // push blank onto stack..
18680 p = this.getParentElement();
18684 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18688 a.push(this.doc.body);
18692 lastSelNode : false,
18695 getSelection : function()
18697 this.assignDocWin();
18698 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18701 getSelectedNode: function()
18703 // this may only work on Gecko!!!
18705 // should we cache this!!!!
18710 var range = this.createRange(this.getSelection()).cloneRange();
18713 var parent = range.parentElement();
18715 var testRange = range.duplicate();
18716 testRange.moveToElementText(parent);
18717 if (testRange.inRange(range)) {
18720 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18723 parent = parent.parentElement;
18728 // is ancestor a text element.
18729 var ac = range.commonAncestorContainer;
18730 if (ac.nodeType == 3) {
18731 ac = ac.parentNode;
18734 var ar = ac.childNodes;
18737 var other_nodes = [];
18738 var has_other_nodes = false;
18739 for (var i=0;i<ar.length;i++) {
18740 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18743 // fullly contained node.
18745 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18750 // probably selected..
18751 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18752 other_nodes.push(ar[i]);
18756 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18761 has_other_nodes = true;
18763 if (!nodes.length && other_nodes.length) {
18764 nodes= other_nodes;
18766 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18772 createRange: function(sel)
18774 // this has strange effects when using with
18775 // top toolbar - not sure if it's a great idea.
18776 //this.editor.contentWindow.focus();
18777 if (typeof sel != "undefined") {
18779 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18781 return this.doc.createRange();
18784 return this.doc.createRange();
18787 getParentElement: function()
18790 this.assignDocWin();
18791 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18793 var range = this.createRange(sel);
18796 var p = range.commonAncestorContainer;
18797 while (p.nodeType == 3) { // text node
18808 * Range intersection.. the hard stuff...
18812 * [ -- selected range --- ]
18816 * if end is before start or hits it. fail.
18817 * if start is after end or hits it fail.
18819 * if either hits (but other is outside. - then it's not
18825 // @see http://www.thismuchiknow.co.uk/?p=64.
18826 rangeIntersectsNode : function(range, node)
18828 var nodeRange = node.ownerDocument.createRange();
18830 nodeRange.selectNode(node);
18832 nodeRange.selectNodeContents(node);
18835 var rangeStartRange = range.cloneRange();
18836 rangeStartRange.collapse(true);
18838 var rangeEndRange = range.cloneRange();
18839 rangeEndRange.collapse(false);
18841 var nodeStartRange = nodeRange.cloneRange();
18842 nodeStartRange.collapse(true);
18844 var nodeEndRange = nodeRange.cloneRange();
18845 nodeEndRange.collapse(false);
18847 return rangeStartRange.compareBoundaryPoints(
18848 Range.START_TO_START, nodeEndRange) == -1 &&
18849 rangeEndRange.compareBoundaryPoints(
18850 Range.START_TO_START, nodeStartRange) == 1;
18854 rangeCompareNode : function(range, node)
18856 var nodeRange = node.ownerDocument.createRange();
18858 nodeRange.selectNode(node);
18860 nodeRange.selectNodeContents(node);
18864 range.collapse(true);
18866 nodeRange.collapse(true);
18868 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18869 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18871 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18873 var nodeIsBefore = ss == 1;
18874 var nodeIsAfter = ee == -1;
18876 if (nodeIsBefore && nodeIsAfter)
18878 if (!nodeIsBefore && nodeIsAfter)
18879 return 1; //right trailed.
18881 if (nodeIsBefore && !nodeIsAfter)
18882 return 2; // left trailed.
18887 // private? - in a new class?
18888 cleanUpPaste : function()
18890 // cleans up the whole document..
18891 Roo.log('cleanuppaste');
18893 this.cleanUpChildren(this.doc.body);
18894 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18895 if (clean != this.doc.body.innerHTML) {
18896 this.doc.body.innerHTML = clean;
18901 cleanWordChars : function(input) {// change the chars to hex code
18902 var he = Roo.HtmlEditorCore;
18904 var output = input;
18905 Roo.each(he.swapCodes, function(sw) {
18906 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18908 output = output.replace(swapper, sw[1]);
18915 cleanUpChildren : function (n)
18917 if (!n.childNodes.length) {
18920 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18921 this.cleanUpChild(n.childNodes[i]);
18928 cleanUpChild : function (node)
18931 //console.log(node);
18932 if (node.nodeName == "#text") {
18933 // clean up silly Windows -- stuff?
18936 if (node.nodeName == "#comment") {
18937 node.parentNode.removeChild(node);
18938 // clean up silly Windows -- stuff?
18941 var lcname = node.tagName.toLowerCase();
18942 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18943 // whitelist of tags..
18945 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18947 node.parentNode.removeChild(node);
18952 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18954 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18955 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18957 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18958 // remove_keep_children = true;
18961 if (remove_keep_children) {
18962 this.cleanUpChildren(node);
18963 // inserts everything just before this node...
18964 while (node.childNodes.length) {
18965 var cn = node.childNodes[0];
18966 node.removeChild(cn);
18967 node.parentNode.insertBefore(cn, node);
18969 node.parentNode.removeChild(node);
18973 if (!node.attributes || !node.attributes.length) {
18974 this.cleanUpChildren(node);
18978 function cleanAttr(n,v)
18981 if (v.match(/^\./) || v.match(/^\//)) {
18984 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18987 if (v.match(/^#/)) {
18990 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18991 node.removeAttribute(n);
18995 var cwhite = this.cwhite;
18996 var cblack = this.cblack;
18998 function cleanStyle(n,v)
19000 if (v.match(/expression/)) { //XSS?? should we even bother..
19001 node.removeAttribute(n);
19005 var parts = v.split(/;/);
19008 Roo.each(parts, function(p) {
19009 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19013 var l = p.split(':').shift().replace(/\s+/g,'');
19014 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19016 if ( cwhite.length && cblack.indexOf(l) > -1) {
19017 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19018 //node.removeAttribute(n);
19022 // only allow 'c whitelisted system attributes'
19023 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19024 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19025 //node.removeAttribute(n);
19035 if (clean.length) {
19036 node.setAttribute(n, clean.join(';'));
19038 node.removeAttribute(n);
19044 for (var i = node.attributes.length-1; i > -1 ; i--) {
19045 var a = node.attributes[i];
19048 if (a.name.toLowerCase().substr(0,2)=='on') {
19049 node.removeAttribute(a.name);
19052 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19053 node.removeAttribute(a.name);
19056 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19057 cleanAttr(a.name,a.value); // fixme..
19060 if (a.name == 'style') {
19061 cleanStyle(a.name,a.value);
19064 /// clean up MS crap..
19065 // tecnically this should be a list of valid class'es..
19068 if (a.name == 'class') {
19069 if (a.value.match(/^Mso/)) {
19070 node.className = '';
19073 if (a.value.match(/body/)) {
19074 node.className = '';
19085 this.cleanUpChildren(node);
19090 * Clean up MS wordisms...
19092 cleanWord : function(node)
19095 var cleanWordChildren = function()
19097 if (!node.childNodes.length) {
19100 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19101 _t.cleanWord(node.childNodes[i]);
19107 this.cleanWord(this.doc.body);
19110 if (node.nodeName == "#text") {
19111 // clean up silly Windows -- stuff?
19114 if (node.nodeName == "#comment") {
19115 node.parentNode.removeChild(node);
19116 // clean up silly Windows -- stuff?
19120 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19121 node.parentNode.removeChild(node);
19125 // remove - but keep children..
19126 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19127 while (node.childNodes.length) {
19128 var cn = node.childNodes[0];
19129 node.removeChild(cn);
19130 node.parentNode.insertBefore(cn, node);
19132 node.parentNode.removeChild(node);
19133 cleanWordChildren();
19137 if (node.className.length) {
19139 var cn = node.className.split(/\W+/);
19141 Roo.each(cn, function(cls) {
19142 if (cls.match(/Mso[a-zA-Z]+/)) {
19147 node.className = cna.length ? cna.join(' ') : '';
19149 node.removeAttribute("class");
19153 if (node.hasAttribute("lang")) {
19154 node.removeAttribute("lang");
19157 if (node.hasAttribute("style")) {
19159 var styles = node.getAttribute("style").split(";");
19161 Roo.each(styles, function(s) {
19162 if (!s.match(/:/)) {
19165 var kv = s.split(":");
19166 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19169 // what ever is left... we allow.
19172 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19173 if (!nstyle.length) {
19174 node.removeAttribute('style');
19178 cleanWordChildren();
19182 domToHTML : function(currentElement, depth, nopadtext) {
19184 depth = depth || 0;
19185 nopadtext = nopadtext || false;
19187 if (!currentElement) {
19188 return this.domToHTML(this.doc.body);
19191 //Roo.log(currentElement);
19193 var allText = false;
19194 var nodeName = currentElement.nodeName;
19195 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19197 if (nodeName == '#text') {
19199 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19204 if (nodeName != 'BODY') {
19207 // Prints the node tagName, such as <A>, <IMG>, etc
19210 for(i = 0; i < currentElement.attributes.length;i++) {
19212 var aname = currentElement.attributes.item(i).name;
19213 if (!currentElement.attributes.item(i).value.length) {
19216 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19219 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19228 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19231 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19236 // Traverse the tree
19238 var currentElementChild = currentElement.childNodes.item(i);
19239 var allText = true;
19240 var innerHTML = '';
19242 while (currentElementChild) {
19243 // Formatting code (indent the tree so it looks nice on the screen)
19244 var nopad = nopadtext;
19245 if (lastnode == 'SPAN') {
19249 if (currentElementChild.nodeName == '#text') {
19250 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19251 toadd = nopadtext ? toadd : toadd.trim();
19252 if (!nopad && toadd.length > 80) {
19253 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19255 innerHTML += toadd;
19258 currentElementChild = currentElement.childNodes.item(i);
19264 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19266 // Recursively traverse the tree structure of the child node
19267 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19268 lastnode = currentElementChild.nodeName;
19270 currentElementChild=currentElement.childNodes.item(i);
19276 // The remaining code is mostly for formatting the tree
19277 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19282 ret+= "</"+tagName+">";
19288 applyBlacklists : function()
19290 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19291 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19295 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19296 if (b.indexOf(tag) > -1) {
19299 this.white.push(tag);
19303 Roo.each(w, function(tag) {
19304 if (b.indexOf(tag) > -1) {
19307 if (this.white.indexOf(tag) > -1) {
19310 this.white.push(tag);
19315 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19316 if (w.indexOf(tag) > -1) {
19319 this.black.push(tag);
19323 Roo.each(b, function(tag) {
19324 if (w.indexOf(tag) > -1) {
19327 if (this.black.indexOf(tag) > -1) {
19330 this.black.push(tag);
19335 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19336 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19340 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19341 if (b.indexOf(tag) > -1) {
19344 this.cwhite.push(tag);
19348 Roo.each(w, function(tag) {
19349 if (b.indexOf(tag) > -1) {
19352 if (this.cwhite.indexOf(tag) > -1) {
19355 this.cwhite.push(tag);
19360 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19361 if (w.indexOf(tag) > -1) {
19364 this.cblack.push(tag);
19368 Roo.each(b, function(tag) {
19369 if (w.indexOf(tag) > -1) {
19372 if (this.cblack.indexOf(tag) > -1) {
19375 this.cblack.push(tag);
19380 setStylesheets : function(stylesheets)
19382 if(typeof(stylesheets) == 'string'){
19383 Roo.get(this.iframe.contentDocument.head).createChild({
19385 rel : 'stylesheet',
19394 Roo.each(stylesheets, function(s) {
19399 Roo.get(_this.iframe.contentDocument.head).createChild({
19401 rel : 'stylesheet',
19410 removeStylesheets : function()
19414 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19419 // hide stuff that is not compatible
19433 * @event specialkey
19437 * @cfg {String} fieldClass @hide
19440 * @cfg {String} focusClass @hide
19443 * @cfg {String} autoCreate @hide
19446 * @cfg {String} inputType @hide
19449 * @cfg {String} invalidClass @hide
19452 * @cfg {String} invalidText @hide
19455 * @cfg {String} msgFx @hide
19458 * @cfg {String} validateOnBlur @hide
19462 Roo.HtmlEditorCore.white = [
19463 'area', 'br', 'img', 'input', 'hr', 'wbr',
19465 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19466 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19467 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19468 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19469 'table', 'ul', 'xmp',
19471 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19474 'dir', 'menu', 'ol', 'ul', 'dl',
19480 Roo.HtmlEditorCore.black = [
19481 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19483 'base', 'basefont', 'bgsound', 'blink', 'body',
19484 'frame', 'frameset', 'head', 'html', 'ilayer',
19485 'iframe', 'layer', 'link', 'meta', 'object',
19486 'script', 'style' ,'title', 'xml' // clean later..
19488 Roo.HtmlEditorCore.clean = [
19489 'script', 'style', 'title', 'xml'
19491 Roo.HtmlEditorCore.remove = [
19496 Roo.HtmlEditorCore.ablack = [
19500 Roo.HtmlEditorCore.aclean = [
19501 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19505 Roo.HtmlEditorCore.pwhite= [
19506 'http', 'https', 'mailto'
19509 // white listed style attributes.
19510 Roo.HtmlEditorCore.cwhite= [
19511 // 'text-align', /// default is to allow most things..
19517 // black listed style attributes.
19518 Roo.HtmlEditorCore.cblack= [
19519 // 'font-size' -- this can be set by the project
19523 Roo.HtmlEditorCore.swapCodes =[
19542 * @class Roo.bootstrap.HtmlEditor
19543 * @extends Roo.bootstrap.TextArea
19544 * Bootstrap HtmlEditor class
19547 * Create a new HtmlEditor
19548 * @param {Object} config The config object
19551 Roo.bootstrap.HtmlEditor = function(config){
19552 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19553 if (!this.toolbars) {
19554 this.toolbars = [];
19556 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19559 * @event initialize
19560 * Fires when the editor is fully initialized (including the iframe)
19561 * @param {HtmlEditor} this
19566 * Fires when the editor is first receives the focus. Any insertion must wait
19567 * until after this event.
19568 * @param {HtmlEditor} this
19572 * @event beforesync
19573 * Fires before the textarea is updated with content from the editor iframe. Return false
19574 * to cancel the sync.
19575 * @param {HtmlEditor} this
19576 * @param {String} html
19580 * @event beforepush
19581 * Fires before the iframe editor is updated with content from the textarea. Return false
19582 * to cancel the push.
19583 * @param {HtmlEditor} this
19584 * @param {String} html
19589 * Fires when the textarea is updated with content from the editor iframe.
19590 * @param {HtmlEditor} this
19591 * @param {String} html
19596 * Fires when the iframe editor is updated with content from the textarea.
19597 * @param {HtmlEditor} this
19598 * @param {String} html
19602 * @event editmodechange
19603 * Fires when the editor switches edit modes
19604 * @param {HtmlEditor} this
19605 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19607 editmodechange: true,
19609 * @event editorevent
19610 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19611 * @param {HtmlEditor} this
19615 * @event firstfocus
19616 * Fires when on first focus - needed by toolbars..
19617 * @param {HtmlEditor} this
19622 * Auto save the htmlEditor value as a file into Events
19623 * @param {HtmlEditor} this
19627 * @event savedpreview
19628 * preview the saved version of htmlEditor
19629 * @param {HtmlEditor} this
19636 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19640 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19645 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19650 * @cfg {Number} height (in pixels)
19654 * @cfg {Number} width (in pixels)
19659 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19662 stylesheets: false,
19667 // private properties
19668 validationEvent : false,
19670 initialized : false,
19673 onFocus : Roo.emptyFn,
19675 hideMode:'offsets',
19678 tbContainer : false,
19680 toolbarContainer :function() {
19681 return this.wrap.select('.x-html-editor-tb',true).first();
19685 * Protected method that will not generally be called directly. It
19686 * is called when the editor creates its toolbar. Override this method if you need to
19687 * add custom toolbar buttons.
19688 * @param {HtmlEditor} editor
19690 createToolbar : function(){
19692 Roo.log("create toolbars");
19694 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19695 this.toolbars[0].render(this.toolbarContainer());
19699 // if (!editor.toolbars || !editor.toolbars.length) {
19700 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19703 // for (var i =0 ; i < editor.toolbars.length;i++) {
19704 // editor.toolbars[i] = Roo.factory(
19705 // typeof(editor.toolbars[i]) == 'string' ?
19706 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19707 // Roo.bootstrap.HtmlEditor);
19708 // editor.toolbars[i].init(editor);
19714 onRender : function(ct, position)
19716 // Roo.log("Call onRender: " + this.xtype);
19718 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19720 this.wrap = this.inputEl().wrap({
19721 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19724 this.editorcore.onRender(ct, position);
19726 if (this.resizable) {
19727 this.resizeEl = new Roo.Resizable(this.wrap, {
19731 minHeight : this.height,
19732 height: this.height,
19733 handles : this.resizable,
19736 resize : function(r, w, h) {
19737 _t.onResize(w,h); // -something
19743 this.createToolbar(this);
19746 if(!this.width && this.resizable){
19747 this.setSize(this.wrap.getSize());
19749 if (this.resizeEl) {
19750 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19751 // should trigger onReize..
19757 onResize : function(w, h)
19759 Roo.log('resize: ' +w + ',' + h );
19760 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19764 if(this.inputEl() ){
19765 if(typeof w == 'number'){
19766 var aw = w - this.wrap.getFrameWidth('lr');
19767 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19770 if(typeof h == 'number'){
19771 var tbh = -11; // fixme it needs to tool bar size!
19772 for (var i =0; i < this.toolbars.length;i++) {
19773 // fixme - ask toolbars for heights?
19774 tbh += this.toolbars[i].el.getHeight();
19775 //if (this.toolbars[i].footer) {
19776 // tbh += this.toolbars[i].footer.el.getHeight();
19784 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19785 ah -= 5; // knock a few pixes off for look..
19786 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19790 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19791 this.editorcore.onResize(ew,eh);
19796 * Toggles the editor between standard and source edit mode.
19797 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19799 toggleSourceEdit : function(sourceEditMode)
19801 this.editorcore.toggleSourceEdit(sourceEditMode);
19803 if(this.editorcore.sourceEditMode){
19804 Roo.log('editor - showing textarea');
19807 // Roo.log(this.syncValue());
19809 this.inputEl().removeClass(['hide', 'x-hidden']);
19810 this.inputEl().dom.removeAttribute('tabIndex');
19811 this.inputEl().focus();
19813 Roo.log('editor - hiding textarea');
19815 // Roo.log(this.pushValue());
19818 this.inputEl().addClass(['hide', 'x-hidden']);
19819 this.inputEl().dom.setAttribute('tabIndex', -1);
19820 //this.deferFocus();
19823 if(this.resizable){
19824 this.setSize(this.wrap.getSize());
19827 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19830 // private (for BoxComponent)
19831 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19833 // private (for BoxComponent)
19834 getResizeEl : function(){
19838 // private (for BoxComponent)
19839 getPositionEl : function(){
19844 initEvents : function(){
19845 this.originalValue = this.getValue();
19849 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19852 // markInvalid : Roo.emptyFn,
19854 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19857 // clearInvalid : Roo.emptyFn,
19859 setValue : function(v){
19860 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19861 this.editorcore.pushValue();
19866 deferFocus : function(){
19867 this.focus.defer(10, this);
19871 focus : function(){
19872 this.editorcore.focus();
19878 onDestroy : function(){
19884 for (var i =0; i < this.toolbars.length;i++) {
19885 // fixme - ask toolbars for heights?
19886 this.toolbars[i].onDestroy();
19889 this.wrap.dom.innerHTML = '';
19890 this.wrap.remove();
19895 onFirstFocus : function(){
19896 //Roo.log("onFirstFocus");
19897 this.editorcore.onFirstFocus();
19898 for (var i =0; i < this.toolbars.length;i++) {
19899 this.toolbars[i].onFirstFocus();
19905 syncValue : function()
19907 this.editorcore.syncValue();
19910 pushValue : function()
19912 this.editorcore.pushValue();
19916 // hide stuff that is not compatible
19930 * @event specialkey
19934 * @cfg {String} fieldClass @hide
19937 * @cfg {String} focusClass @hide
19940 * @cfg {String} autoCreate @hide
19943 * @cfg {String} inputType @hide
19946 * @cfg {String} invalidClass @hide
19949 * @cfg {String} invalidText @hide
19952 * @cfg {String} msgFx @hide
19955 * @cfg {String} validateOnBlur @hide
19964 Roo.namespace('Roo.bootstrap.htmleditor');
19966 * @class Roo.bootstrap.HtmlEditorToolbar1
19971 new Roo.bootstrap.HtmlEditor({
19974 new Roo.bootstrap.HtmlEditorToolbar1({
19975 disable : { fonts: 1 , format: 1, ..., ... , ...],
19981 * @cfg {Object} disable List of elements to disable..
19982 * @cfg {Array} btns List of additional buttons.
19986 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19989 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19992 Roo.apply(this, config);
19994 // default disabled, based on 'good practice'..
19995 this.disable = this.disable || {};
19996 Roo.applyIf(this.disable, {
19999 specialElements : true
20001 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
20003 this.editor = config.editor;
20004 this.editorcore = config.editor.editorcore;
20006 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20008 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20009 // dont call parent... till later.
20011 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20016 editorcore : false,
20021 "h1","h2","h3","h4","h5","h6",
20023 "abbr", "acronym", "address", "cite", "samp", "var",
20027 onRender : function(ct, position)
20029 // Roo.log("Call onRender: " + this.xtype);
20031 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20033 this.el.dom.style.marginBottom = '0';
20035 var editorcore = this.editorcore;
20036 var editor= this.editor;
20039 var btn = function(id,cmd , toggle, handler){
20041 var event = toggle ? 'toggle' : 'click';
20046 xns: Roo.bootstrap,
20049 enableToggle:toggle !== false,
20051 pressed : toggle ? false : null,
20054 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20055 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20064 xns: Roo.bootstrap,
20065 glyphicon : 'font',
20069 xns: Roo.bootstrap,
20073 Roo.each(this.formats, function(f) {
20074 style.menu.items.push({
20076 xns: Roo.bootstrap,
20077 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20082 editorcore.insertTag(this.tagname);
20089 children.push(style);
20092 btn('bold',false,true);
20093 btn('italic',false,true);
20094 btn('align-left', 'justifyleft',true);
20095 btn('align-center', 'justifycenter',true);
20096 btn('align-right' , 'justifyright',true);
20097 btn('link', false, false, function(btn) {
20098 //Roo.log("create link?");
20099 var url = prompt(this.createLinkText, this.defaultLinkValue);
20100 if(url && url != 'http:/'+'/'){
20101 this.editorcore.relayCmd('createlink', url);
20104 btn('list','insertunorderedlist',true);
20105 btn('pencil', false,true, function(btn){
20108 this.toggleSourceEdit(btn.pressed);
20114 xns: Roo.bootstrap,
20119 xns: Roo.bootstrap,
20124 cog.menu.items.push({
20126 xns: Roo.bootstrap,
20127 html : Clean styles,
20132 editorcore.insertTag(this.tagname);
20141 this.xtype = 'NavSimplebar';
20143 for(var i=0;i< children.length;i++) {
20145 this.buttons.add(this.addxtypeChild(children[i]));
20149 editor.on('editorevent', this.updateToolbar, this);
20151 onBtnClick : function(id)
20153 this.editorcore.relayCmd(id);
20154 this.editorcore.focus();
20158 * Protected method that will not generally be called directly. It triggers
20159 * a toolbar update by reading the markup state of the current selection in the editor.
20161 updateToolbar: function(){
20163 if(!this.editorcore.activated){
20164 this.editor.onFirstFocus(); // is this neeed?
20168 var btns = this.buttons;
20169 var doc = this.editorcore.doc;
20170 btns.get('bold').setActive(doc.queryCommandState('bold'));
20171 btns.get('italic').setActive(doc.queryCommandState('italic'));
20172 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20174 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20175 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20176 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20178 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20179 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20182 var ans = this.editorcore.getAllAncestors();
20183 if (this.formatCombo) {
20186 var store = this.formatCombo.store;
20187 this.formatCombo.setValue("");
20188 for (var i =0; i < ans.length;i++) {
20189 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20191 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20199 // hides menus... - so this cant be on a menu...
20200 Roo.bootstrap.MenuMgr.hideAll();
20202 Roo.bootstrap.MenuMgr.hideAll();
20203 //this.editorsyncValue();
20205 onFirstFocus: function() {
20206 this.buttons.each(function(item){
20210 toggleSourceEdit : function(sourceEditMode){
20213 if(sourceEditMode){
20214 Roo.log("disabling buttons");
20215 this.buttons.each( function(item){
20216 if(item.cmd != 'pencil'){
20222 Roo.log("enabling buttons");
20223 if(this.editorcore.initialized){
20224 this.buttons.each( function(item){
20230 Roo.log("calling toggole on editor");
20231 // tell the editor that it's been pressed..
20232 this.editor.toggleSourceEdit(sourceEditMode);
20242 * @class Roo.bootstrap.Table.AbstractSelectionModel
20243 * @extends Roo.util.Observable
20244 * Abstract base class for grid SelectionModels. It provides the interface that should be
20245 * implemented by descendant classes. This class should not be directly instantiated.
20248 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20249 this.locked = false;
20250 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20254 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20255 /** @ignore Called by the grid automatically. Do not call directly. */
20256 init : function(grid){
20262 * Locks the selections.
20265 this.locked = true;
20269 * Unlocks the selections.
20271 unlock : function(){
20272 this.locked = false;
20276 * Returns true if the selections are locked.
20277 * @return {Boolean}
20279 isLocked : function(){
20280 return this.locked;
20284 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20285 * @class Roo.bootstrap.Table.RowSelectionModel
20286 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20287 * It supports multiple selections and keyboard selection/navigation.
20289 * @param {Object} config
20292 Roo.bootstrap.Table.RowSelectionModel = function(config){
20293 Roo.apply(this, config);
20294 this.selections = new Roo.util.MixedCollection(false, function(o){
20299 this.lastActive = false;
20303 * @event selectionchange
20304 * Fires when the selection changes
20305 * @param {SelectionModel} this
20307 "selectionchange" : true,
20309 * @event afterselectionchange
20310 * Fires after the selection changes (eg. by key press or clicking)
20311 * @param {SelectionModel} this
20313 "afterselectionchange" : true,
20315 * @event beforerowselect
20316 * Fires when a row is selected being selected, return false to cancel.
20317 * @param {SelectionModel} this
20318 * @param {Number} rowIndex The selected index
20319 * @param {Boolean} keepExisting False if other selections will be cleared
20321 "beforerowselect" : true,
20324 * Fires when a row is selected.
20325 * @param {SelectionModel} this
20326 * @param {Number} rowIndex The selected index
20327 * @param {Roo.data.Record} r The record
20329 "rowselect" : true,
20331 * @event rowdeselect
20332 * Fires when a row is deselected.
20333 * @param {SelectionModel} this
20334 * @param {Number} rowIndex The selected index
20336 "rowdeselect" : true
20338 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20339 this.locked = false;
20342 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20344 * @cfg {Boolean} singleSelect
20345 * True to allow selection of only one row at a time (defaults to false)
20347 singleSelect : false,
20350 initEvents : function(){
20352 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20353 this.grid.on("mousedown", this.handleMouseDown, this);
20354 }else{ // allow click to work like normal
20355 this.grid.on("rowclick", this.handleDragableRowClick, this);
20358 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20359 "up" : function(e){
20361 this.selectPrevious(e.shiftKey);
20362 }else if(this.last !== false && this.lastActive !== false){
20363 var last = this.last;
20364 this.selectRange(this.last, this.lastActive-1);
20365 this.grid.getView().focusRow(this.lastActive);
20366 if(last !== false){
20370 this.selectFirstRow();
20372 this.fireEvent("afterselectionchange", this);
20374 "down" : function(e){
20376 this.selectNext(e.shiftKey);
20377 }else if(this.last !== false && this.lastActive !== false){
20378 var last = this.last;
20379 this.selectRange(this.last, this.lastActive+1);
20380 this.grid.getView().focusRow(this.lastActive);
20381 if(last !== false){
20385 this.selectFirstRow();
20387 this.fireEvent("afterselectionchange", this);
20392 var view = this.grid.view;
20393 view.on("refresh", this.onRefresh, this);
20394 view.on("rowupdated", this.onRowUpdated, this);
20395 view.on("rowremoved", this.onRemove, this);
20399 onRefresh : function(){
20400 var ds = this.grid.dataSource, i, v = this.grid.view;
20401 var s = this.selections;
20402 s.each(function(r){
20403 if((i = ds.indexOfId(r.id)) != -1){
20412 onRemove : function(v, index, r){
20413 this.selections.remove(r);
20417 onRowUpdated : function(v, index, r){
20418 if(this.isSelected(r)){
20419 v.onRowSelect(index);
20425 * @param {Array} records The records to select
20426 * @param {Boolean} keepExisting (optional) True to keep existing selections
20428 selectRecords : function(records, keepExisting){
20430 this.clearSelections();
20432 var ds = this.grid.dataSource;
20433 for(var i = 0, len = records.length; i < len; i++){
20434 this.selectRow(ds.indexOf(records[i]), true);
20439 * Gets the number of selected rows.
20442 getCount : function(){
20443 return this.selections.length;
20447 * Selects the first row in the grid.
20449 selectFirstRow : function(){
20454 * Select the last row.
20455 * @param {Boolean} keepExisting (optional) True to keep existing selections
20457 selectLastRow : function(keepExisting){
20458 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20462 * Selects the row immediately following the last selected row.
20463 * @param {Boolean} keepExisting (optional) True to keep existing selections
20465 selectNext : function(keepExisting){
20466 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20467 this.selectRow(this.last+1, keepExisting);
20468 this.grid.getView().focusRow(this.last);
20473 * Selects the row that precedes the last selected row.
20474 * @param {Boolean} keepExisting (optional) True to keep existing selections
20476 selectPrevious : function(keepExisting){
20478 this.selectRow(this.last-1, keepExisting);
20479 this.grid.getView().focusRow(this.last);
20484 * Returns the selected records
20485 * @return {Array} Array of selected records
20487 getSelections : function(){
20488 return [].concat(this.selections.items);
20492 * Returns the first selected record.
20495 getSelected : function(){
20496 return this.selections.itemAt(0);
20501 * Clears all selections.
20503 clearSelections : function(fast){
20504 if(this.locked) return;
20506 var ds = this.grid.dataSource;
20507 var s = this.selections;
20508 s.each(function(r){
20509 this.deselectRow(ds.indexOfId(r.id));
20513 this.selections.clear();
20520 * Selects all rows.
20522 selectAll : function(){
20523 if(this.locked) return;
20524 this.selections.clear();
20525 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20526 this.selectRow(i, true);
20531 * Returns True if there is a selection.
20532 * @return {Boolean}
20534 hasSelection : function(){
20535 return this.selections.length > 0;
20539 * Returns True if the specified row is selected.
20540 * @param {Number/Record} record The record or index of the record to check
20541 * @return {Boolean}
20543 isSelected : function(index){
20544 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20545 return (r && this.selections.key(r.id) ? true : false);
20549 * Returns True if the specified record id is selected.
20550 * @param {String} id The id of record to check
20551 * @return {Boolean}
20553 isIdSelected : function(id){
20554 return (this.selections.key(id) ? true : false);
20558 handleMouseDown : function(e, t){
20559 var view = this.grid.getView(), rowIndex;
20560 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20563 if(e.shiftKey && this.last !== false){
20564 var last = this.last;
20565 this.selectRange(last, rowIndex, e.ctrlKey);
20566 this.last = last; // reset the last
20567 view.focusRow(rowIndex);
20569 var isSelected = this.isSelected(rowIndex);
20570 if(e.button !== 0 && isSelected){
20571 view.focusRow(rowIndex);
20572 }else if(e.ctrlKey && isSelected){
20573 this.deselectRow(rowIndex);
20574 }else if(!isSelected){
20575 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20576 view.focusRow(rowIndex);
20579 this.fireEvent("afterselectionchange", this);
20582 handleDragableRowClick : function(grid, rowIndex, e)
20584 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20585 this.selectRow(rowIndex, false);
20586 grid.view.focusRow(rowIndex);
20587 this.fireEvent("afterselectionchange", this);
20592 * Selects multiple rows.
20593 * @param {Array} rows Array of the indexes of the row to select
20594 * @param {Boolean} keepExisting (optional) True to keep existing selections
20596 selectRows : function(rows, keepExisting){
20598 this.clearSelections();
20600 for(var i = 0, len = rows.length; i < len; i++){
20601 this.selectRow(rows[i], true);
20606 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20607 * @param {Number} startRow The index of the first row in the range
20608 * @param {Number} endRow The index of the last row in the range
20609 * @param {Boolean} keepExisting (optional) True to retain existing selections
20611 selectRange : function(startRow, endRow, keepExisting){
20612 if(this.locked) return;
20614 this.clearSelections();
20616 if(startRow <= endRow){
20617 for(var i = startRow; i <= endRow; i++){
20618 this.selectRow(i, true);
20621 for(var i = startRow; i >= endRow; i--){
20622 this.selectRow(i, true);
20628 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20629 * @param {Number} startRow The index of the first row in the range
20630 * @param {Number} endRow The index of the last row in the range
20632 deselectRange : function(startRow, endRow, preventViewNotify){
20633 if(this.locked) return;
20634 for(var i = startRow; i <= endRow; i++){
20635 this.deselectRow(i, preventViewNotify);
20641 * @param {Number} row The index of the row to select
20642 * @param {Boolean} keepExisting (optional) True to keep existing selections
20644 selectRow : function(index, keepExisting, preventViewNotify){
20645 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20646 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20647 if(!keepExisting || this.singleSelect){
20648 this.clearSelections();
20650 var r = this.grid.dataSource.getAt(index);
20651 this.selections.add(r);
20652 this.last = this.lastActive = index;
20653 if(!preventViewNotify){
20654 this.grid.getView().onRowSelect(index);
20656 this.fireEvent("rowselect", this, index, r);
20657 this.fireEvent("selectionchange", this);
20663 * @param {Number} row The index of the row to deselect
20665 deselectRow : function(index, preventViewNotify){
20666 if(this.locked) return;
20667 if(this.last == index){
20670 if(this.lastActive == index){
20671 this.lastActive = false;
20673 var r = this.grid.dataSource.getAt(index);
20674 this.selections.remove(r);
20675 if(!preventViewNotify){
20676 this.grid.getView().onRowDeselect(index);
20678 this.fireEvent("rowdeselect", this, index);
20679 this.fireEvent("selectionchange", this);
20683 restoreLast : function(){
20685 this.last = this._last;
20690 acceptsNav : function(row, col, cm){
20691 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20695 onEditorKey : function(field, e){
20696 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20701 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20703 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20705 }else if(k == e.ENTER && !e.ctrlKey){
20709 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20711 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20713 }else if(k == e.ESC){
20717 g.startEditing(newCell[0], newCell[1]);
20722 * Ext JS Library 1.1.1
20723 * Copyright(c) 2006-2007, Ext JS, LLC.
20725 * Originally Released Under LGPL - original licence link has changed is not relivant.
20728 * <script type="text/javascript">
20732 * @class Roo.bootstrap.PagingToolbar
20734 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20736 * Create a new PagingToolbar
20737 * @param {Object} config The config object
20739 Roo.bootstrap.PagingToolbar = function(config)
20741 // old args format still supported... - xtype is prefered..
20742 // created from xtype...
20743 var ds = config.dataSource;
20744 this.toolbarItems = [];
20745 if (config.items) {
20746 this.toolbarItems = config.items;
20747 // config.items = [];
20750 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20757 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20761 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20763 * @cfg {Roo.data.Store} dataSource
20764 * The underlying data store providing the paged data
20767 * @cfg {String/HTMLElement/Element} container
20768 * container The id or element that will contain the toolbar
20771 * @cfg {Boolean} displayInfo
20772 * True to display the displayMsg (defaults to false)
20775 * @cfg {Number} pageSize
20776 * The number of records to display per page (defaults to 20)
20780 * @cfg {String} displayMsg
20781 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20783 displayMsg : 'Displaying {0} - {1} of {2}',
20785 * @cfg {String} emptyMsg
20786 * The message to display when no records are found (defaults to "No data to display")
20788 emptyMsg : 'No data to display',
20790 * Customizable piece of the default paging text (defaults to "Page")
20793 beforePageText : "Page",
20795 * Customizable piece of the default paging text (defaults to "of %0")
20798 afterPageText : "of {0}",
20800 * Customizable piece of the default paging text (defaults to "First Page")
20803 firstText : "First Page",
20805 * Customizable piece of the default paging text (defaults to "Previous Page")
20808 prevText : "Previous Page",
20810 * Customizable piece of the default paging text (defaults to "Next Page")
20813 nextText : "Next Page",
20815 * Customizable piece of the default paging text (defaults to "Last Page")
20818 lastText : "Last Page",
20820 * Customizable piece of the default paging text (defaults to "Refresh")
20823 refreshText : "Refresh",
20827 onRender : function(ct, position)
20829 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20830 this.navgroup.parentId = this.id;
20831 this.navgroup.onRender(this.el, null);
20832 // add the buttons to the navgroup
20834 if(this.displayInfo){
20835 Roo.log(this.el.select('ul.navbar-nav',true).first());
20836 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20837 this.displayEl = this.el.select('.x-paging-info', true).first();
20838 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20839 // this.displayEl = navel.el.select('span',true).first();
20845 Roo.each(_this.buttons, function(e){
20846 Roo.factory(e).onRender(_this.el, null);
20850 Roo.each(_this.toolbarItems, function(e) {
20851 _this.navgroup.addItem(e);
20855 this.first = this.navgroup.addItem({
20856 tooltip: this.firstText,
20858 icon : 'fa fa-backward',
20860 preventDefault: true,
20861 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20864 this.prev = this.navgroup.addItem({
20865 tooltip: this.prevText,
20867 icon : 'fa fa-step-backward',
20869 preventDefault: true,
20870 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20872 //this.addSeparator();
20875 var field = this.navgroup.addItem( {
20877 cls : 'x-paging-position',
20879 html : this.beforePageText +
20880 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20881 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20884 this.field = field.el.select('input', true).first();
20885 this.field.on("keydown", this.onPagingKeydown, this);
20886 this.field.on("focus", function(){this.dom.select();});
20889 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20890 //this.field.setHeight(18);
20891 //this.addSeparator();
20892 this.next = this.navgroup.addItem({
20893 tooltip: this.nextText,
20895 html : ' <i class="fa fa-step-forward">',
20897 preventDefault: true,
20898 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20900 this.last = this.navgroup.addItem({
20901 tooltip: this.lastText,
20902 icon : 'fa fa-forward',
20905 preventDefault: true,
20906 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20908 //this.addSeparator();
20909 this.loading = this.navgroup.addItem({
20910 tooltip: this.refreshText,
20911 icon: 'fa fa-refresh',
20912 preventDefault: true,
20913 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20919 updateInfo : function(){
20920 if(this.displayEl){
20921 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20922 var msg = count == 0 ?
20926 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20928 this.displayEl.update(msg);
20933 onLoad : function(ds, r, o){
20934 this.cursor = o.params ? o.params.start : 0;
20935 var d = this.getPageData(),
20939 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20940 this.field.dom.value = ap;
20941 this.first.setDisabled(ap == 1);
20942 this.prev.setDisabled(ap == 1);
20943 this.next.setDisabled(ap == ps);
20944 this.last.setDisabled(ap == ps);
20945 this.loading.enable();
20950 getPageData : function(){
20951 var total = this.ds.getTotalCount();
20954 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20955 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20960 onLoadError : function(){
20961 this.loading.enable();
20965 onPagingKeydown : function(e){
20966 var k = e.getKey();
20967 var d = this.getPageData();
20969 var v = this.field.dom.value, pageNum;
20970 if(!v || isNaN(pageNum = parseInt(v, 10))){
20971 this.field.dom.value = d.activePage;
20974 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20975 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20978 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))
20980 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20981 this.field.dom.value = pageNum;
20982 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20985 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20987 var v = this.field.dom.value, pageNum;
20988 var increment = (e.shiftKey) ? 10 : 1;
20989 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20991 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20992 this.field.dom.value = d.activePage;
20995 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20997 this.field.dom.value = parseInt(v, 10) + increment;
20998 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20999 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21006 beforeLoad : function(){
21008 this.loading.disable();
21013 onClick : function(which){
21022 ds.load({params:{start: 0, limit: this.pageSize}});
21025 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21028 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21031 var total = ds.getTotalCount();
21032 var extra = total % this.pageSize;
21033 var lastStart = extra ? (total - extra) : total-this.pageSize;
21034 ds.load({params:{start: lastStart, limit: this.pageSize}});
21037 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21043 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21044 * @param {Roo.data.Store} store The data store to unbind
21046 unbind : function(ds){
21047 ds.un("beforeload", this.beforeLoad, this);
21048 ds.un("load", this.onLoad, this);
21049 ds.un("loadexception", this.onLoadError, this);
21050 ds.un("remove", this.updateInfo, this);
21051 ds.un("add", this.updateInfo, this);
21052 this.ds = undefined;
21056 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21057 * @param {Roo.data.Store} store The data store to bind
21059 bind : function(ds){
21060 ds.on("beforeload", this.beforeLoad, this);
21061 ds.on("load", this.onLoad, this);
21062 ds.on("loadexception", this.onLoadError, this);
21063 ds.on("remove", this.updateInfo, this);
21064 ds.on("add", this.updateInfo, this);
21075 * @class Roo.bootstrap.MessageBar
21076 * @extends Roo.bootstrap.Component
21077 * Bootstrap MessageBar class
21078 * @cfg {String} html contents of the MessageBar
21079 * @cfg {String} weight (info | success | warning | danger) default info
21080 * @cfg {String} beforeClass insert the bar before the given class
21081 * @cfg {Boolean} closable (true | false) default false
21082 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21085 * Create a new Element
21086 * @param {Object} config The config object
21089 Roo.bootstrap.MessageBar = function(config){
21090 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21093 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21099 beforeClass: 'bootstrap-sticky-wrap',
21101 getAutoCreate : function(){
21105 cls: 'alert alert-dismissable alert-' + this.weight,
21110 html: this.html || ''
21116 cfg.cls += ' alert-messages-fixed';
21130 onRender : function(ct, position)
21132 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21135 var cfg = Roo.apply({}, this.getAutoCreate());
21139 cfg.cls += ' ' + this.cls;
21142 cfg.style = this.style;
21144 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21146 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21149 this.el.select('>button.close').on('click', this.hide, this);
21155 if (!this.rendered) {
21161 this.fireEvent('show', this);
21167 if (!this.rendered) {
21173 this.fireEvent('hide', this);
21176 update : function()
21178 // var e = this.el.dom.firstChild;
21180 // if(this.closable){
21181 // e = e.nextSibling;
21184 // e.data = this.html || '';
21186 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21202 * @class Roo.bootstrap.Graph
21203 * @extends Roo.bootstrap.Component
21204 * Bootstrap Graph class
21208 @cfg {String} graphtype bar | vbar | pie
21209 @cfg {number} g_x coodinator | centre x (pie)
21210 @cfg {number} g_y coodinator | centre y (pie)
21211 @cfg {number} g_r radius (pie)
21212 @cfg {number} g_height height of the chart (respected by all elements in the set)
21213 @cfg {number} g_width width of the chart (respected by all elements in the set)
21214 @cfg {Object} title The title of the chart
21217 -opts (object) options for the chart
21219 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21220 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21222 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.
21223 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21225 o stretch (boolean)
21227 -opts (object) options for the pie
21230 o startAngle (number)
21231 o endAngle (number)
21235 * Create a new Input
21236 * @param {Object} config The config object
21239 Roo.bootstrap.Graph = function(config){
21240 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21246 * The img click event for the img.
21247 * @param {Roo.EventObject} e
21253 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21264 //g_colors: this.colors,
21271 getAutoCreate : function(){
21282 onRender : function(ct,position){
21283 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21284 this.raphael = Raphael(this.el.dom);
21286 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21287 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21288 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21289 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21291 r.text(160, 10, "Single Series Chart").attr(txtattr);
21292 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21293 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21294 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21296 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21297 r.barchart(330, 10, 300, 220, data1);
21298 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21299 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21302 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21303 // r.barchart(30, 30, 560, 250, xdata, {
21304 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21305 // axis : "0 0 1 1",
21306 // axisxlabels : xdata
21307 // //yvalues : cols,
21310 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21312 // this.load(null,xdata,{
21313 // axis : "0 0 1 1",
21314 // axisxlabels : xdata
21319 load : function(graphtype,xdata,opts){
21320 this.raphael.clear();
21322 graphtype = this.graphtype;
21327 var r = this.raphael,
21328 fin = function () {
21329 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21331 fout = function () {
21332 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21334 pfin = function() {
21335 this.sector.stop();
21336 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21339 this.label[0].stop();
21340 this.label[0].attr({ r: 7.5 });
21341 this.label[1].attr({ "font-weight": 800 });
21344 pfout = function() {
21345 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21348 this.label[0].animate({ r: 5 }, 500, "bounce");
21349 this.label[1].attr({ "font-weight": 400 });
21355 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21358 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21361 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21362 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21364 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21371 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21376 setTitle: function(o)
21381 initEvents: function() {
21384 this.el.on('click', this.onClick, this);
21388 onClick : function(e)
21390 Roo.log('img onclick');
21391 this.fireEvent('click', this, e);
21403 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21406 * @class Roo.bootstrap.dash.NumberBox
21407 * @extends Roo.bootstrap.Component
21408 * Bootstrap NumberBox class
21409 * @cfg {String} headline Box headline
21410 * @cfg {String} content Box content
21411 * @cfg {String} icon Box icon
21412 * @cfg {String} footer Footer text
21413 * @cfg {String} fhref Footer href
21416 * Create a new NumberBox
21417 * @param {Object} config The config object
21421 Roo.bootstrap.dash.NumberBox = function(config){
21422 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21426 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21435 getAutoCreate : function(){
21439 cls : 'small-box ',
21447 cls : 'roo-headline',
21448 html : this.headline
21452 cls : 'roo-content',
21453 html : this.content
21467 cls : 'ion ' + this.icon
21476 cls : 'small-box-footer',
21477 href : this.fhref || '#',
21481 cfg.cn.push(footer);
21488 onRender : function(ct,position){
21489 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21496 setHeadline: function (value)
21498 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21501 setFooter: function (value, href)
21503 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21506 this.el.select('a.small-box-footer',true).first().attr('href', href);
21511 setContent: function (value)
21513 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21516 initEvents: function()
21530 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21533 * @class Roo.bootstrap.dash.TabBox
21534 * @extends Roo.bootstrap.Component
21535 * Bootstrap TabBox class
21536 * @cfg {String} title Title of the TabBox
21537 * @cfg {String} icon Icon of the TabBox
21538 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21539 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21542 * Create a new TabBox
21543 * @param {Object} config The config object
21547 Roo.bootstrap.dash.TabBox = function(config){
21548 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21553 * When a pane is added
21554 * @param {Roo.bootstrap.dash.TabPane} pane
21558 * @event activatepane
21559 * When a pane is activated
21560 * @param {Roo.bootstrap.dash.TabPane} pane
21562 "activatepane" : true
21570 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21575 tabScrollable : false,
21577 getChildContainer : function()
21579 return this.el.select('.tab-content', true).first();
21582 getAutoCreate : function(){
21586 cls: 'pull-left header',
21594 cls: 'fa ' + this.icon
21600 cls: 'nav nav-tabs pull-right',
21606 if(this.tabScrollable){
21613 cls: 'nav nav-tabs pull-right',
21624 cls: 'nav-tabs-custom',
21629 cls: 'tab-content no-padding',
21637 initEvents : function()
21639 //Roo.log('add add pane handler');
21640 this.on('addpane', this.onAddPane, this);
21643 * Updates the box title
21644 * @param {String} html to set the title to.
21646 setTitle : function(value)
21648 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21650 onAddPane : function(pane)
21652 this.panes.push(pane);
21653 //Roo.log('addpane');
21655 // tabs are rendere left to right..
21656 if(!this.showtabs){
21660 var ctr = this.el.select('.nav-tabs', true).first();
21663 var existing = ctr.select('.nav-tab',true);
21664 var qty = existing.getCount();;
21667 var tab = ctr.createChild({
21669 cls : 'nav-tab' + (qty ? '' : ' active'),
21677 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21680 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21682 pane.el.addClass('active');
21687 onTabClick : function(ev,un,ob,pane)
21689 //Roo.log('tab - prev default');
21690 ev.preventDefault();
21693 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21694 pane.tab.addClass('active');
21695 //Roo.log(pane.title);
21696 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21697 // technically we should have a deactivate event.. but maybe add later.
21698 // and it should not de-activate the selected tab...
21699 this.fireEvent('activatepane', pane);
21700 pane.el.addClass('active');
21701 pane.fireEvent('activate');
21706 getActivePane : function()
21709 Roo.each(this.panes, function(p) {
21710 if(p.el.hasClass('active')){
21731 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21733 * @class Roo.bootstrap.TabPane
21734 * @extends Roo.bootstrap.Component
21735 * Bootstrap TabPane class
21736 * @cfg {Boolean} active (false | true) Default false
21737 * @cfg {String} title title of panel
21741 * Create a new TabPane
21742 * @param {Object} config The config object
21745 Roo.bootstrap.dash.TabPane = function(config){
21746 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21752 * When a pane is activated
21753 * @param {Roo.bootstrap.dash.TabPane} pane
21760 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21765 // the tabBox that this is attached to.
21768 getAutoCreate : function()
21776 cfg.cls += ' active';
21781 initEvents : function()
21783 //Roo.log('trigger add pane handler');
21784 this.parent().fireEvent('addpane', this)
21788 * Updates the tab title
21789 * @param {String} html to set the title to.
21791 setTitle: function(str)
21797 this.tab.select('a', true).first().dom.innerHTML = str;
21814 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21817 * @class Roo.bootstrap.menu.Menu
21818 * @extends Roo.bootstrap.Component
21819 * Bootstrap Menu class - container for Menu
21820 * @cfg {String} html Text of the menu
21821 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21822 * @cfg {String} icon Font awesome icon
21823 * @cfg {String} pos Menu align to (top | bottom) default bottom
21827 * Create a new Menu
21828 * @param {Object} config The config object
21832 Roo.bootstrap.menu.Menu = function(config){
21833 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21837 * @event beforeshow
21838 * Fires before this menu is displayed
21839 * @param {Roo.bootstrap.menu.Menu} this
21843 * @event beforehide
21844 * Fires before this menu is hidden
21845 * @param {Roo.bootstrap.menu.Menu} this
21850 * Fires after this menu is displayed
21851 * @param {Roo.bootstrap.menu.Menu} this
21856 * Fires after this menu is hidden
21857 * @param {Roo.bootstrap.menu.Menu} this
21862 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21863 * @param {Roo.bootstrap.menu.Menu} this
21864 * @param {Roo.EventObject} e
21871 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21875 weight : 'default',
21880 getChildContainer : function() {
21881 if(this.isSubMenu){
21885 return this.el.select('ul.dropdown-menu', true).first();
21888 getAutoCreate : function()
21893 cls : 'roo-menu-text',
21901 cls : 'fa ' + this.icon
21912 cls : 'dropdown-button btn btn-' + this.weight,
21917 cls : 'dropdown-toggle btn btn-' + this.weight,
21927 cls : 'dropdown-menu'
21933 if(this.pos == 'top'){
21934 cfg.cls += ' dropup';
21937 if(this.isSubMenu){
21940 cls : 'dropdown-menu'
21947 onRender : function(ct, position)
21949 this.isSubMenu = ct.hasClass('dropdown-submenu');
21951 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21954 initEvents : function()
21956 if(this.isSubMenu){
21960 this.hidden = true;
21962 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21963 this.triggerEl.on('click', this.onTriggerPress, this);
21965 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21966 this.buttonEl.on('click', this.onClick, this);
21972 if(this.isSubMenu){
21976 return this.el.select('ul.dropdown-menu', true).first();
21979 onClick : function(e)
21981 this.fireEvent("click", this, e);
21984 onTriggerPress : function(e)
21986 if (this.isVisible()) {
21993 isVisible : function(){
21994 return !this.hidden;
21999 this.fireEvent("beforeshow", this);
22001 this.hidden = false;
22002 this.el.addClass('open');
22004 Roo.get(document).on("mouseup", this.onMouseUp, this);
22006 this.fireEvent("show", this);
22013 this.fireEvent("beforehide", this);
22015 this.hidden = true;
22016 this.el.removeClass('open');
22018 Roo.get(document).un("mouseup", this.onMouseUp);
22020 this.fireEvent("hide", this);
22023 onMouseUp : function()
22037 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22040 * @class Roo.bootstrap.menu.Item
22041 * @extends Roo.bootstrap.Component
22042 * Bootstrap MenuItem class
22043 * @cfg {Boolean} submenu (true | false) default false
22044 * @cfg {String} html text of the item
22045 * @cfg {String} href the link
22046 * @cfg {Boolean} disable (true | false) default false
22047 * @cfg {Boolean} preventDefault (true | false) default true
22048 * @cfg {String} icon Font awesome icon
22049 * @cfg {String} pos Submenu align to (left | right) default right
22053 * Create a new Item
22054 * @param {Object} config The config object
22058 Roo.bootstrap.menu.Item = function(config){
22059 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22063 * Fires when the mouse is hovering over this menu
22064 * @param {Roo.bootstrap.menu.Item} this
22065 * @param {Roo.EventObject} e
22070 * Fires when the mouse exits this menu
22071 * @param {Roo.bootstrap.menu.Item} this
22072 * @param {Roo.EventObject} e
22078 * The raw click event for the entire grid.
22079 * @param {Roo.EventObject} e
22085 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22090 preventDefault: true,
22095 getAutoCreate : function()
22100 cls : 'roo-menu-item-text',
22108 cls : 'fa ' + this.icon
22117 href : this.href || '#',
22124 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22128 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22130 if(this.pos == 'left'){
22131 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22138 initEvents : function()
22140 this.el.on('mouseover', this.onMouseOver, this);
22141 this.el.on('mouseout', this.onMouseOut, this);
22143 this.el.select('a', true).first().on('click', this.onClick, this);
22147 onClick : function(e)
22149 if(this.preventDefault){
22150 e.preventDefault();
22153 this.fireEvent("click", this, e);
22156 onMouseOver : function(e)
22158 if(this.submenu && this.pos == 'left'){
22159 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
22162 this.fireEvent("mouseover", this, e);
22165 onMouseOut : function(e)
22167 this.fireEvent("mouseout", this, e);
22179 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22182 * @class Roo.bootstrap.menu.Separator
22183 * @extends Roo.bootstrap.Component
22184 * Bootstrap Separator class
22187 * Create a new Separator
22188 * @param {Object} config The config object
22192 Roo.bootstrap.menu.Separator = function(config){
22193 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22196 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22198 getAutoCreate : function(){
22219 * @class Roo.bootstrap.Tooltip
22220 * Bootstrap Tooltip class
22221 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22222 * to determine which dom element triggers the tooltip.
22224 * It needs to add support for additional attributes like tooltip-position
22227 * Create a new Toolti
22228 * @param {Object} config The config object
22231 Roo.bootstrap.Tooltip = function(config){
22232 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22235 Roo.apply(Roo.bootstrap.Tooltip, {
22237 * @function init initialize tooltip monitoring.
22241 currentTip : false,
22242 currentRegion : false,
22248 Roo.get(document).on('mouseover', this.enter ,this);
22249 Roo.get(document).on('mouseout', this.leave, this);
22252 this.currentTip = new Roo.bootstrap.Tooltip();
22255 enter : function(ev)
22257 var dom = ev.getTarget();
22259 //Roo.log(['enter',dom]);
22260 var el = Roo.fly(dom);
22261 if (this.currentEl) {
22263 //Roo.log(this.currentEl);
22264 //Roo.log(this.currentEl.contains(dom));
22265 if (this.currentEl == el) {
22268 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22276 if (this.currentTip.el) {
22277 this.currentTip.el.hide(); // force hiding...
22282 // you can not look for children, as if el is the body.. then everythign is the child..
22283 if (!el.attr('tooltip')) { //
22284 if (!el.select("[tooltip]").elements.length) {
22287 // is the mouse over this child...?
22288 bindEl = el.select("[tooltip]").first();
22289 var xy = ev.getXY();
22290 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22291 //Roo.log("not in region.");
22294 //Roo.log("child element over..");
22297 this.currentEl = bindEl;
22298 this.currentTip.bind(bindEl);
22299 this.currentRegion = Roo.lib.Region.getRegion(dom);
22300 this.currentTip.enter();
22303 leave : function(ev)
22305 var dom = ev.getTarget();
22306 //Roo.log(['leave',dom]);
22307 if (!this.currentEl) {
22312 if (dom != this.currentEl.dom) {
22315 var xy = ev.getXY();
22316 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22319 // only activate leave if mouse cursor is outside... bounding box..
22324 if (this.currentTip) {
22325 this.currentTip.leave();
22327 //Roo.log('clear currentEl');
22328 this.currentEl = false;
22333 'left' : ['r-l', [-2,0], 'right'],
22334 'right' : ['l-r', [2,0], 'left'],
22335 'bottom' : ['t-b', [0,2], 'top'],
22336 'top' : [ 'b-t', [0,-2], 'bottom']
22342 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22347 delay : null, // can be { show : 300 , hide: 500}
22351 hoverState : null, //???
22353 placement : 'bottom',
22355 getAutoCreate : function(){
22362 cls : 'tooltip-arrow'
22365 cls : 'tooltip-inner'
22372 bind : function(el)
22378 enter : function () {
22380 if (this.timeout != null) {
22381 clearTimeout(this.timeout);
22384 this.hoverState = 'in';
22385 //Roo.log("enter - show");
22386 if (!this.delay || !this.delay.show) {
22391 this.timeout = setTimeout(function () {
22392 if (_t.hoverState == 'in') {
22395 }, this.delay.show);
22399 clearTimeout(this.timeout);
22401 this.hoverState = 'out';
22402 if (!this.delay || !this.delay.hide) {
22408 this.timeout = setTimeout(function () {
22409 //Roo.log("leave - timeout");
22411 if (_t.hoverState == 'out') {
22413 Roo.bootstrap.Tooltip.currentEl = false;
22421 this.render(document.body);
22424 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22426 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22428 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22430 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22432 var placement = typeof this.placement == 'function' ?
22433 this.placement.call(this, this.el, on_el) :
22436 var autoToken = /\s?auto?\s?/i;
22437 var autoPlace = autoToken.test(placement);
22439 placement = placement.replace(autoToken, '') || 'top';
22443 //this.el.setXY([0,0]);
22445 //this.el.dom.style.display='block';
22446 this.el.addClass(placement);
22448 //this.el.appendTo(on_el);
22450 var p = this.getPosition();
22451 var box = this.el.getBox();
22456 var align = Roo.bootstrap.Tooltip.alignment[placement];
22457 this.el.alignTo(this.bindEl, align[0],align[1]);
22458 //var arrow = this.el.select('.arrow',true).first();
22459 //arrow.set(align[2],
22461 this.el.addClass('in fade');
22462 this.hoverState = null;
22464 if (this.el.hasClass('fade')) {
22475 //this.el.setXY([0,0]);
22476 this.el.removeClass('in');
22492 * @class Roo.bootstrap.LocationPicker
22493 * @extends Roo.bootstrap.Component
22494 * Bootstrap LocationPicker class
22495 * @cfg {Number} latitude Position when init default 0
22496 * @cfg {Number} longitude Position when init default 0
22497 * @cfg {Number} zoom default 15
22498 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22499 * @cfg {Boolean} mapTypeControl default false
22500 * @cfg {Boolean} disableDoubleClickZoom default false
22501 * @cfg {Boolean} scrollwheel default true
22502 * @cfg {Boolean} streetViewControl default false
22503 * @cfg {Number} radius default 0
22504 * @cfg {String} locationName
22505 * @cfg {Boolean} draggable default true
22506 * @cfg {Boolean} enableAutocomplete default false
22507 * @cfg {Boolean} enableReverseGeocode default true
22508 * @cfg {String} markerTitle
22511 * Create a new LocationPicker
22512 * @param {Object} config The config object
22516 Roo.bootstrap.LocationPicker = function(config){
22518 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22523 * Fires when the picker initialized.
22524 * @param {Roo.bootstrap.LocationPicker} this
22525 * @param {Google Location} location
22529 * @event positionchanged
22530 * Fires when the picker position changed.
22531 * @param {Roo.bootstrap.LocationPicker} this
22532 * @param {Google Location} location
22534 positionchanged : true,
22537 * Fires when the map resize.
22538 * @param {Roo.bootstrap.LocationPicker} this
22543 * Fires when the map show.
22544 * @param {Roo.bootstrap.LocationPicker} this
22549 * Fires when the map hide.
22550 * @param {Roo.bootstrap.LocationPicker} this
22555 * Fires when click the map.
22556 * @param {Roo.bootstrap.LocationPicker} this
22557 * @param {Map event} e
22561 * @event mapRightClick
22562 * Fires when right click the map.
22563 * @param {Roo.bootstrap.LocationPicker} this
22564 * @param {Map event} e
22566 mapRightClick : true,
22568 * @event markerClick
22569 * Fires when click the marker.
22570 * @param {Roo.bootstrap.LocationPicker} this
22571 * @param {Map event} e
22573 markerClick : true,
22575 * @event markerRightClick
22576 * Fires when right click the marker.
22577 * @param {Roo.bootstrap.LocationPicker} this
22578 * @param {Map event} e
22580 markerRightClick : true,
22582 * @event OverlayViewDraw
22583 * Fires when OverlayView Draw
22584 * @param {Roo.bootstrap.LocationPicker} this
22586 OverlayViewDraw : true,
22588 * @event OverlayViewOnAdd
22589 * Fires when OverlayView Draw
22590 * @param {Roo.bootstrap.LocationPicker} this
22592 OverlayViewOnAdd : true,
22594 * @event OverlayViewOnRemove
22595 * Fires when OverlayView Draw
22596 * @param {Roo.bootstrap.LocationPicker} this
22598 OverlayViewOnRemove : true,
22600 * @event OverlayViewShow
22601 * Fires when OverlayView Draw
22602 * @param {Roo.bootstrap.LocationPicker} this
22603 * @param {Pixel} cpx
22605 OverlayViewShow : true,
22607 * @event OverlayViewHide
22608 * Fires when OverlayView Draw
22609 * @param {Roo.bootstrap.LocationPicker} this
22611 OverlayViewHide : true
22616 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22618 gMapContext: false,
22624 mapTypeControl: false,
22625 disableDoubleClickZoom: false,
22627 streetViewControl: false,
22631 enableAutocomplete: false,
22632 enableReverseGeocode: true,
22635 getAutoCreate: function()
22640 cls: 'roo-location-picker'
22646 initEvents: function(ct, position)
22648 if(!this.el.getWidth() || this.isApplied()){
22652 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22657 initial: function()
22659 if(!this.mapTypeId){
22660 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22663 this.gMapContext = this.GMapContext();
22665 this.initOverlayView();
22667 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22671 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22672 _this.setPosition(_this.gMapContext.marker.position);
22675 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22676 _this.fireEvent('mapClick', this, event);
22680 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22681 _this.fireEvent('mapRightClick', this, event);
22685 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22686 _this.fireEvent('markerClick', this, event);
22690 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22691 _this.fireEvent('markerRightClick', this, event);
22695 this.setPosition(this.gMapContext.location);
22697 this.fireEvent('initial', this, this.gMapContext.location);
22700 initOverlayView: function()
22704 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22708 _this.fireEvent('OverlayViewDraw', _this);
22713 _this.fireEvent('OverlayViewOnAdd', _this);
22716 onRemove: function()
22718 _this.fireEvent('OverlayViewOnRemove', _this);
22721 show: function(cpx)
22723 _this.fireEvent('OverlayViewShow', _this, cpx);
22728 _this.fireEvent('OverlayViewHide', _this);
22734 fromLatLngToContainerPixel: function(event)
22736 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22739 isApplied: function()
22741 return this.getGmapContext() == false ? false : true;
22744 getGmapContext: function()
22746 return this.gMapContext
22749 GMapContext: function()
22751 var position = new google.maps.LatLng(this.latitude, this.longitude);
22753 var _map = new google.maps.Map(this.el.dom, {
22756 mapTypeId: this.mapTypeId,
22757 mapTypeControl: this.mapTypeControl,
22758 disableDoubleClickZoom: this.disableDoubleClickZoom,
22759 scrollwheel: this.scrollwheel,
22760 streetViewControl: this.streetViewControl,
22761 locationName: this.locationName,
22762 draggable: this.draggable,
22763 enableAutocomplete: this.enableAutocomplete,
22764 enableReverseGeocode: this.enableReverseGeocode
22767 var _marker = new google.maps.Marker({
22768 position: position,
22770 title: this.markerTitle,
22771 draggable: this.draggable
22778 location: position,
22779 radius: this.radius,
22780 locationName: this.locationName,
22781 addressComponents: {
22782 formatted_address: null,
22783 addressLine1: null,
22784 addressLine2: null,
22786 streetNumber: null,
22790 stateOrProvince: null
22793 domContainer: this.el.dom,
22794 geodecoder: new google.maps.Geocoder()
22798 drawCircle: function(center, radius, options)
22800 if (this.gMapContext.circle != null) {
22801 this.gMapContext.circle.setMap(null);
22805 options = Roo.apply({}, options, {
22806 strokeColor: "#0000FF",
22807 strokeOpacity: .35,
22809 fillColor: "#0000FF",
22813 options.map = this.gMapContext.map;
22814 options.radius = radius;
22815 options.center = center;
22816 this.gMapContext.circle = new google.maps.Circle(options);
22817 return this.gMapContext.circle;
22823 setPosition: function(location)
22825 this.gMapContext.location = location;
22826 this.gMapContext.marker.setPosition(location);
22827 this.gMapContext.map.panTo(location);
22828 this.drawCircle(location, this.gMapContext.radius, {});
22832 if (this.gMapContext.settings.enableReverseGeocode) {
22833 this.gMapContext.geodecoder.geocode({
22834 latLng: this.gMapContext.location
22835 }, function(results, status) {
22837 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22838 _this.gMapContext.locationName = results[0].formatted_address;
22839 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22841 _this.fireEvent('positionchanged', this, location);
22848 this.fireEvent('positionchanged', this, location);
22853 google.maps.event.trigger(this.gMapContext.map, "resize");
22855 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22857 this.fireEvent('resize', this);
22860 setPositionByLatLng: function(latitude, longitude)
22862 this.setPosition(new google.maps.LatLng(latitude, longitude));
22865 getCurrentPosition: function()
22868 latitude: this.gMapContext.location.lat(),
22869 longitude: this.gMapContext.location.lng()
22873 getAddressName: function()
22875 return this.gMapContext.locationName;
22878 getAddressComponents: function()
22880 return this.gMapContext.addressComponents;
22883 address_component_from_google_geocode: function(address_components)
22887 for (var i = 0; i < address_components.length; i++) {
22888 var component = address_components[i];
22889 if (component.types.indexOf("postal_code") >= 0) {
22890 result.postalCode = component.short_name;
22891 } else if (component.types.indexOf("street_number") >= 0) {
22892 result.streetNumber = component.short_name;
22893 } else if (component.types.indexOf("route") >= 0) {
22894 result.streetName = component.short_name;
22895 } else if (component.types.indexOf("neighborhood") >= 0) {
22896 result.city = component.short_name;
22897 } else if (component.types.indexOf("locality") >= 0) {
22898 result.city = component.short_name;
22899 } else if (component.types.indexOf("sublocality") >= 0) {
22900 result.district = component.short_name;
22901 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22902 result.stateOrProvince = component.short_name;
22903 } else if (component.types.indexOf("country") >= 0) {
22904 result.country = component.short_name;
22908 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22909 result.addressLine2 = "";
22913 setZoomLevel: function(zoom)
22915 this.gMapContext.map.setZoom(zoom);
22928 this.fireEvent('show', this);
22939 this.fireEvent('hide', this);
22944 Roo.apply(Roo.bootstrap.LocationPicker, {
22946 OverlayView : function(map, options)
22948 options = options || {};
22962 * @class Roo.bootstrap.Alert
22963 * @extends Roo.bootstrap.Component
22964 * Bootstrap Alert class
22965 * @cfg {String} title The title of alert
22966 * @cfg {String} html The content of alert
22967 * @cfg {String} weight ( success | info | warning | danger )
22968 * @cfg {String} faicon font-awesomeicon
22971 * Create a new alert
22972 * @param {Object} config The config object
22976 Roo.bootstrap.Alert = function(config){
22977 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22981 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22988 getAutoCreate : function()
22997 cls : 'roo-alert-icon'
23002 cls : 'roo-alert-title',
23007 cls : 'roo-alert-text',
23014 cfg.cn[0].cls += ' fa ' + this.faicon;
23018 cfg.cls += ' alert-' + this.weight;
23024 initEvents: function()
23026 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23029 setTitle : function(str)
23031 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23034 setText : function(str)
23036 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23039 setWeight : function(weight)
23042 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23045 this.weight = weight;
23047 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23050 setIcon : function(icon)
23053 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23058 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);