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);
4064 isActive: function () {
4067 setActive : function(state, fire, is_was_active)
4069 if (this.active && !state & this.navId) {
4070 this.was_active = true;
4071 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4073 nv.clearWasActive(this);
4077 this.active = state;
4080 this.el.removeClass('active');
4081 } else if (!this.el.hasClass('active')) {
4082 this.el.addClass('active');
4085 this.fireEvent('changed', this, state);
4088 // show a panel if it's registered and related..
4090 if (!this.navId || !this.tabId || !state || is_was_active) {
4094 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4098 var pan = tg.getPanelByName(this.tabId);
4102 // if we can not flip to new panel - go back to old nav highlight..
4103 if (false == tg.showPanel(pan)) {
4104 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4106 var onav = nv.getWasActive();
4108 onav.setActive(true, false, true);
4117 // this should not be here...
4118 setDisabled : function(state)
4120 this.disabled = state;
4122 this.el.removeClass('disabled');
4123 } else if (!this.el.hasClass('disabled')) {
4124 this.el.addClass('disabled');
4130 * Fetch the element to display the tooltip on.
4131 * @return {Roo.Element} defaults to this.el
4133 tooltipEl : function()
4135 return this.el.select('' + this.tagtype + '', true).first();
4138 scrollToElement : function(e)
4140 var c = document.body;
4143 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4145 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4146 c = document.documentElement;
4149 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4155 var o = target.calcOffsetsTo(c);
4162 this.fireEvent('scrollto', this, options, e);
4164 Roo.get(c).scrollTo('top', options.value, true);
4177 * <span> icon </span>
4178 * <span> text </span>
4179 * <span>badge </span>
4183 * @class Roo.bootstrap.NavSidebarItem
4184 * @extends Roo.bootstrap.NavItem
4185 * Bootstrap Navbar.NavSidebarItem class
4187 * Create a new Navbar Button
4188 * @param {Object} config The config object
4190 Roo.bootstrap.NavSidebarItem = function(config){
4191 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4196 * The raw click event for the entire grid.
4197 * @param {Roo.EventObject} e
4202 * Fires when the active item active state changes
4203 * @param {Roo.bootstrap.NavSidebarItem} this
4204 * @param {boolean} state the new state
4212 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4215 getAutoCreate : function(){
4220 href : this.href || '#',
4232 html : this.html || ''
4237 cfg.cls += ' active';
4241 if (this.glyphicon || this.icon) {
4242 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4243 a.cn.push({ tag : 'i', cls : c }) ;
4248 if (this.badge !== '') {
4249 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4253 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4254 a.cls += 'dropdown-toggle treeview' ;
4278 * @class Roo.bootstrap.Row
4279 * @extends Roo.bootstrap.Component
4280 * Bootstrap Row class (contains columns...)
4284 * @param {Object} config The config object
4287 Roo.bootstrap.Row = function(config){
4288 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4291 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4293 getAutoCreate : function(){
4312 * @class Roo.bootstrap.Element
4313 * @extends Roo.bootstrap.Component
4314 * Bootstrap Element class
4315 * @cfg {String} html contents of the element
4316 * @cfg {String} tag tag of the element
4317 * @cfg {String} cls class of the element
4318 * @cfg {Boolean} preventDefault (true|false) default false
4319 * @cfg {Boolean} clickable (true|false) default false
4322 * Create a new Element
4323 * @param {Object} config The config object
4326 Roo.bootstrap.Element = function(config){
4327 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4333 * When a element is chick
4334 * @param {Roo.bootstrap.Element} this
4335 * @param {Roo.EventObject} e
4341 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4346 preventDefault: false,
4349 getAutoCreate : function(){
4360 initEvents: function()
4362 Roo.bootstrap.Element.superclass.initEvents.call(this);
4365 this.el.on('click', this.onClick, this);
4370 onClick : function(e)
4372 if(this.preventDefault){
4376 this.fireEvent('click', this, e);
4379 getValue : function()
4381 return this.el.dom.innerHTML;
4384 setValue : function(value)
4386 this.el.dom.innerHTML = value;
4401 * @class Roo.bootstrap.Pagination
4402 * @extends Roo.bootstrap.Component
4403 * Bootstrap Pagination class
4404 * @cfg {String} size xs | sm | md | lg
4405 * @cfg {Boolean} inverse false | true
4408 * Create a new Pagination
4409 * @param {Object} config The config object
4412 Roo.bootstrap.Pagination = function(config){
4413 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4416 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4422 getAutoCreate : function(){
4428 cfg.cls += ' inverse';
4434 cfg.cls += " " + this.cls;
4452 * @class Roo.bootstrap.PaginationItem
4453 * @extends Roo.bootstrap.Component
4454 * Bootstrap PaginationItem class
4455 * @cfg {String} html text
4456 * @cfg {String} href the link
4457 * @cfg {Boolean} preventDefault (true | false) default true
4458 * @cfg {Boolean} active (true | false) default false
4459 * @cfg {Boolean} disabled default false
4463 * Create a new PaginationItem
4464 * @param {Object} config The config object
4468 Roo.bootstrap.PaginationItem = function(config){
4469 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4474 * The raw click event for the entire grid.
4475 * @param {Roo.EventObject} e
4481 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4485 preventDefault: true,
4490 getAutoCreate : function(){
4496 href : this.href ? this.href : '#',
4497 html : this.html ? this.html : ''
4507 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4511 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4517 initEvents: function() {
4519 this.el.on('click', this.onClick, this);
4522 onClick : function(e)
4524 Roo.log('PaginationItem on click ');
4525 if(this.preventDefault){
4533 this.fireEvent('click', this, e);
4549 * @class Roo.bootstrap.Slider
4550 * @extends Roo.bootstrap.Component
4551 * Bootstrap Slider class
4554 * Create a new Slider
4555 * @param {Object} config The config object
4558 Roo.bootstrap.Slider = function(config){
4559 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4562 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4564 getAutoCreate : function(){
4568 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4572 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4584 * Ext JS Library 1.1.1
4585 * Copyright(c) 2006-2007, Ext JS, LLC.
4587 * Originally Released Under LGPL - original licence link has changed is not relivant.
4590 * <script type="text/javascript">
4595 * @class Roo.grid.ColumnModel
4596 * @extends Roo.util.Observable
4597 * This is the default implementation of a ColumnModel used by the Grid. It defines
4598 * the columns in the grid.
4601 var colModel = new Roo.grid.ColumnModel([
4602 {header: "Ticker", width: 60, sortable: true, locked: true},
4603 {header: "Company Name", width: 150, sortable: true},
4604 {header: "Market Cap.", width: 100, sortable: true},
4605 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4606 {header: "Employees", width: 100, sortable: true, resizable: false}
4611 * The config options listed for this class are options which may appear in each
4612 * individual column definition.
4613 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4615 * @param {Object} config An Array of column config objects. See this class's
4616 * config objects for details.
4618 Roo.grid.ColumnModel = function(config){
4620 * The config passed into the constructor
4622 this.config = config;
4625 // if no id, create one
4626 // if the column does not have a dataIndex mapping,
4627 // map it to the order it is in the config
4628 for(var i = 0, len = config.length; i < len; i++){
4630 if(typeof c.dataIndex == "undefined"){
4633 if(typeof c.renderer == "string"){
4634 c.renderer = Roo.util.Format[c.renderer];
4636 if(typeof c.id == "undefined"){
4639 if(c.editor && c.editor.xtype){
4640 c.editor = Roo.factory(c.editor, Roo.grid);
4642 if(c.editor && c.editor.isFormField){
4643 c.editor = new Roo.grid.GridEditor(c.editor);
4645 this.lookup[c.id] = c;
4649 * The width of columns which have no width specified (defaults to 100)
4652 this.defaultWidth = 100;
4655 * Default sortable of columns which have no sortable specified (defaults to false)
4658 this.defaultSortable = false;
4662 * @event widthchange
4663 * Fires when the width of a column changes.
4664 * @param {ColumnModel} this
4665 * @param {Number} columnIndex The column index
4666 * @param {Number} newWidth The new width
4668 "widthchange": true,
4670 * @event headerchange
4671 * Fires when the text of a header changes.
4672 * @param {ColumnModel} this
4673 * @param {Number} columnIndex The column index
4674 * @param {Number} newText The new header text
4676 "headerchange": true,
4678 * @event hiddenchange
4679 * Fires when a column is hidden or "unhidden".
4680 * @param {ColumnModel} this
4681 * @param {Number} columnIndex The column index
4682 * @param {Boolean} hidden true if hidden, false otherwise
4684 "hiddenchange": true,
4686 * @event columnmoved
4687 * Fires when a column is moved.
4688 * @param {ColumnModel} this
4689 * @param {Number} oldIndex
4690 * @param {Number} newIndex
4692 "columnmoved" : true,
4694 * @event columlockchange
4695 * Fires when a column's locked state is changed
4696 * @param {ColumnModel} this
4697 * @param {Number} colIndex
4698 * @param {Boolean} locked true if locked
4700 "columnlockchange" : true
4702 Roo.grid.ColumnModel.superclass.constructor.call(this);
4704 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4706 * @cfg {String} header The header text to display in the Grid view.
4709 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4710 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4711 * specified, the column's index is used as an index into the Record's data Array.
4714 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4715 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4718 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4719 * Defaults to the value of the {@link #defaultSortable} property.
4720 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4723 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4726 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4729 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4732 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4735 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4736 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4737 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4738 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4741 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4744 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4747 * @cfg {String} cursor (Optional)
4750 * @cfg {String} tooltip (Optional)
4753 * Returns the id of the column at the specified index.
4754 * @param {Number} index The column index
4755 * @return {String} the id
4757 getColumnId : function(index){
4758 return this.config[index].id;
4762 * Returns the column for a specified id.
4763 * @param {String} id The column id
4764 * @return {Object} the column
4766 getColumnById : function(id){
4767 return this.lookup[id];
4772 * Returns the column for a specified dataIndex.
4773 * @param {String} dataIndex The column dataIndex
4774 * @return {Object|Boolean} the column or false if not found
4776 getColumnByDataIndex: function(dataIndex){
4777 var index = this.findColumnIndex(dataIndex);
4778 return index > -1 ? this.config[index] : false;
4782 * Returns the index for a specified column id.
4783 * @param {String} id The column id
4784 * @return {Number} the index, or -1 if not found
4786 getIndexById : function(id){
4787 for(var i = 0, len = this.config.length; i < len; i++){
4788 if(this.config[i].id == id){
4796 * Returns the index for a specified column dataIndex.
4797 * @param {String} dataIndex The column dataIndex
4798 * @return {Number} the index, or -1 if not found
4801 findColumnIndex : function(dataIndex){
4802 for(var i = 0, len = this.config.length; i < len; i++){
4803 if(this.config[i].dataIndex == dataIndex){
4811 moveColumn : function(oldIndex, newIndex){
4812 var c = this.config[oldIndex];
4813 this.config.splice(oldIndex, 1);
4814 this.config.splice(newIndex, 0, c);
4815 this.dataMap = null;
4816 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4819 isLocked : function(colIndex){
4820 return this.config[colIndex].locked === true;
4823 setLocked : function(colIndex, value, suppressEvent){
4824 if(this.isLocked(colIndex) == value){
4827 this.config[colIndex].locked = value;
4829 this.fireEvent("columnlockchange", this, colIndex, value);
4833 getTotalLockedWidth : function(){
4835 for(var i = 0; i < this.config.length; i++){
4836 if(this.isLocked(i) && !this.isHidden(i)){
4837 this.totalWidth += this.getColumnWidth(i);
4843 getLockedCount : function(){
4844 for(var i = 0, len = this.config.length; i < len; i++){
4845 if(!this.isLocked(i)){
4852 * Returns the number of columns.
4855 getColumnCount : function(visibleOnly){
4856 if(visibleOnly === true){
4858 for(var i = 0, len = this.config.length; i < len; i++){
4859 if(!this.isHidden(i)){
4865 return this.config.length;
4869 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4870 * @param {Function} fn
4871 * @param {Object} scope (optional)
4872 * @return {Array} result
4874 getColumnsBy : function(fn, scope){
4876 for(var i = 0, len = this.config.length; i < len; i++){
4877 var c = this.config[i];
4878 if(fn.call(scope||this, c, i) === true){
4886 * Returns true if the specified column is sortable.
4887 * @param {Number} col The column index
4890 isSortable : function(col){
4891 if(typeof this.config[col].sortable == "undefined"){
4892 return this.defaultSortable;
4894 return this.config[col].sortable;
4898 * Returns the rendering (formatting) function defined for the column.
4899 * @param {Number} col The column index.
4900 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4902 getRenderer : function(col){
4903 if(!this.config[col].renderer){
4904 return Roo.grid.ColumnModel.defaultRenderer;
4906 return this.config[col].renderer;
4910 * Sets the rendering (formatting) function for a column.
4911 * @param {Number} col The column index
4912 * @param {Function} fn The function to use to process the cell's raw data
4913 * to return HTML markup for the grid view. The render function is called with
4914 * the following parameters:<ul>
4915 * <li>Data value.</li>
4916 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4917 * <li>css A CSS style string to apply to the table cell.</li>
4918 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4919 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4920 * <li>Row index</li>
4921 * <li>Column index</li>
4922 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4924 setRenderer : function(col, fn){
4925 this.config[col].renderer = fn;
4929 * Returns the width for the specified column.
4930 * @param {Number} col The column index
4933 getColumnWidth : function(col){
4934 return this.config[col].width * 1 || this.defaultWidth;
4938 * Sets the width for a column.
4939 * @param {Number} col The column index
4940 * @param {Number} width The new width
4942 setColumnWidth : function(col, width, suppressEvent){
4943 this.config[col].width = width;
4944 this.totalWidth = null;
4946 this.fireEvent("widthchange", this, col, width);
4951 * Returns the total width of all columns.
4952 * @param {Boolean} includeHidden True to include hidden column widths
4955 getTotalWidth : function(includeHidden){
4956 if(!this.totalWidth){
4957 this.totalWidth = 0;
4958 for(var i = 0, len = this.config.length; i < len; i++){
4959 if(includeHidden || !this.isHidden(i)){
4960 this.totalWidth += this.getColumnWidth(i);
4964 return this.totalWidth;
4968 * Returns the header for the specified column.
4969 * @param {Number} col The column index
4972 getColumnHeader : function(col){
4973 return this.config[col].header;
4977 * Sets the header for a column.
4978 * @param {Number} col The column index
4979 * @param {String} header The new header
4981 setColumnHeader : function(col, header){
4982 this.config[col].header = header;
4983 this.fireEvent("headerchange", this, col, header);
4987 * Returns the tooltip for the specified column.
4988 * @param {Number} col The column index
4991 getColumnTooltip : function(col){
4992 return this.config[col].tooltip;
4995 * Sets the tooltip for a column.
4996 * @param {Number} col The column index
4997 * @param {String} tooltip The new tooltip
4999 setColumnTooltip : function(col, tooltip){
5000 this.config[col].tooltip = tooltip;
5004 * Returns the dataIndex for the specified column.
5005 * @param {Number} col The column index
5008 getDataIndex : function(col){
5009 return this.config[col].dataIndex;
5013 * Sets the dataIndex for a column.
5014 * @param {Number} col The column index
5015 * @param {Number} dataIndex The new dataIndex
5017 setDataIndex : function(col, dataIndex){
5018 this.config[col].dataIndex = dataIndex;
5024 * Returns true if the cell is editable.
5025 * @param {Number} colIndex The column index
5026 * @param {Number} rowIndex The row index
5029 isCellEditable : function(colIndex, rowIndex){
5030 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5034 * Returns the editor defined for the cell/column.
5035 * return false or null to disable editing.
5036 * @param {Number} colIndex The column index
5037 * @param {Number} rowIndex The row index
5040 getCellEditor : function(colIndex, rowIndex){
5041 return this.config[colIndex].editor;
5045 * Sets if a column is editable.
5046 * @param {Number} col The column index
5047 * @param {Boolean} editable True if the column is editable
5049 setEditable : function(col, editable){
5050 this.config[col].editable = editable;
5055 * Returns true if the column is hidden.
5056 * @param {Number} colIndex The column index
5059 isHidden : function(colIndex){
5060 return this.config[colIndex].hidden;
5065 * Returns true if the column width cannot be changed
5067 isFixed : function(colIndex){
5068 return this.config[colIndex].fixed;
5072 * Returns true if the column can be resized
5075 isResizable : function(colIndex){
5076 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5079 * Sets if a column is hidden.
5080 * @param {Number} colIndex The column index
5081 * @param {Boolean} hidden True if the column is hidden
5083 setHidden : function(colIndex, hidden){
5084 this.config[colIndex].hidden = hidden;
5085 this.totalWidth = null;
5086 this.fireEvent("hiddenchange", this, colIndex, hidden);
5090 * Sets the editor for a column.
5091 * @param {Number} col The column index
5092 * @param {Object} editor The editor object
5094 setEditor : function(col, editor){
5095 this.config[col].editor = editor;
5099 Roo.grid.ColumnModel.defaultRenderer = function(value){
5100 if(typeof value == "string" && value.length < 1){
5106 // Alias for backwards compatibility
5107 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5110 * Ext JS Library 1.1.1
5111 * Copyright(c) 2006-2007, Ext JS, LLC.
5113 * Originally Released Under LGPL - original licence link has changed is not relivant.
5116 * <script type="text/javascript">
5120 * @class Roo.LoadMask
5121 * A simple utility class for generically masking elements while loading data. If the element being masked has
5122 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5123 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5124 * element's UpdateManager load indicator and will be destroyed after the initial load.
5126 * Create a new LoadMask
5127 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5128 * @param {Object} config The config object
5130 Roo.LoadMask = function(el, config){
5131 this.el = Roo.get(el);
5132 Roo.apply(this, config);
5134 this.store.on('beforeload', this.onBeforeLoad, this);
5135 this.store.on('load', this.onLoad, this);
5136 this.store.on('loadexception', this.onLoadException, this);
5137 this.removeMask = false;
5139 var um = this.el.getUpdateManager();
5140 um.showLoadIndicator = false; // disable the default indicator
5141 um.on('beforeupdate', this.onBeforeLoad, this);
5142 um.on('update', this.onLoad, this);
5143 um.on('failure', this.onLoad, this);
5144 this.removeMask = true;
5148 Roo.LoadMask.prototype = {
5150 * @cfg {Boolean} removeMask
5151 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5152 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5156 * The text to display in a centered loading message box (defaults to 'Loading...')
5160 * @cfg {String} msgCls
5161 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5163 msgCls : 'x-mask-loading',
5166 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5172 * Disables the mask to prevent it from being displayed
5174 disable : function(){
5175 this.disabled = true;
5179 * Enables the mask so that it can be displayed
5181 enable : function(){
5182 this.disabled = false;
5185 onLoadException : function()
5189 if (typeof(arguments[3]) != 'undefined') {
5190 Roo.MessageBox.alert("Error loading",arguments[3]);
5194 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5195 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5204 this.el.unmask(this.removeMask);
5209 this.el.unmask(this.removeMask);
5213 onBeforeLoad : function(){
5215 this.el.mask(this.msg, this.msgCls);
5220 destroy : function(){
5222 this.store.un('beforeload', this.onBeforeLoad, this);
5223 this.store.un('load', this.onLoad, this);
5224 this.store.un('loadexception', this.onLoadException, this);
5226 var um = this.el.getUpdateManager();
5227 um.un('beforeupdate', this.onBeforeLoad, this);
5228 um.un('update', this.onLoad, this);
5229 um.un('failure', this.onLoad, this);
5240 * @class Roo.bootstrap.Table
5241 * @extends Roo.bootstrap.Component
5242 * Bootstrap Table class
5243 * @cfg {String} cls table class
5244 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5245 * @cfg {String} bgcolor Specifies the background color for a table
5246 * @cfg {Number} border Specifies whether the table cells should have borders or not
5247 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5248 * @cfg {Number} cellspacing Specifies the space between cells
5249 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5250 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5251 * @cfg {String} sortable Specifies that the table should be sortable
5252 * @cfg {String} summary Specifies a summary of the content of a table
5253 * @cfg {Number} width Specifies the width of a table
5254 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5256 * @cfg {boolean} striped Should the rows be alternative striped
5257 * @cfg {boolean} bordered Add borders to the table
5258 * @cfg {boolean} hover Add hover highlighting
5259 * @cfg {boolean} condensed Format condensed
5260 * @cfg {boolean} responsive Format condensed
5261 * @cfg {Boolean} loadMask (true|false) default false
5262 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5263 * @cfg {Boolean} thead (true|false) generate thead, default true
5264 * @cfg {Boolean} RowSelection (true|false) default false
5265 * @cfg {Boolean} CellSelection (true|false) default false
5266 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5270 * Create a new Table
5271 * @param {Object} config The config object
5274 Roo.bootstrap.Table = function(config){
5275 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5278 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5279 this.sm = this.selModel;
5280 this.sm.xmodule = this.xmodule || false;
5282 if (this.cm && typeof(this.cm.config) == 'undefined') {
5283 this.colModel = new Roo.grid.ColumnModel(this.cm);
5284 this.cm = this.colModel;
5285 this.cm.xmodule = this.xmodule || false;
5288 this.store= Roo.factory(this.store, Roo.data);
5289 this.ds = this.store;
5290 this.ds.xmodule = this.xmodule || false;
5293 if (this.footer && this.store) {
5294 this.footer.dataSource = this.ds;
5295 this.footer = Roo.factory(this.footer);
5302 * Fires when a cell is clicked
5303 * @param {Roo.bootstrap.Table} this
5304 * @param {Roo.Element} el
5305 * @param {Number} rowIndex
5306 * @param {Number} columnIndex
5307 * @param {Roo.EventObject} e
5311 * @event celldblclick
5312 * Fires when a cell is double clicked
5313 * @param {Roo.bootstrap.Table} this
5314 * @param {Roo.Element} el
5315 * @param {Number} rowIndex
5316 * @param {Number} columnIndex
5317 * @param {Roo.EventObject} e
5319 "celldblclick" : true,
5322 * Fires when a row is clicked
5323 * @param {Roo.bootstrap.Table} this
5324 * @param {Roo.Element} el
5325 * @param {Number} rowIndex
5326 * @param {Roo.EventObject} e
5330 * @event rowdblclick
5331 * Fires when a row is double clicked
5332 * @param {Roo.bootstrap.Table} this
5333 * @param {Roo.Element} el
5334 * @param {Number} rowIndex
5335 * @param {Roo.EventObject} e
5337 "rowdblclick" : true,
5340 * Fires when a mouseover occur
5341 * @param {Roo.bootstrap.Table} this
5342 * @param {Roo.Element} el
5343 * @param {Number} rowIndex
5344 * @param {Number} columnIndex
5345 * @param {Roo.EventObject} e
5350 * Fires when a mouseout occur
5351 * @param {Roo.bootstrap.Table} this
5352 * @param {Roo.Element} el
5353 * @param {Number} rowIndex
5354 * @param {Number} columnIndex
5355 * @param {Roo.EventObject} e
5360 * Fires when a row is rendered, so you can change add a style to it.
5361 * @param {Roo.bootstrap.Table} this
5362 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5366 * @event rowsrendered
5367 * Fires when all the rows have been rendered
5368 * @param {Roo.bootstrap.Table} this
5370 'rowsrendered' : true
5375 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5399 RowSelection : false,
5400 CellSelection : false,
5403 // Roo.Element - the tbody
5406 getAutoCreate : function(){
5407 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5416 cfg.cls += ' table-striped';
5420 cfg.cls += ' table-hover';
5422 if (this.bordered) {
5423 cfg.cls += ' table-bordered';
5425 if (this.condensed) {
5426 cfg.cls += ' table-condensed';
5428 if (this.responsive) {
5429 cfg.cls += ' table-responsive';
5433 cfg.cls+= ' ' +this.cls;
5436 // this lot should be simplifed...
5439 cfg.align=this.align;
5442 cfg.bgcolor=this.bgcolor;
5445 cfg.border=this.border;
5447 if (this.cellpadding) {
5448 cfg.cellpadding=this.cellpadding;
5450 if (this.cellspacing) {
5451 cfg.cellspacing=this.cellspacing;
5454 cfg.frame=this.frame;
5457 cfg.rules=this.rules;
5459 if (this.sortable) {
5460 cfg.sortable=this.sortable;
5463 cfg.summary=this.summary;
5466 cfg.width=this.width;
5469 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5472 if(this.store || this.cm){
5474 cfg.cn.push(this.renderHeader());
5477 cfg.cn.push(this.renderBody());
5480 cfg.cn.push(this.renderFooter());
5483 cfg.cls+= ' TableGrid';
5486 return { cn : [ cfg ] };
5489 initEvents : function()
5491 if(!this.store || !this.cm){
5495 //Roo.log('initEvents with ds!!!!');
5497 this.mainBody = this.el.select('tbody', true).first();
5502 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5503 e.on('click', _this.sort, _this);
5506 this.el.on("click", this.onClick, this);
5507 this.el.on("dblclick", this.onDblClick, this);
5509 // why is this done????? = it breaks dialogs??
5510 //this.parent().el.setStyle('position', 'relative');
5514 this.footer.parentId = this.id;
5515 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5518 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5520 this.store.on('load', this.onLoad, this);
5521 this.store.on('beforeload', this.onBeforeLoad, this);
5522 this.store.on('update', this.onUpdate, this);
5523 this.store.on('add', this.onAdd, this);
5527 onMouseover : function(e, el)
5529 var cell = Roo.get(el);
5535 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5536 cell = cell.findParent('td', false, true);
5539 var row = cell.findParent('tr', false, true);
5540 var cellIndex = cell.dom.cellIndex;
5541 var rowIndex = row.dom.rowIndex - 1; // start from 0
5543 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5547 onMouseout : function(e, el)
5549 var cell = Roo.get(el);
5555 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5556 cell = cell.findParent('td', false, true);
5559 var row = cell.findParent('tr', false, true);
5560 var cellIndex = cell.dom.cellIndex;
5561 var rowIndex = row.dom.rowIndex - 1; // start from 0
5563 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5567 onClick : function(e, el)
5569 var cell = Roo.get(el);
5571 if(!cell || (!this.CellSelection && !this.RowSelection)){
5575 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5576 cell = cell.findParent('td', false, true);
5579 if(!cell || typeof(cell) == 'undefined'){
5583 var row = cell.findParent('tr', false, true);
5585 if(!row || typeof(row) == 'undefined'){
5589 var cellIndex = cell.dom.cellIndex;
5590 var rowIndex = this.getRowIndex(row);
5592 if(this.CellSelection){
5593 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5596 if(this.RowSelection){
5597 this.fireEvent('rowclick', this, row, rowIndex, e);
5603 onDblClick : function(e,el)
5605 var cell = Roo.get(el);
5607 if(!cell || (!this.CellSelection && !this.RowSelection)){
5611 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5612 cell = cell.findParent('td', false, true);
5615 if(!cell || typeof(cell) == 'undefined'){
5619 var row = cell.findParent('tr', false, true);
5621 if(!row || typeof(row) == 'undefined'){
5625 var cellIndex = cell.dom.cellIndex;
5626 var rowIndex = this.getRowIndex(row);
5628 if(this.CellSelection){
5629 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5632 if(this.RowSelection){
5633 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5637 sort : function(e,el)
5639 var col = Roo.get(el);
5641 if(!col.hasClass('sortable')){
5645 var sort = col.attr('sort');
5648 if(col.hasClass('glyphicon-arrow-up')){
5652 this.store.sortInfo = {field : sort, direction : dir};
5655 Roo.log("calling footer first");
5656 this.footer.onClick('first');
5659 this.store.load({ params : { start : 0 } });
5663 renderHeader : function()
5672 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5674 var config = cm.config[i];
5679 html: cm.getColumnHeader(i)
5682 if(typeof(config.tooltip) != 'undefined'){
5683 c.tooltip = config.tooltip;
5686 if(typeof(config.colspan) != 'undefined'){
5687 c.colspan = config.colspan;
5690 if(typeof(config.hidden) != 'undefined' && config.hidden){
5691 c.style += ' display:none;';
5694 if(typeof(config.dataIndex) != 'undefined'){
5695 c.sort = config.dataIndex;
5698 if(typeof(config.sortable) != 'undefined' && config.sortable){
5702 if(typeof(config.align) != 'undefined' && config.align.length){
5703 c.style += ' text-align:' + config.align + ';';
5706 if(typeof(config.width) != 'undefined'){
5707 c.style += ' width:' + config.width + 'px;';
5710 if(typeof(config.cls) != 'undefined'){
5711 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5720 renderBody : function()
5730 colspan : this.cm.getColumnCount()
5740 renderFooter : function()
5750 colspan : this.cm.getColumnCount()
5764 Roo.log('ds onload');
5769 var ds = this.store;
5771 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5772 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5774 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5775 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5778 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5779 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5783 var tbody = this.mainBody;
5785 if(ds.getCount() > 0){
5786 ds.data.each(function(d,rowIndex){
5787 var row = this.renderRow(cm, ds, rowIndex);
5789 tbody.createChild(row);
5793 if(row.cellObjects.length){
5794 Roo.each(row.cellObjects, function(r){
5795 _this.renderCellObject(r);
5802 Roo.each(this.el.select('tbody td', true).elements, function(e){
5803 e.on('mouseover', _this.onMouseover, _this);
5806 Roo.each(this.el.select('tbody td', true).elements, function(e){
5807 e.on('mouseout', _this.onMouseout, _this);
5809 this.fireEvent('rowsrendered', this);
5810 //if(this.loadMask){
5811 // this.maskEl.hide();
5816 onUpdate : function(ds,record)
5818 this.refreshRow(record);
5821 onRemove : function(ds, record, index, isUpdate){
5822 if(isUpdate !== true){
5823 this.fireEvent("beforerowremoved", this, index, record);
5825 var bt = this.mainBody.dom;
5827 var rows = this.el.select('tbody > tr', true).elements;
5829 if(typeof(rows[index]) != 'undefined'){
5830 bt.removeChild(rows[index].dom);
5833 // if(bt.rows[index]){
5834 // bt.removeChild(bt.rows[index]);
5837 if(isUpdate !== true){
5838 //this.stripeRows(index);
5839 //this.syncRowHeights(index, index);
5841 this.fireEvent("rowremoved", this, index, record);
5845 onAdd : function(ds, records, rowIndex)
5847 //Roo.log('on Add called');
5848 // - note this does not handle multiple adding very well..
5849 var bt = this.mainBody.dom;
5850 for (var i =0 ; i < records.length;i++) {
5851 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5852 //Roo.log(records[i]);
5853 //Roo.log(this.store.getAt(rowIndex+i));
5854 this.insertRow(this.store, rowIndex + i, false);
5861 refreshRow : function(record){
5862 var ds = this.store, index;
5863 if(typeof record == 'number'){
5865 record = ds.getAt(index);
5867 index = ds.indexOf(record);
5869 this.insertRow(ds, index, true);
5870 this.onRemove(ds, record, index+1, true);
5871 //this.syncRowHeights(index, index);
5873 this.fireEvent("rowupdated", this, index, record);
5876 insertRow : function(dm, rowIndex, isUpdate){
5879 this.fireEvent("beforerowsinserted", this, rowIndex);
5881 //var s = this.getScrollState();
5882 var row = this.renderRow(this.cm, this.store, rowIndex);
5883 // insert before rowIndex..
5884 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5888 if(row.cellObjects.length){
5889 Roo.each(row.cellObjects, function(r){
5890 _this.renderCellObject(r);
5895 this.fireEvent("rowsinserted", this, rowIndex);
5896 //this.syncRowHeights(firstRow, lastRow);
5897 //this.stripeRows(firstRow);
5904 getRowDom : function(rowIndex)
5906 var rows = this.el.select('tbody > tr', true).elements;
5908 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5911 // returns the object tree for a tr..
5914 renderRow : function(cm, ds, rowIndex)
5917 var d = ds.getAt(rowIndex);
5924 var cellObjects = [];
5926 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5927 var config = cm.config[i];
5929 var renderer = cm.getRenderer(i);
5933 if(typeof(renderer) !== 'undefined'){
5934 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5936 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5937 // and are rendered into the cells after the row is rendered - using the id for the element.
5939 if(typeof(value) === 'object'){
5949 rowIndex : rowIndex,
5954 this.fireEvent('rowclass', this, rowcfg);
5958 cls : rowcfg.rowClass,
5960 html: (typeof(value) === 'object') ? '' : value
5967 if(typeof(config.colspan) != 'undefined'){
5968 td.colspan = config.colspan;
5971 if(typeof(config.hidden) != 'undefined' && config.hidden){
5972 td.style += ' display:none;';
5975 if(typeof(config.align) != 'undefined' && config.align.length){
5976 td.style += ' text-align:' + config.align + ';';
5979 if(typeof(config.width) != 'undefined'){
5980 td.style += ' width:' + config.width + 'px;';
5983 if(typeof(config.cursor) != 'undefined'){
5984 td.style += ' cursor:' + config.cursor + ';';
5987 if(typeof(config.cls) != 'undefined'){
5988 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
5995 row.cellObjects = cellObjects;
6003 onBeforeLoad : function()
6005 //Roo.log('ds onBeforeLoad');
6009 //if(this.loadMask){
6010 // this.maskEl.show();
6018 this.el.select('tbody', true).first().dom.innerHTML = '';
6021 * Show or hide a row.
6022 * @param {Number} rowIndex to show or hide
6023 * @param {Boolean} state hide
6025 setRowVisibility : function(rowIndex, state)
6027 var bt = this.mainBody.dom;
6029 var rows = this.el.select('tbody > tr', true).elements;
6031 if(typeof(rows[rowIndex]) == 'undefined'){
6034 rows[rowIndex].dom.style.display = state ? '' : 'none';
6038 getSelectionModel : function(){
6040 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6042 return this.selModel;
6045 * Render the Roo.bootstrap object from renderder
6047 renderCellObject : function(r)
6051 var t = r.cfg.render(r.container);
6054 Roo.each(r.cfg.cn, function(c){
6056 container: t.getChildContainer(),
6059 _this.renderCellObject(child);
6064 getRowIndex : function(row)
6068 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6091 * @class Roo.bootstrap.TableCell
6092 * @extends Roo.bootstrap.Component
6093 * Bootstrap TableCell class
6094 * @cfg {String} html cell contain text
6095 * @cfg {String} cls cell class
6096 * @cfg {String} tag cell tag (td|th) default td
6097 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6098 * @cfg {String} align Aligns the content in a cell
6099 * @cfg {String} axis Categorizes cells
6100 * @cfg {String} bgcolor Specifies the background color of a cell
6101 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6102 * @cfg {Number} colspan Specifies the number of columns a cell should span
6103 * @cfg {String} headers Specifies one or more header cells a cell is related to
6104 * @cfg {Number} height Sets the height of a cell
6105 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6106 * @cfg {Number} rowspan Sets the number of rows a cell should span
6107 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6108 * @cfg {String} valign Vertical aligns the content in a cell
6109 * @cfg {Number} width Specifies the width of a cell
6112 * Create a new TableCell
6113 * @param {Object} config The config object
6116 Roo.bootstrap.TableCell = function(config){
6117 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6120 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6140 getAutoCreate : function(){
6141 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6161 cfg.align=this.align
6167 cfg.bgcolor=this.bgcolor
6170 cfg.charoff=this.charoff
6173 cfg.colspan=this.colspan
6176 cfg.headers=this.headers
6179 cfg.height=this.height
6182 cfg.nowrap=this.nowrap
6185 cfg.rowspan=this.rowspan
6188 cfg.scope=this.scope
6191 cfg.valign=this.valign
6194 cfg.width=this.width
6213 * @class Roo.bootstrap.TableRow
6214 * @extends Roo.bootstrap.Component
6215 * Bootstrap TableRow class
6216 * @cfg {String} cls row class
6217 * @cfg {String} align Aligns the content in a table row
6218 * @cfg {String} bgcolor Specifies a background color for a table row
6219 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6220 * @cfg {String} valign Vertical aligns the content in a table row
6223 * Create a new TableRow
6224 * @param {Object} config The config object
6227 Roo.bootstrap.TableRow = function(config){
6228 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6231 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6239 getAutoCreate : function(){
6240 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6250 cfg.align = this.align;
6253 cfg.bgcolor = this.bgcolor;
6256 cfg.charoff = this.charoff;
6259 cfg.valign = this.valign;
6277 * @class Roo.bootstrap.TableBody
6278 * @extends Roo.bootstrap.Component
6279 * Bootstrap TableBody class
6280 * @cfg {String} cls element class
6281 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6282 * @cfg {String} align Aligns the content inside the element
6283 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6284 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6287 * Create a new TableBody
6288 * @param {Object} config The config object
6291 Roo.bootstrap.TableBody = function(config){
6292 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6295 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6303 getAutoCreate : function(){
6304 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6318 cfg.align = this.align;
6321 cfg.charoff = this.charoff;
6324 cfg.valign = this.valign;
6331 // initEvents : function()
6338 // this.store = Roo.factory(this.store, Roo.data);
6339 // this.store.on('load', this.onLoad, this);
6341 // this.store.load();
6345 // onLoad: function ()
6347 // this.fireEvent('load', this);
6357 * Ext JS Library 1.1.1
6358 * Copyright(c) 2006-2007, Ext JS, LLC.
6360 * Originally Released Under LGPL - original licence link has changed is not relivant.
6363 * <script type="text/javascript">
6366 // as we use this in bootstrap.
6367 Roo.namespace('Roo.form');
6369 * @class Roo.form.Action
6370 * Internal Class used to handle form actions
6372 * @param {Roo.form.BasicForm} el The form element or its id
6373 * @param {Object} config Configuration options
6378 // define the action interface
6379 Roo.form.Action = function(form, options){
6381 this.options = options || {};
6384 * Client Validation Failed
6387 Roo.form.Action.CLIENT_INVALID = 'client';
6389 * Server Validation Failed
6392 Roo.form.Action.SERVER_INVALID = 'server';
6394 * Connect to Server Failed
6397 Roo.form.Action.CONNECT_FAILURE = 'connect';
6399 * Reading Data from Server Failed
6402 Roo.form.Action.LOAD_FAILURE = 'load';
6404 Roo.form.Action.prototype = {
6406 failureType : undefined,
6407 response : undefined,
6411 run : function(options){
6416 success : function(response){
6421 handleResponse : function(response){
6425 // default connection failure
6426 failure : function(response){
6428 this.response = response;
6429 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6430 this.form.afterAction(this, false);
6433 processResponse : function(response){
6434 this.response = response;
6435 if(!response.responseText){
6438 this.result = this.handleResponse(response);
6442 // utility functions used internally
6443 getUrl : function(appendParams){
6444 var url = this.options.url || this.form.url || this.form.el.dom.action;
6446 var p = this.getParams();
6448 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6454 getMethod : function(){
6455 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6458 getParams : function(){
6459 var bp = this.form.baseParams;
6460 var p = this.options.params;
6462 if(typeof p == "object"){
6463 p = Roo.urlEncode(Roo.applyIf(p, bp));
6464 }else if(typeof p == 'string' && bp){
6465 p += '&' + Roo.urlEncode(bp);
6468 p = Roo.urlEncode(bp);
6473 createCallback : function(){
6475 success: this.success,
6476 failure: this.failure,
6478 timeout: (this.form.timeout*1000),
6479 upload: this.form.fileUpload ? this.success : undefined
6484 Roo.form.Action.Submit = function(form, options){
6485 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6488 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6491 haveProgress : false,
6492 uploadComplete : false,
6494 // uploadProgress indicator.
6495 uploadProgress : function()
6497 if (!this.form.progressUrl) {
6501 if (!this.haveProgress) {
6502 Roo.MessageBox.progress("Uploading", "Uploading");
6504 if (this.uploadComplete) {
6505 Roo.MessageBox.hide();
6509 this.haveProgress = true;
6511 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6513 var c = new Roo.data.Connection();
6515 url : this.form.progressUrl,
6520 success : function(req){
6521 //console.log(data);
6525 rdata = Roo.decode(req.responseText)
6527 Roo.log("Invalid data from server..");
6531 if (!rdata || !rdata.success) {
6533 Roo.MessageBox.alert(Roo.encode(rdata));
6536 var data = rdata.data;
6538 if (this.uploadComplete) {
6539 Roo.MessageBox.hide();
6544 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6545 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6548 this.uploadProgress.defer(2000,this);
6551 failure: function(data) {
6552 Roo.log('progress url failed ');
6563 // run get Values on the form, so it syncs any secondary forms.
6564 this.form.getValues();
6566 var o = this.options;
6567 var method = this.getMethod();
6568 var isPost = method == 'POST';
6569 if(o.clientValidation === false || this.form.isValid()){
6571 if (this.form.progressUrl) {
6572 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6573 (new Date() * 1) + '' + Math.random());
6578 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6579 form:this.form.el.dom,
6580 url:this.getUrl(!isPost),
6582 params:isPost ? this.getParams() : null,
6583 isUpload: this.form.fileUpload
6586 this.uploadProgress();
6588 }else if (o.clientValidation !== false){ // client validation failed
6589 this.failureType = Roo.form.Action.CLIENT_INVALID;
6590 this.form.afterAction(this, false);
6594 success : function(response)
6596 this.uploadComplete= true;
6597 if (this.haveProgress) {
6598 Roo.MessageBox.hide();
6602 var result = this.processResponse(response);
6603 if(result === true || result.success){
6604 this.form.afterAction(this, true);
6608 this.form.markInvalid(result.errors);
6609 this.failureType = Roo.form.Action.SERVER_INVALID;
6611 this.form.afterAction(this, false);
6613 failure : function(response)
6615 this.uploadComplete= true;
6616 if (this.haveProgress) {
6617 Roo.MessageBox.hide();
6620 this.response = response;
6621 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6622 this.form.afterAction(this, false);
6625 handleResponse : function(response){
6626 if(this.form.errorReader){
6627 var rs = this.form.errorReader.read(response);
6630 for(var i = 0, len = rs.records.length; i < len; i++) {
6631 var r = rs.records[i];
6635 if(errors.length < 1){
6639 success : rs.success,
6645 ret = Roo.decode(response.responseText);
6649 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6659 Roo.form.Action.Load = function(form, options){
6660 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6661 this.reader = this.form.reader;
6664 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6669 Roo.Ajax.request(Roo.apply(
6670 this.createCallback(), {
6671 method:this.getMethod(),
6672 url:this.getUrl(false),
6673 params:this.getParams()
6677 success : function(response){
6679 var result = this.processResponse(response);
6680 if(result === true || !result.success || !result.data){
6681 this.failureType = Roo.form.Action.LOAD_FAILURE;
6682 this.form.afterAction(this, false);
6685 this.form.clearInvalid();
6686 this.form.setValues(result.data);
6687 this.form.afterAction(this, true);
6690 handleResponse : function(response){
6691 if(this.form.reader){
6692 var rs = this.form.reader.read(response);
6693 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6695 success : rs.success,
6699 return Roo.decode(response.responseText);
6703 Roo.form.Action.ACTION_TYPES = {
6704 'load' : Roo.form.Action.Load,
6705 'submit' : Roo.form.Action.Submit
6714 * @class Roo.bootstrap.Form
6715 * @extends Roo.bootstrap.Component
6716 * Bootstrap Form class
6717 * @cfg {String} method GET | POST (default POST)
6718 * @cfg {String} labelAlign top | left (default top)
6719 * @cfg {String} align left | right - for navbars
6720 * @cfg {Boolean} loadMask load mask when submit (default true)
6725 * @param {Object} config The config object
6729 Roo.bootstrap.Form = function(config){
6730 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6733 * @event clientvalidation
6734 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6735 * @param {Form} this
6736 * @param {Boolean} valid true if the form has passed client-side validation
6738 clientvalidation: true,
6740 * @event beforeaction
6741 * Fires before any action is performed. Return false to cancel the action.
6742 * @param {Form} this
6743 * @param {Action} action The action to be performed
6747 * @event actionfailed
6748 * Fires when an action fails.
6749 * @param {Form} this
6750 * @param {Action} action The action that failed
6752 actionfailed : true,
6754 * @event actioncomplete
6755 * Fires when an action is completed.
6756 * @param {Form} this
6757 * @param {Action} action The action that completed
6759 actioncomplete : true
6764 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6767 * @cfg {String} method
6768 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6773 * The URL to use for form actions if one isn't supplied in the action options.
6776 * @cfg {Boolean} fileUpload
6777 * Set to true if this form is a file upload.
6781 * @cfg {Object} baseParams
6782 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6786 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6790 * @cfg {Sting} align (left|right) for navbar forms
6795 activeAction : null,
6798 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6799 * element by passing it or its id or mask the form itself by passing in true.
6802 waitMsgTarget : false,
6806 getAutoCreate : function(){
6810 method : this.method || 'POST',
6811 id : this.id || Roo.id(),
6814 if (this.parent().xtype.match(/^Nav/)) {
6815 cfg.cls = 'navbar-form navbar-' + this.align;
6819 if (this.labelAlign == 'left' ) {
6820 cfg.cls += ' form-horizontal';
6826 initEvents : function()
6828 this.el.on('submit', this.onSubmit, this);
6829 // this was added as random key presses on the form where triggering form submit.
6830 this.el.on('keypress', function(e) {
6831 if (e.getCharCode() != 13) {
6834 // we might need to allow it for textareas.. and some other items.
6835 // check e.getTarget().
6837 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6841 Roo.log("keypress blocked");
6849 onSubmit : function(e){
6854 * Returns true if client-side validation on the form is successful.
6857 isValid : function(){
6858 var items = this.getItems();
6860 items.each(function(f){
6869 * Returns true if any fields in this form have changed since their original load.
6872 isDirty : function(){
6874 var items = this.getItems();
6875 items.each(function(f){
6885 * Performs a predefined action (submit or load) or custom actions you define on this form.
6886 * @param {String} actionName The name of the action type
6887 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6888 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6889 * accept other config options):
6891 Property Type Description
6892 ---------------- --------------- ----------------------------------------------------------------------------------
6893 url String The url for the action (defaults to the form's url)
6894 method String The form method to use (defaults to the form's method, or POST if not defined)
6895 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6896 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6897 validate the form on the client (defaults to false)
6899 * @return {BasicForm} this
6901 doAction : function(action, options){
6902 if(typeof action == 'string'){
6903 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6905 if(this.fireEvent('beforeaction', this, action) !== false){
6906 this.beforeAction(action);
6907 action.run.defer(100, action);
6913 beforeAction : function(action){
6914 var o = action.options;
6917 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6919 // not really supported yet.. ??
6921 //if(this.waitMsgTarget === true){
6922 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6923 //}else if(this.waitMsgTarget){
6924 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6925 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6927 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6933 afterAction : function(action, success){
6934 this.activeAction = null;
6935 var o = action.options;
6937 //if(this.waitMsgTarget === true){
6939 //}else if(this.waitMsgTarget){
6940 // this.waitMsgTarget.unmask();
6942 // Roo.MessageBox.updateProgress(1);
6943 // Roo.MessageBox.hide();
6950 Roo.callback(o.success, o.scope, [this, action]);
6951 this.fireEvent('actioncomplete', this, action);
6955 // failure condition..
6956 // we have a scenario where updates need confirming.
6957 // eg. if a locking scenario exists..
6958 // we look for { errors : { needs_confirm : true }} in the response.
6960 (typeof(action.result) != 'undefined') &&
6961 (typeof(action.result.errors) != 'undefined') &&
6962 (typeof(action.result.errors.needs_confirm) != 'undefined')
6965 Roo.log("not supported yet");
6968 Roo.MessageBox.confirm(
6969 "Change requires confirmation",
6970 action.result.errorMsg,
6975 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6985 Roo.callback(o.failure, o.scope, [this, action]);
6986 // show an error message if no failed handler is set..
6987 if (!this.hasListener('actionfailed')) {
6988 Roo.log("need to add dialog support");
6990 Roo.MessageBox.alert("Error",
6991 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
6992 action.result.errorMsg :
6993 "Saving Failed, please check your entries or try again"
6998 this.fireEvent('actionfailed', this, action);
7003 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7004 * @param {String} id The value to search for
7007 findField : function(id){
7008 var items = this.getItems();
7009 var field = items.get(id);
7011 items.each(function(f){
7012 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7019 return field || null;
7022 * Mark fields in this form invalid in bulk.
7023 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7024 * @return {BasicForm} this
7026 markInvalid : function(errors){
7027 if(errors instanceof Array){
7028 for(var i = 0, len = errors.length; i < len; i++){
7029 var fieldError = errors[i];
7030 var f = this.findField(fieldError.id);
7032 f.markInvalid(fieldError.msg);
7038 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7039 field.markInvalid(errors[id]);
7043 //Roo.each(this.childForms || [], function (f) {
7044 // f.markInvalid(errors);
7051 * Set values for fields in this form in bulk.
7052 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7053 * @return {BasicForm} this
7055 setValues : function(values){
7056 if(values instanceof Array){ // array of objects
7057 for(var i = 0, len = values.length; i < len; i++){
7059 var f = this.findField(v.id);
7061 f.setValue(v.value);
7062 if(this.trackResetOnLoad){
7063 f.originalValue = f.getValue();
7067 }else{ // object hash
7070 if(typeof values[id] != 'function' && (field = this.findField(id))){
7072 if (field.setFromData &&
7074 field.displayField &&
7075 // combos' with local stores can
7076 // be queried via setValue()
7077 // to set their value..
7078 (field.store && !field.store.isLocal)
7082 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7083 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7084 field.setFromData(sd);
7087 field.setValue(values[id]);
7091 if(this.trackResetOnLoad){
7092 field.originalValue = field.getValue();
7098 //Roo.each(this.childForms || [], function (f) {
7099 // f.setValues(values);
7106 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7107 * they are returned as an array.
7108 * @param {Boolean} asString
7111 getValues : function(asString){
7112 //if (this.childForms) {
7113 // copy values from the child forms
7114 // Roo.each(this.childForms, function (f) {
7115 // this.setValues(f.getValues());
7121 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7122 if(asString === true){
7125 return Roo.urlDecode(fs);
7129 * Returns the fields in this form as an object with key/value pairs.
7130 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7133 getFieldValues : function(with_hidden)
7135 var items = this.getItems();
7137 items.each(function(f){
7141 var v = f.getValue();
7142 if (f.inputType =='radio') {
7143 if (typeof(ret[f.getName()]) == 'undefined') {
7144 ret[f.getName()] = ''; // empty..
7147 if (!f.el.dom.checked) {
7155 // not sure if this supported any more..
7156 if ((typeof(v) == 'object') && f.getRawValue) {
7157 v = f.getRawValue() ; // dates..
7159 // combo boxes where name != hiddenName...
7160 if (f.name != f.getName()) {
7161 ret[f.name] = f.getRawValue();
7163 ret[f.getName()] = v;
7170 * Clears all invalid messages in this form.
7171 * @return {BasicForm} this
7173 clearInvalid : function(){
7174 var items = this.getItems();
7176 items.each(function(f){
7187 * @return {BasicForm} this
7190 var items = this.getItems();
7191 items.each(function(f){
7195 Roo.each(this.childForms || [], function (f) {
7202 getItems : function()
7204 var r=new Roo.util.MixedCollection(false, function(o){
7205 return o.id || (o.id = Roo.id());
7207 var iter = function(el) {
7214 Roo.each(el.items,function(e) {
7234 * Ext JS Library 1.1.1
7235 * Copyright(c) 2006-2007, Ext JS, LLC.
7237 * Originally Released Under LGPL - original licence link has changed is not relivant.
7240 * <script type="text/javascript">
7243 * @class Roo.form.VTypes
7244 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7247 Roo.form.VTypes = function(){
7248 // closure these in so they are only created once.
7249 var alpha = /^[a-zA-Z_]+$/;
7250 var alphanum = /^[a-zA-Z0-9_]+$/;
7251 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7252 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7254 // All these messages and functions are configurable
7257 * The function used to validate email addresses
7258 * @param {String} value The email address
7260 'email' : function(v){
7261 return email.test(v);
7264 * The error text to display when the email validation function returns false
7267 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7269 * The keystroke filter mask to be applied on email input
7272 'emailMask' : /[a-z0-9_\.\-@]/i,
7275 * The function used to validate URLs
7276 * @param {String} value The URL
7278 'url' : function(v){
7282 * The error text to display when the url validation function returns false
7285 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7288 * The function used to validate alpha values
7289 * @param {String} value The value
7291 'alpha' : function(v){
7292 return alpha.test(v);
7295 * The error text to display when the alpha validation function returns false
7298 'alphaText' : 'This field should only contain letters and _',
7300 * The keystroke filter mask to be applied on alpha input
7303 'alphaMask' : /[a-z_]/i,
7306 * The function used to validate alphanumeric values
7307 * @param {String} value The value
7309 'alphanum' : function(v){
7310 return alphanum.test(v);
7313 * The error text to display when the alphanumeric validation function returns false
7316 'alphanumText' : 'This field should only contain letters, numbers and _',
7318 * The keystroke filter mask to be applied on alphanumeric input
7321 'alphanumMask' : /[a-z0-9_]/i
7331 * @class Roo.bootstrap.Input
7332 * @extends Roo.bootstrap.Component
7333 * Bootstrap Input class
7334 * @cfg {Boolean} disabled is it disabled
7335 * @cfg {String} fieldLabel - the label associated
7336 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7337 * @cfg {String} name name of the input
7338 * @cfg {string} fieldLabel - the label associated
7339 * @cfg {string} inputType - input / file submit ...
7340 * @cfg {string} placeholder - placeholder to put in text.
7341 * @cfg {string} before - input group add on before
7342 * @cfg {string} after - input group add on after
7343 * @cfg {string} size - (lg|sm) or leave empty..
7344 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7345 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7346 * @cfg {Number} md colspan out of 12 for computer-sized screens
7347 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7348 * @cfg {string} value default value of the input
7349 * @cfg {Number} labelWidth set the width of label (0-12)
7350 * @cfg {String} labelAlign (top|left)
7351 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7352 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7354 * @cfg {String} align (left|center|right) Default left
7359 * Create a new Input
7360 * @param {Object} config The config object
7363 Roo.bootstrap.Input = function(config){
7364 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7369 * Fires when this field receives input focus.
7370 * @param {Roo.form.Field} this
7375 * Fires when this field loses input focus.
7376 * @param {Roo.form.Field} this
7381 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7382 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7383 * @param {Roo.form.Field} this
7384 * @param {Roo.EventObject} e The event object
7389 * Fires just before the field blurs if the field value has changed.
7390 * @param {Roo.form.Field} this
7391 * @param {Mixed} newValue The new value
7392 * @param {Mixed} oldValue The original value
7397 * Fires after the field has been marked as invalid.
7398 * @param {Roo.form.Field} this
7399 * @param {String} msg The validation message
7404 * Fires after the field has been validated with no errors.
7405 * @param {Roo.form.Field} this
7410 * Fires after the key up
7411 * @param {Roo.form.Field} this
7412 * @param {Roo.EventObject} e The event Object
7418 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7420 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7421 automatic validation (defaults to "keyup").
7423 validationEvent : "keyup",
7425 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7427 validateOnBlur : true,
7429 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7431 validationDelay : 250,
7433 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7435 focusClass : "x-form-focus", // not needed???
7439 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7441 invalidClass : "has-warning",
7444 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7446 validClass : "has-success",
7449 * @cfg {Boolean} hasFeedback (true|false) default true
7454 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7456 invalidFeedbackClass : "glyphicon-warning-sign",
7459 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7461 validFeedbackClass : "glyphicon-ok",
7464 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7466 selectOnFocus : false,
7469 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7473 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7478 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7480 disableKeyFilter : false,
7483 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7487 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7491 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7493 blankText : "This field is required",
7496 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7500 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7502 maxLength : Number.MAX_VALUE,
7504 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7506 minLengthText : "The minimum length for this field is {0}",
7508 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7510 maxLengthText : "The maximum length for this field is {0}",
7514 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7515 * If available, this function will be called only after the basic validators all return true, and will be passed the
7516 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7520 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7521 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7522 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7526 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7530 autocomplete: false,
7549 formatedValue : false,
7551 parentLabelAlign : function()
7554 while (parent.parent()) {
7555 parent = parent.parent();
7556 if (typeof(parent.labelAlign) !='undefined') {
7557 return parent.labelAlign;
7564 getAutoCreate : function(){
7566 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7572 if(this.inputType != 'hidden'){
7573 cfg.cls = 'form-group' //input-group
7579 type : this.inputType,
7581 cls : 'form-control',
7582 placeholder : this.placeholder || '',
7583 autocomplete : this.autocomplete || 'new-password'
7588 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7591 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7592 input.maxLength = this.maxLength;
7595 if (this.disabled) {
7596 input.disabled=true;
7599 if (this.readOnly) {
7600 input.readonly=true;
7604 input.name = this.name;
7607 input.cls += ' input-' + this.size;
7610 ['xs','sm','md','lg'].map(function(size){
7611 if (settings[size]) {
7612 cfg.cls += ' col-' + size + '-' + settings[size];
7616 var inputblock = input;
7620 cls: 'glyphicon form-control-feedback'
7623 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7626 cls : 'has-feedback',
7634 if (this.before || this.after) {
7637 cls : 'input-group',
7641 if (this.before && typeof(this.before) == 'string') {
7643 inputblock.cn.push({
7645 cls : 'roo-input-before input-group-addon',
7649 if (this.before && typeof(this.before) == 'object') {
7650 this.before = Roo.factory(this.before);
7651 Roo.log(this.before);
7652 inputblock.cn.push({
7654 cls : 'roo-input-before input-group-' +
7655 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7659 inputblock.cn.push(input);
7661 if (this.after && typeof(this.after) == 'string') {
7662 inputblock.cn.push({
7664 cls : 'roo-input-after input-group-addon',
7668 if (this.after && typeof(this.after) == 'object') {
7669 this.after = Roo.factory(this.after);
7670 Roo.log(this.after);
7671 inputblock.cn.push({
7673 cls : 'roo-input-after input-group-' +
7674 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7678 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7679 inputblock.cls += ' has-feedback';
7680 inputblock.cn.push(feedback);
7684 if (align ==='left' && this.fieldLabel.length) {
7685 Roo.log("left and has label");
7691 cls : 'control-label col-sm-' + this.labelWidth,
7692 html : this.fieldLabel
7696 cls : "col-sm-" + (12 - this.labelWidth),
7703 } else if ( this.fieldLabel.length) {
7709 //cls : 'input-group-addon',
7710 html : this.fieldLabel
7720 Roo.log(" no label && no align");
7729 Roo.log('input-parentType: ' + this.parentType);
7731 if (this.parentType === 'Navbar' && this.parent().bar) {
7732 cfg.cls += ' navbar-form';
7740 * return the real input element.
7742 inputEl: function ()
7744 return this.el.select('input.form-control',true).first();
7747 tooltipEl : function()
7749 return this.inputEl();
7752 setDisabled : function(v)
7754 var i = this.inputEl().dom;
7756 i.removeAttribute('disabled');
7760 i.setAttribute('disabled','true');
7762 initEvents : function()
7765 this.inputEl().on("keydown" , this.fireKey, this);
7766 this.inputEl().on("focus", this.onFocus, this);
7767 this.inputEl().on("blur", this.onBlur, this);
7769 this.inputEl().relayEvent('keyup', this);
7771 // reference to original value for reset
7772 this.originalValue = this.getValue();
7773 //Roo.form.TextField.superclass.initEvents.call(this);
7774 if(this.validationEvent == 'keyup'){
7775 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7776 this.inputEl().on('keyup', this.filterValidation, this);
7778 else if(this.validationEvent !== false){
7779 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7782 if(this.selectOnFocus){
7783 this.on("focus", this.preFocus, this);
7786 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7787 this.inputEl().on("keypress", this.filterKeys, this);
7790 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7791 this.el.on("click", this.autoSize, this);
7794 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7795 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7798 if (typeof(this.before) == 'object') {
7799 this.before.render(this.el.select('.roo-input-before',true).first());
7801 if (typeof(this.after) == 'object') {
7802 this.after.render(this.el.select('.roo-input-after',true).first());
7807 filterValidation : function(e){
7808 if(!e.isNavKeyPress()){
7809 this.validationTask.delay(this.validationDelay);
7813 * Validates the field value
7814 * @return {Boolean} True if the value is valid, else false
7816 validate : function(){
7817 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7818 if(this.disabled || this.validateValue(this.getRawValue())){
7829 * Validates a value according to the field's validation rules and marks the field as invalid
7830 * if the validation fails
7831 * @param {Mixed} value The value to validate
7832 * @return {Boolean} True if the value is valid, else false
7834 validateValue : function(value){
7835 if(value.length < 1) { // if it's blank
7836 if(this.allowBlank){
7842 if(value.length < this.minLength){
7845 if(value.length > this.maxLength){
7849 var vt = Roo.form.VTypes;
7850 if(!vt[this.vtype](value, this)){
7854 if(typeof this.validator == "function"){
7855 var msg = this.validator(value);
7861 if(this.regex && !this.regex.test(value)){
7871 fireKey : function(e){
7872 //Roo.log('field ' + e.getKey());
7873 if(e.isNavKeyPress()){
7874 this.fireEvent("specialkey", this, e);
7877 focus : function (selectText){
7879 this.inputEl().focus();
7880 if(selectText === true){
7881 this.inputEl().dom.select();
7887 onFocus : function(){
7888 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7889 // this.el.addClass(this.focusClass);
7892 this.hasFocus = true;
7893 this.startValue = this.getValue();
7894 this.fireEvent("focus", this);
7898 beforeBlur : Roo.emptyFn,
7902 onBlur : function(){
7904 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7905 //this.el.removeClass(this.focusClass);
7907 this.hasFocus = false;
7908 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7911 var v = this.getValue();
7912 if(String(v) !== String(this.startValue)){
7913 this.fireEvent('change', this, v, this.startValue);
7915 this.fireEvent("blur", this);
7919 * Resets the current field value to the originally loaded value and clears any validation messages
7922 this.setValue(this.originalValue);
7926 * Returns the name of the field
7927 * @return {Mixed} name The name field
7929 getName: function(){
7933 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7934 * @return {Mixed} value The field value
7936 getValue : function(){
7938 var v = this.inputEl().getValue();
7943 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7944 * @return {Mixed} value The field value
7946 getRawValue : function(){
7947 var v = this.inputEl().getValue();
7953 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7954 * @param {Mixed} value The value to set
7956 setRawValue : function(v){
7957 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7960 selectText : function(start, end){
7961 var v = this.getRawValue();
7963 start = start === undefined ? 0 : start;
7964 end = end === undefined ? v.length : end;
7965 var d = this.inputEl().dom;
7966 if(d.setSelectionRange){
7967 d.setSelectionRange(start, end);
7968 }else if(d.createTextRange){
7969 var range = d.createTextRange();
7970 range.moveStart("character", start);
7971 range.moveEnd("character", v.length-end);
7978 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7979 * @param {Mixed} value The value to set
7981 setValue : function(v){
7984 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7990 processValue : function(value){
7991 if(this.stripCharsRe){
7992 var newValue = value.replace(this.stripCharsRe, '');
7993 if(newValue !== value){
7994 this.setRawValue(newValue);
8001 preFocus : function(){
8003 if(this.selectOnFocus){
8004 this.inputEl().dom.select();
8007 filterKeys : function(e){
8009 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8012 var c = e.getCharCode(), cc = String.fromCharCode(c);
8013 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8016 if(!this.maskRe.test(cc)){
8021 * Clear any invalid styles/messages for this field
8023 clearInvalid : function(){
8025 if(!this.el || this.preventMark){ // not rendered
8028 this.el.removeClass(this.invalidClass);
8030 this.fireEvent('valid', this);
8034 * Mark this field as valid
8036 markValid : function(){
8037 if(!this.el || this.preventMark){ // not rendered
8041 this.el.removeClass([this.invalidClass, this.validClass]);
8043 if(this.disabled || this.allowBlank){
8047 this.el.addClass(this.validClass);
8049 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8051 var feedback = this.el.select('.form-control-feedback', true).first();
8054 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8055 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8060 this.fireEvent('valid', this);
8064 * Mark this field as invalid
8065 * @param {String} msg The validation message
8067 markInvalid : function(msg){
8068 if(!this.el || this.preventMark){ // not rendered
8072 this.el.removeClass([this.invalidClass, this.validClass]);
8074 if(this.disabled || this.allowBlank){
8078 this.el.addClass(this.invalidClass);
8080 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8082 var feedback = this.el.select('.form-control-feedback', true).first();
8085 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8087 if(this.getValue().length){
8088 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8095 this.fireEvent('invalid', this, msg);
8098 SafariOnKeyDown : function(event)
8100 // this is a workaround for a password hang bug on chrome/ webkit.
8102 var isSelectAll = false;
8104 if(this.inputEl().dom.selectionEnd > 0){
8105 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8107 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8108 event.preventDefault();
8113 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8115 event.preventDefault();
8116 // this is very hacky as keydown always get's upper case.
8118 var cc = String.fromCharCode(event.getCharCode());
8119 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8123 adjustWidth : function(tag, w){
8124 tag = tag.toLowerCase();
8125 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8126 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8130 if(tag == 'textarea'){
8133 }else if(Roo.isOpera){
8137 if(tag == 'textarea'){
8156 * @class Roo.bootstrap.TextArea
8157 * @extends Roo.bootstrap.Input
8158 * Bootstrap TextArea class
8159 * @cfg {Number} cols Specifies the visible width of a text area
8160 * @cfg {Number} rows Specifies the visible number of lines in a text area
8161 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8162 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8163 * @cfg {string} html text
8166 * Create a new TextArea
8167 * @param {Object} config The config object
8170 Roo.bootstrap.TextArea = function(config){
8171 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8175 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8185 getAutoCreate : function(){
8187 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8198 value : this.value || '',
8199 html: this.html || '',
8200 cls : 'form-control',
8201 placeholder : this.placeholder || ''
8205 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8206 input.maxLength = this.maxLength;
8210 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8214 input.cols = this.cols;
8217 if (this.readOnly) {
8218 input.readonly = true;
8222 input.name = this.name;
8226 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8230 ['xs','sm','md','lg'].map(function(size){
8231 if (settings[size]) {
8232 cfg.cls += ' col-' + size + '-' + settings[size];
8236 var inputblock = input;
8238 if(this.hasFeedback && !this.allowBlank){
8242 cls: 'glyphicon form-control-feedback'
8246 cls : 'has-feedback',
8255 if (this.before || this.after) {
8258 cls : 'input-group',
8262 inputblock.cn.push({
8264 cls : 'input-group-addon',
8269 inputblock.cn.push(input);
8271 if(this.hasFeedback && !this.allowBlank){
8272 inputblock.cls += ' has-feedback';
8273 inputblock.cn.push(feedback);
8277 inputblock.cn.push({
8279 cls : 'input-group-addon',
8286 if (align ==='left' && this.fieldLabel.length) {
8287 Roo.log("left and has label");
8293 cls : 'control-label col-sm-' + this.labelWidth,
8294 html : this.fieldLabel
8298 cls : "col-sm-" + (12 - this.labelWidth),
8305 } else if ( this.fieldLabel.length) {
8311 //cls : 'input-group-addon',
8312 html : this.fieldLabel
8322 Roo.log(" no label && no align");
8332 if (this.disabled) {
8333 input.disabled=true;
8340 * return the real textarea element.
8342 inputEl: function ()
8344 return this.el.select('textarea.form-control',true).first();
8352 * trigger field - base class for combo..
8357 * @class Roo.bootstrap.TriggerField
8358 * @extends Roo.bootstrap.Input
8359 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8360 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8361 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8362 * for which you can provide a custom implementation. For example:
8364 var trigger = new Roo.bootstrap.TriggerField();
8365 trigger.onTriggerClick = myTriggerFn;
8366 trigger.applyTo('my-field');
8369 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8370 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8371 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8372 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8373 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8376 * Create a new TriggerField.
8377 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8378 * to the base TextField)
8380 Roo.bootstrap.TriggerField = function(config){
8381 this.mimicing = false;
8382 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8385 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8387 * @cfg {String} triggerClass A CSS class to apply to the trigger
8390 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8394 /** @cfg {Boolean} grow @hide */
8395 /** @cfg {Number} growMin @hide */
8396 /** @cfg {Number} growMax @hide */
8402 autoSize: Roo.emptyFn,
8409 actionMode : 'wrap',
8414 getAutoCreate : function(){
8416 var align = this.labelAlign || this.parentLabelAlign();
8421 cls: 'form-group' //input-group
8428 type : this.inputType,
8429 cls : 'form-control',
8430 autocomplete: 'new-password',
8431 placeholder : this.placeholder || ''
8435 input.name = this.name;
8438 input.cls += ' input-' + this.size;
8441 if (this.disabled) {
8442 input.disabled=true;
8445 var inputblock = input;
8447 if(this.hasFeedback && !this.allowBlank){
8451 cls: 'glyphicon form-control-feedback'
8455 cls : 'has-feedback',
8463 if (this.before || this.after) {
8466 cls : 'input-group',
8470 inputblock.cn.push({
8472 cls : 'input-group-addon',
8477 inputblock.cn.push(input);
8479 if(this.hasFeedback && !this.allowBlank){
8480 inputblock.cls += ' has-feedback';
8481 inputblock.cn.push(feedback);
8485 inputblock.cn.push({
8487 cls : 'input-group-addon',
8500 cls: 'form-hidden-field'
8508 Roo.log('multiple');
8516 cls: 'form-hidden-field'
8520 cls: 'select2-choices',
8524 cls: 'select2-search-field',
8537 cls: 'select2-container input-group',
8542 // cls: 'typeahead typeahead-long dropdown-menu',
8543 // style: 'display:none'
8548 if(!this.multiple && this.showToggleBtn){
8554 if (this.caret != false) {
8557 cls: 'fa fa-' + this.caret
8564 cls : 'input-group-addon btn dropdown-toggle',
8569 cls: 'combobox-clear',
8583 combobox.cls += ' select2-container-multi';
8586 if (align ==='left' && this.fieldLabel.length) {
8588 Roo.log("left and has label");
8594 cls : 'control-label col-sm-' + this.labelWidth,
8595 html : this.fieldLabel
8599 cls : "col-sm-" + (12 - this.labelWidth),
8606 } else if ( this.fieldLabel.length) {
8612 //cls : 'input-group-addon',
8613 html : this.fieldLabel
8623 Roo.log(" no label && no align");
8630 ['xs','sm','md','lg'].map(function(size){
8631 if (settings[size]) {
8632 cfg.cls += ' col-' + size + '-' + settings[size];
8643 onResize : function(w, h){
8644 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8645 // if(typeof w == 'number'){
8646 // var x = w - this.trigger.getWidth();
8647 // this.inputEl().setWidth(this.adjustWidth('input', x));
8648 // this.trigger.setStyle('left', x+'px');
8653 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8656 getResizeEl : function(){
8657 return this.inputEl();
8661 getPositionEl : function(){
8662 return this.inputEl();
8666 alignErrorIcon : function(){
8667 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8671 initEvents : function(){
8675 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8676 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8677 if(!this.multiple && this.showToggleBtn){
8678 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8679 if(this.hideTrigger){
8680 this.trigger.setDisplayed(false);
8682 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8686 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8689 //this.trigger.addClassOnOver('x-form-trigger-over');
8690 //this.trigger.addClassOnClick('x-form-trigger-click');
8693 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8697 createList : function()
8699 this.list = Roo.get(document.body).createChild({
8701 cls: 'typeahead typeahead-long dropdown-menu',
8702 style: 'display:none'
8705 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8710 initTrigger : function(){
8715 onDestroy : function(){
8717 this.trigger.removeAllListeners();
8718 // this.trigger.remove();
8721 // this.wrap.remove();
8723 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8727 onFocus : function(){
8728 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8731 this.wrap.addClass('x-trigger-wrap-focus');
8732 this.mimicing = true;
8733 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8734 if(this.monitorTab){
8735 this.el.on("keydown", this.checkTab, this);
8742 checkTab : function(e){
8743 if(e.getKey() == e.TAB){
8749 onBlur : function(){
8754 mimicBlur : function(e, t){
8756 if(!this.wrap.contains(t) && this.validateBlur()){
8763 triggerBlur : function(){
8764 this.mimicing = false;
8765 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8766 if(this.monitorTab){
8767 this.el.un("keydown", this.checkTab, this);
8769 //this.wrap.removeClass('x-trigger-wrap-focus');
8770 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8774 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8775 validateBlur : function(e, t){
8780 onDisable : function(){
8781 this.inputEl().dom.disabled = true;
8782 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8784 // this.wrap.addClass('x-item-disabled');
8789 onEnable : function(){
8790 this.inputEl().dom.disabled = false;
8791 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8793 // this.el.removeClass('x-item-disabled');
8798 onShow : function(){
8799 var ae = this.getActionEl();
8802 ae.dom.style.display = '';
8803 ae.dom.style.visibility = 'visible';
8809 onHide : function(){
8810 var ae = this.getActionEl();
8811 ae.dom.style.display = 'none';
8815 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8816 * by an implementing function.
8818 * @param {EventObject} e
8820 onTriggerClick : Roo.emptyFn
8824 * Ext JS Library 1.1.1
8825 * Copyright(c) 2006-2007, Ext JS, LLC.
8827 * Originally Released Under LGPL - original licence link has changed is not relivant.
8830 * <script type="text/javascript">
8835 * @class Roo.data.SortTypes
8837 * Defines the default sorting (casting?) comparison functions used when sorting data.
8839 Roo.data.SortTypes = {
8841 * Default sort that does nothing
8842 * @param {Mixed} s The value being converted
8843 * @return {Mixed} The comparison value
8850 * The regular expression used to strip tags
8854 stripTagsRE : /<\/?[^>]+>/gi,
8857 * Strips all HTML tags to sort on text only
8858 * @param {Mixed} s The value being converted
8859 * @return {String} The comparison value
8861 asText : function(s){
8862 return String(s).replace(this.stripTagsRE, "");
8866 * Strips all HTML tags to sort on text only - Case insensitive
8867 * @param {Mixed} s The value being converted
8868 * @return {String} The comparison value
8870 asUCText : function(s){
8871 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8875 * Case insensitive string
8876 * @param {Mixed} s The value being converted
8877 * @return {String} The comparison value
8879 asUCString : function(s) {
8880 return String(s).toUpperCase();
8885 * @param {Mixed} s The value being converted
8886 * @return {Number} The comparison value
8888 asDate : function(s) {
8892 if(s instanceof Date){
8895 return Date.parse(String(s));
8900 * @param {Mixed} s The value being converted
8901 * @return {Float} The comparison value
8903 asFloat : function(s) {
8904 var val = parseFloat(String(s).replace(/,/g, ""));
8905 if(isNaN(val)) val = 0;
8911 * @param {Mixed} s The value being converted
8912 * @return {Number} The comparison value
8914 asInt : function(s) {
8915 var val = parseInt(String(s).replace(/,/g, ""));
8916 if(isNaN(val)) val = 0;
8921 * Ext JS Library 1.1.1
8922 * Copyright(c) 2006-2007, Ext JS, LLC.
8924 * Originally Released Under LGPL - original licence link has changed is not relivant.
8927 * <script type="text/javascript">
8931 * @class Roo.data.Record
8932 * Instances of this class encapsulate both record <em>definition</em> information, and record
8933 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8934 * to access Records cached in an {@link Roo.data.Store} object.<br>
8936 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8937 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8940 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8942 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8943 * {@link #create}. The parameters are the same.
8944 * @param {Array} data An associative Array of data values keyed by the field name.
8945 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8946 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8947 * not specified an integer id is generated.
8949 Roo.data.Record = function(data, id){
8950 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8955 * Generate a constructor for a specific record layout.
8956 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8957 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8958 * Each field definition object may contain the following properties: <ul>
8959 * <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,
8960 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8961 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8962 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8963 * is being used, then this is a string containing the javascript expression to reference the data relative to
8964 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8965 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8966 * this may be omitted.</p></li>
8967 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8968 * <ul><li>auto (Default, implies no conversion)</li>
8973 * <li>date</li></ul></p></li>
8974 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8975 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8976 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8977 * by the Reader into an object that will be stored in the Record. It is passed the
8978 * following parameters:<ul>
8979 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8981 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8983 * <br>usage:<br><pre><code>
8984 var TopicRecord = Roo.data.Record.create(
8985 {name: 'title', mapping: 'topic_title'},
8986 {name: 'author', mapping: 'username'},
8987 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8988 {name: 'lastPost', mapping: 'post_time', type: 'date'},
8989 {name: 'lastPoster', mapping: 'user2'},
8990 {name: 'excerpt', mapping: 'post_text'}
8993 var myNewRecord = new TopicRecord({
8994 title: 'Do my job please',
8997 lastPost: new Date(),
8998 lastPoster: 'Animal',
8999 excerpt: 'No way dude!'
9001 myStore.add(myNewRecord);
9006 Roo.data.Record.create = function(o){
9008 f.superclass.constructor.apply(this, arguments);
9010 Roo.extend(f, Roo.data.Record);
9011 var p = f.prototype;
9012 p.fields = new Roo.util.MixedCollection(false, function(field){
9015 for(var i = 0, len = o.length; i < len; i++){
9016 p.fields.add(new Roo.data.Field(o[i]));
9018 f.getField = function(name){
9019 return p.fields.get(name);
9024 Roo.data.Record.AUTO_ID = 1000;
9025 Roo.data.Record.EDIT = 'edit';
9026 Roo.data.Record.REJECT = 'reject';
9027 Roo.data.Record.COMMIT = 'commit';
9029 Roo.data.Record.prototype = {
9031 * Readonly flag - true if this record has been modified.
9040 join : function(store){
9045 * Set the named field to the specified value.
9046 * @param {String} name The name of the field to set.
9047 * @param {Object} value The value to set the field to.
9049 set : function(name, value){
9050 if(this.data[name] == value){
9057 if(typeof this.modified[name] == 'undefined'){
9058 this.modified[name] = this.data[name];
9060 this.data[name] = value;
9061 if(!this.editing && this.store){
9062 this.store.afterEdit(this);
9067 * Get the value of the named field.
9068 * @param {String} name The name of the field to get the value of.
9069 * @return {Object} The value of the field.
9071 get : function(name){
9072 return this.data[name];
9076 beginEdit : function(){
9077 this.editing = true;
9082 cancelEdit : function(){
9083 this.editing = false;
9084 delete this.modified;
9088 endEdit : function(){
9089 this.editing = false;
9090 if(this.dirty && this.store){
9091 this.store.afterEdit(this);
9096 * Usually called by the {@link Roo.data.Store} which owns the Record.
9097 * Rejects all changes made to the Record since either creation, or the last commit operation.
9098 * Modified fields are reverted to their original values.
9100 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9101 * of reject operations.
9103 reject : function(){
9104 var m = this.modified;
9106 if(typeof m[n] != "function"){
9107 this.data[n] = m[n];
9111 delete this.modified;
9112 this.editing = false;
9114 this.store.afterReject(this);
9119 * Usually called by the {@link Roo.data.Store} which owns the Record.
9120 * Commits all changes made to the Record since either creation, or the last commit operation.
9122 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9123 * of commit operations.
9125 commit : function(){
9127 delete this.modified;
9128 this.editing = false;
9130 this.store.afterCommit(this);
9135 hasError : function(){
9136 return this.error != null;
9140 clearError : function(){
9145 * Creates a copy of this record.
9146 * @param {String} id (optional) A new record id if you don't want to use this record's id
9149 copy : function(newId) {
9150 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9154 * Ext JS Library 1.1.1
9155 * Copyright(c) 2006-2007, Ext JS, LLC.
9157 * Originally Released Under LGPL - original licence link has changed is not relivant.
9160 * <script type="text/javascript">
9166 * @class Roo.data.Store
9167 * @extends Roo.util.Observable
9168 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9169 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9171 * 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
9172 * has no knowledge of the format of the data returned by the Proxy.<br>
9174 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9175 * instances from the data object. These records are cached and made available through accessor functions.
9177 * Creates a new Store.
9178 * @param {Object} config A config object containing the objects needed for the Store to access data,
9179 * and read the data into Records.
9181 Roo.data.Store = function(config){
9182 this.data = new Roo.util.MixedCollection(false);
9183 this.data.getKey = function(o){
9186 this.baseParams = {};
9193 "multisort" : "_multisort"
9196 if(config && config.data){
9197 this.inlineData = config.data;
9201 Roo.apply(this, config);
9203 if(this.reader){ // reader passed
9204 this.reader = Roo.factory(this.reader, Roo.data);
9205 this.reader.xmodule = this.xmodule || false;
9206 if(!this.recordType){
9207 this.recordType = this.reader.recordType;
9209 if(this.reader.onMetaChange){
9210 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9214 if(this.recordType){
9215 this.fields = this.recordType.prototype.fields;
9221 * @event datachanged
9222 * Fires when the data cache has changed, and a widget which is using this Store
9223 * as a Record cache should refresh its view.
9224 * @param {Store} this
9229 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9230 * @param {Store} this
9231 * @param {Object} meta The JSON metadata
9236 * Fires when Records have been added to the Store
9237 * @param {Store} this
9238 * @param {Roo.data.Record[]} records The array of Records added
9239 * @param {Number} index The index at which the record(s) were added
9244 * Fires when a Record has been removed from the Store
9245 * @param {Store} this
9246 * @param {Roo.data.Record} record The Record that was removed
9247 * @param {Number} index The index at which the record was removed
9252 * Fires when a Record has been updated
9253 * @param {Store} this
9254 * @param {Roo.data.Record} record The Record that was updated
9255 * @param {String} operation The update operation being performed. Value may be one of:
9257 Roo.data.Record.EDIT
9258 Roo.data.Record.REJECT
9259 Roo.data.Record.COMMIT
9265 * Fires when the data cache has been cleared.
9266 * @param {Store} this
9271 * Fires before a request is made for a new data object. If the beforeload handler returns false
9272 * the load action will be canceled.
9273 * @param {Store} this
9274 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9278 * @event beforeloadadd
9279 * Fires after a new set of Records has been loaded.
9280 * @param {Store} this
9281 * @param {Roo.data.Record[]} records The Records that were loaded
9282 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9284 beforeloadadd : true,
9287 * Fires after a new set of Records has been loaded, before they are added to the store.
9288 * @param {Store} this
9289 * @param {Roo.data.Record[]} records The Records that were loaded
9290 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9291 * @params {Object} return from reader
9295 * @event loadexception
9296 * Fires if an exception occurs in the Proxy during loading.
9297 * Called with the signature of the Proxy's "loadexception" event.
9298 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9301 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9302 * @param {Object} load options
9303 * @param {Object} jsonData from your request (normally this contains the Exception)
9305 loadexception : true
9309 this.proxy = Roo.factory(this.proxy, Roo.data);
9310 this.proxy.xmodule = this.xmodule || false;
9311 this.relayEvents(this.proxy, ["loadexception"]);
9313 this.sortToggle = {};
9314 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9316 Roo.data.Store.superclass.constructor.call(this);
9318 if(this.inlineData){
9319 this.loadData(this.inlineData);
9320 delete this.inlineData;
9324 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9326 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9327 * without a remote query - used by combo/forms at present.
9331 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9334 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9337 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9338 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9341 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9342 * on any HTTP request
9345 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9348 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9352 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9353 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9358 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9359 * loaded or when a record is removed. (defaults to false).
9361 pruneModifiedRecords : false,
9367 * Add Records to the Store and fires the add event.
9368 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9370 add : function(records){
9371 records = [].concat(records);
9372 for(var i = 0, len = records.length; i < len; i++){
9373 records[i].join(this);
9375 var index = this.data.length;
9376 this.data.addAll(records);
9377 this.fireEvent("add", this, records, index);
9381 * Remove a Record from the Store and fires the remove event.
9382 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9384 remove : function(record){
9385 var index = this.data.indexOf(record);
9386 this.data.removeAt(index);
9387 if(this.pruneModifiedRecords){
9388 this.modified.remove(record);
9390 this.fireEvent("remove", this, record, index);
9394 * Remove all Records from the Store and fires the clear event.
9396 removeAll : function(){
9398 if(this.pruneModifiedRecords){
9401 this.fireEvent("clear", this);
9405 * Inserts Records to the Store at the given index and fires the add event.
9406 * @param {Number} index The start index at which to insert the passed Records.
9407 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9409 insert : function(index, records){
9410 records = [].concat(records);
9411 for(var i = 0, len = records.length; i < len; i++){
9412 this.data.insert(index, records[i]);
9413 records[i].join(this);
9415 this.fireEvent("add", this, records, index);
9419 * Get the index within the cache of the passed Record.
9420 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9421 * @return {Number} The index of the passed Record. Returns -1 if not found.
9423 indexOf : function(record){
9424 return this.data.indexOf(record);
9428 * Get the index within the cache of the Record with the passed id.
9429 * @param {String} id The id of the Record to find.
9430 * @return {Number} The index of the Record. Returns -1 if not found.
9432 indexOfId : function(id){
9433 return this.data.indexOfKey(id);
9437 * Get the Record with the specified id.
9438 * @param {String} id The id of the Record to find.
9439 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9441 getById : function(id){
9442 return this.data.key(id);
9446 * Get the Record at the specified index.
9447 * @param {Number} index The index of the Record to find.
9448 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9450 getAt : function(index){
9451 return this.data.itemAt(index);
9455 * Returns a range of Records between specified indices.
9456 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9457 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9458 * @return {Roo.data.Record[]} An array of Records
9460 getRange : function(start, end){
9461 return this.data.getRange(start, end);
9465 storeOptions : function(o){
9466 o = Roo.apply({}, o);
9469 this.lastOptions = o;
9473 * Loads the Record cache from the configured Proxy using the configured Reader.
9475 * If using remote paging, then the first load call must specify the <em>start</em>
9476 * and <em>limit</em> properties in the options.params property to establish the initial
9477 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9479 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9480 * and this call will return before the new data has been loaded. Perform any post-processing
9481 * in a callback function, or in a "load" event handler.</strong>
9483 * @param {Object} options An object containing properties which control loading options:<ul>
9484 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9485 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9486 * passed the following arguments:<ul>
9487 * <li>r : Roo.data.Record[]</li>
9488 * <li>options: Options object from the load call</li>
9489 * <li>success: Boolean success indicator</li></ul></li>
9490 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9491 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9494 load : function(options){
9495 options = options || {};
9496 if(this.fireEvent("beforeload", this, options) !== false){
9497 this.storeOptions(options);
9498 var p = Roo.apply(options.params || {}, this.baseParams);
9499 // if meta was not loaded from remote source.. try requesting it.
9500 if (!this.reader.metaFromRemote) {
9503 if(this.sortInfo && this.remoteSort){
9504 var pn = this.paramNames;
9505 p[pn["sort"]] = this.sortInfo.field;
9506 p[pn["dir"]] = this.sortInfo.direction;
9508 if (this.multiSort) {
9509 var pn = this.paramNames;
9510 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9513 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9518 * Reloads the Record cache from the configured Proxy using the configured Reader and
9519 * the options from the last load operation performed.
9520 * @param {Object} options (optional) An object containing properties which may override the options
9521 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9522 * the most recently used options are reused).
9524 reload : function(options){
9525 this.load(Roo.applyIf(options||{}, this.lastOptions));
9529 // Called as a callback by the Reader during a load operation.
9530 loadRecords : function(o, options, success){
9531 if(!o || success === false){
9532 if(success !== false){
9533 this.fireEvent("load", this, [], options, o);
9535 if(options.callback){
9536 options.callback.call(options.scope || this, [], options, false);
9540 // if data returned failure - throw an exception.
9541 if (o.success === false) {
9542 // show a message if no listener is registered.
9543 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9544 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9546 // loadmask wil be hooked into this..
9547 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9550 var r = o.records, t = o.totalRecords || r.length;
9552 this.fireEvent("beforeloadadd", this, r, options, o);
9554 if(!options || options.add !== true){
9555 if(this.pruneModifiedRecords){
9558 for(var i = 0, len = r.length; i < len; i++){
9562 this.data = this.snapshot;
9563 delete this.snapshot;
9566 this.data.addAll(r);
9567 this.totalLength = t;
9569 this.fireEvent("datachanged", this);
9571 this.totalLength = Math.max(t, this.data.length+r.length);
9574 this.fireEvent("load", this, r, options, o);
9575 if(options.callback){
9576 options.callback.call(options.scope || this, r, options, true);
9582 * Loads data from a passed data block. A Reader which understands the format of the data
9583 * must have been configured in the constructor.
9584 * @param {Object} data The data block from which to read the Records. The format of the data expected
9585 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9586 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9588 loadData : function(o, append){
9589 var r = this.reader.readRecords(o);
9590 this.loadRecords(r, {add: append}, true);
9594 * Gets the number of cached records.
9596 * <em>If using paging, this may not be the total size of the dataset. If the data object
9597 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9598 * the data set size</em>
9600 getCount : function(){
9601 return this.data.length || 0;
9605 * Gets the total number of records in the dataset as returned by the server.
9607 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9608 * the dataset size</em>
9610 getTotalCount : function(){
9611 return this.totalLength || 0;
9615 * Returns the sort state of the Store as an object with two properties:
9617 field {String} The name of the field by which the Records are sorted
9618 direction {String} The sort order, "ASC" or "DESC"
9621 getSortState : function(){
9622 return this.sortInfo;
9626 applySort : function(){
9627 if(this.sortInfo && !this.remoteSort){
9628 var s = this.sortInfo, f = s.field;
9629 var st = this.fields.get(f).sortType;
9630 var fn = function(r1, r2){
9631 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9632 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9634 this.data.sort(s.direction, fn);
9635 if(this.snapshot && this.snapshot != this.data){
9636 this.snapshot.sort(s.direction, fn);
9642 * Sets the default sort column and order to be used by the next load operation.
9643 * @param {String} fieldName The name of the field to sort by.
9644 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9646 setDefaultSort : function(field, dir){
9647 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9652 * If remote sorting is used, the sort is performed on the server, and the cache is
9653 * reloaded. If local sorting is used, the cache is sorted internally.
9654 * @param {String} fieldName The name of the field to sort by.
9655 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9657 sort : function(fieldName, dir){
9658 var f = this.fields.get(fieldName);
9660 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9662 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9663 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9668 this.sortToggle[f.name] = dir;
9669 this.sortInfo = {field: f.name, direction: dir};
9670 if(!this.remoteSort){
9672 this.fireEvent("datachanged", this);
9674 this.load(this.lastOptions);
9679 * Calls the specified function for each of the Records in the cache.
9680 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9681 * Returning <em>false</em> aborts and exits the iteration.
9682 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9684 each : function(fn, scope){
9685 this.data.each(fn, scope);
9689 * Gets all records modified since the last commit. Modified records are persisted across load operations
9690 * (e.g., during paging).
9691 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9693 getModifiedRecords : function(){
9694 return this.modified;
9698 createFilterFn : function(property, value, anyMatch){
9699 if(!value.exec){ // not a regex
9700 value = String(value);
9701 if(value.length == 0){
9704 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9707 return value.test(r.data[property]);
9712 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9713 * @param {String} property A field on your records
9714 * @param {Number} start The record index to start at (defaults to 0)
9715 * @param {Number} end The last record index to include (defaults to length - 1)
9716 * @return {Number} The sum
9718 sum : function(property, start, end){
9719 var rs = this.data.items, v = 0;
9721 end = (end || end === 0) ? end : rs.length-1;
9723 for(var i = start; i <= end; i++){
9724 v += (rs[i].data[property] || 0);
9730 * Filter the records by a specified property.
9731 * @param {String} field A field on your records
9732 * @param {String/RegExp} value Either a string that the field
9733 * should start with or a RegExp to test against the field
9734 * @param {Boolean} anyMatch True to match any part not just the beginning
9736 filter : function(property, value, anyMatch){
9737 var fn = this.createFilterFn(property, value, anyMatch);
9738 return fn ? this.filterBy(fn) : this.clearFilter();
9742 * Filter by a function. The specified function will be called with each
9743 * record in this data source. If the function returns true the record is included,
9744 * otherwise it is filtered.
9745 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9746 * @param {Object} scope (optional) The scope of the function (defaults to this)
9748 filterBy : function(fn, scope){
9749 this.snapshot = this.snapshot || this.data;
9750 this.data = this.queryBy(fn, scope||this);
9751 this.fireEvent("datachanged", this);
9755 * Query the records by a specified property.
9756 * @param {String} field A field on your records
9757 * @param {String/RegExp} value Either a string that the field
9758 * should start with or a RegExp to test against the field
9759 * @param {Boolean} anyMatch True to match any part not just the beginning
9760 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9762 query : function(property, value, anyMatch){
9763 var fn = this.createFilterFn(property, value, anyMatch);
9764 return fn ? this.queryBy(fn) : this.data.clone();
9768 * Query by a function. The specified function will be called with each
9769 * record in this data source. If the function returns true the record is included
9771 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9772 * @param {Object} scope (optional) The scope of the function (defaults to this)
9773 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9775 queryBy : function(fn, scope){
9776 var data = this.snapshot || this.data;
9777 return data.filterBy(fn, scope||this);
9781 * Collects unique values for a particular dataIndex from this store.
9782 * @param {String} dataIndex The property to collect
9783 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9784 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9785 * @return {Array} An array of the unique values
9787 collect : function(dataIndex, allowNull, bypassFilter){
9788 var d = (bypassFilter === true && this.snapshot) ?
9789 this.snapshot.items : this.data.items;
9790 var v, sv, r = [], l = {};
9791 for(var i = 0, len = d.length; i < len; i++){
9792 v = d[i].data[dataIndex];
9794 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9803 * Revert to a view of the Record cache with no filtering applied.
9804 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9806 clearFilter : function(suppressEvent){
9807 if(this.snapshot && this.snapshot != this.data){
9808 this.data = this.snapshot;
9809 delete this.snapshot;
9810 if(suppressEvent !== true){
9811 this.fireEvent("datachanged", this);
9817 afterEdit : function(record){
9818 if(this.modified.indexOf(record) == -1){
9819 this.modified.push(record);
9821 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9825 afterReject : function(record){
9826 this.modified.remove(record);
9827 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9831 afterCommit : function(record){
9832 this.modified.remove(record);
9833 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9837 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9838 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9840 commitChanges : function(){
9841 var m = this.modified.slice(0);
9843 for(var i = 0, len = m.length; i < len; i++){
9849 * Cancel outstanding changes on all changed records.
9851 rejectChanges : function(){
9852 var m = this.modified.slice(0);
9854 for(var i = 0, len = m.length; i < len; i++){
9859 onMetaChange : function(meta, rtype, o){
9860 this.recordType = rtype;
9861 this.fields = rtype.prototype.fields;
9862 delete this.snapshot;
9863 this.sortInfo = meta.sortInfo || this.sortInfo;
9865 this.fireEvent('metachange', this, this.reader.meta);
9868 moveIndex : function(data, type)
9870 var index = this.indexOf(data);
9872 var newIndex = index + type;
9876 this.insert(newIndex, data);
9881 * Ext JS Library 1.1.1
9882 * Copyright(c) 2006-2007, Ext JS, LLC.
9884 * Originally Released Under LGPL - original licence link has changed is not relivant.
9887 * <script type="text/javascript">
9891 * @class Roo.data.SimpleStore
9892 * @extends Roo.data.Store
9893 * Small helper class to make creating Stores from Array data easier.
9894 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9895 * @cfg {Array} fields An array of field definition objects, or field name strings.
9896 * @cfg {Array} data The multi-dimensional array of data
9898 * @param {Object} config
9900 Roo.data.SimpleStore = function(config){
9901 Roo.data.SimpleStore.superclass.constructor.call(this, {
9903 reader: new Roo.data.ArrayReader({
9906 Roo.data.Record.create(config.fields)
9908 proxy : new Roo.data.MemoryProxy(config.data)
9912 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9914 * Ext JS Library 1.1.1
9915 * Copyright(c) 2006-2007, Ext JS, LLC.
9917 * Originally Released Under LGPL - original licence link has changed is not relivant.
9920 * <script type="text/javascript">
9925 * @extends Roo.data.Store
9926 * @class Roo.data.JsonStore
9927 * Small helper class to make creating Stores for JSON data easier. <br/>
9929 var store = new Roo.data.JsonStore({
9930 url: 'get-images.php',
9932 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9935 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9936 * JsonReader and HttpProxy (unless inline data is provided).</b>
9937 * @cfg {Array} fields An array of field definition objects, or field name strings.
9939 * @param {Object} config
9941 Roo.data.JsonStore = function(c){
9942 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9943 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9944 reader: new Roo.data.JsonReader(c, c.fields)
9947 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9949 * Ext JS Library 1.1.1
9950 * Copyright(c) 2006-2007, Ext JS, LLC.
9952 * Originally Released Under LGPL - original licence link has changed is not relivant.
9955 * <script type="text/javascript">
9959 Roo.data.Field = function(config){
9960 if(typeof config == "string"){
9961 config = {name: config};
9963 Roo.apply(this, config);
9969 var st = Roo.data.SortTypes;
9970 // named sortTypes are supported, here we look them up
9971 if(typeof this.sortType == "string"){
9972 this.sortType = st[this.sortType];
9975 // set default sortType for strings and dates
9979 this.sortType = st.asUCString;
9982 this.sortType = st.asDate;
9985 this.sortType = st.none;
9990 var stripRe = /[\$,%]/g;
9992 // prebuilt conversion function for this field, instead of
9993 // switching every time we're reading a value
9995 var cv, dateFormat = this.dateFormat;
10000 cv = function(v){ return v; };
10003 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10007 return v !== undefined && v !== null && v !== '' ?
10008 parseInt(String(v).replace(stripRe, ""), 10) : '';
10013 return v !== undefined && v !== null && v !== '' ?
10014 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10019 cv = function(v){ return v === true || v === "true" || v == 1; };
10026 if(v instanceof Date){
10030 if(dateFormat == "timestamp"){
10031 return new Date(v*1000);
10033 return Date.parseDate(v, dateFormat);
10035 var parsed = Date.parse(v);
10036 return parsed ? new Date(parsed) : null;
10045 Roo.data.Field.prototype = {
10053 * Ext JS Library 1.1.1
10054 * Copyright(c) 2006-2007, Ext JS, LLC.
10056 * Originally Released Under LGPL - original licence link has changed is not relivant.
10059 * <script type="text/javascript">
10062 // Base class for reading structured data from a data source. This class is intended to be
10063 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10066 * @class Roo.data.DataReader
10067 * Base class for reading structured data from a data source. This class is intended to be
10068 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10071 Roo.data.DataReader = function(meta, recordType){
10075 this.recordType = recordType instanceof Array ?
10076 Roo.data.Record.create(recordType) : recordType;
10079 Roo.data.DataReader.prototype = {
10081 * Create an empty record
10082 * @param {Object} data (optional) - overlay some values
10083 * @return {Roo.data.Record} record created.
10085 newRow : function(d) {
10087 this.recordType.prototype.fields.each(function(c) {
10089 case 'int' : da[c.name] = 0; break;
10090 case 'date' : da[c.name] = new Date(); break;
10091 case 'float' : da[c.name] = 0.0; break;
10092 case 'boolean' : da[c.name] = false; break;
10093 default : da[c.name] = ""; break;
10097 return new this.recordType(Roo.apply(da, d));
10102 * Ext JS Library 1.1.1
10103 * Copyright(c) 2006-2007, Ext JS, LLC.
10105 * Originally Released Under LGPL - original licence link has changed is not relivant.
10108 * <script type="text/javascript">
10112 * @class Roo.data.DataProxy
10113 * @extends Roo.data.Observable
10114 * This class is an abstract base class for implementations which provide retrieval of
10115 * unformatted data objects.<br>
10117 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10118 * (of the appropriate type which knows how to parse the data object) to provide a block of
10119 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10121 * Custom implementations must implement the load method as described in
10122 * {@link Roo.data.HttpProxy#load}.
10124 Roo.data.DataProxy = function(){
10127 * @event beforeload
10128 * Fires before a network request is made to retrieve a data object.
10129 * @param {Object} This DataProxy object.
10130 * @param {Object} params The params parameter to the load function.
10135 * Fires before the load method's callback is called.
10136 * @param {Object} This DataProxy object.
10137 * @param {Object} o The data object.
10138 * @param {Object} arg The callback argument object passed to the load function.
10142 * @event loadexception
10143 * Fires if an Exception occurs during data retrieval.
10144 * @param {Object} This DataProxy object.
10145 * @param {Object} o The data object.
10146 * @param {Object} arg The callback argument object passed to the load function.
10147 * @param {Object} e The Exception.
10149 loadexception : true
10151 Roo.data.DataProxy.superclass.constructor.call(this);
10154 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10157 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10161 * Ext JS Library 1.1.1
10162 * Copyright(c) 2006-2007, Ext JS, LLC.
10164 * Originally Released Under LGPL - original licence link has changed is not relivant.
10167 * <script type="text/javascript">
10170 * @class Roo.data.MemoryProxy
10171 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10172 * to the Reader when its load method is called.
10174 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10176 Roo.data.MemoryProxy = function(data){
10180 Roo.data.MemoryProxy.superclass.constructor.call(this);
10184 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10186 * Load data from the requested source (in this case an in-memory
10187 * data object passed to the constructor), read the data object into
10188 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10189 * process that block using the passed callback.
10190 * @param {Object} params This parameter is not used by the MemoryProxy class.
10191 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10192 * object into a block of Roo.data.Records.
10193 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10194 * The function must be passed <ul>
10195 * <li>The Record block object</li>
10196 * <li>The "arg" argument from the load function</li>
10197 * <li>A boolean success indicator</li>
10199 * @param {Object} scope The scope in which to call the callback
10200 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10202 load : function(params, reader, callback, scope, arg){
10203 params = params || {};
10206 result = reader.readRecords(this.data);
10208 this.fireEvent("loadexception", this, arg, null, e);
10209 callback.call(scope, null, arg, false);
10212 callback.call(scope, result, arg, true);
10216 update : function(params, records){
10221 * Ext JS Library 1.1.1
10222 * Copyright(c) 2006-2007, Ext JS, LLC.
10224 * Originally Released Under LGPL - original licence link has changed is not relivant.
10227 * <script type="text/javascript">
10230 * @class Roo.data.HttpProxy
10231 * @extends Roo.data.DataProxy
10232 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10233 * configured to reference a certain URL.<br><br>
10235 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10236 * from which the running page was served.<br><br>
10238 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10240 * Be aware that to enable the browser to parse an XML document, the server must set
10241 * the Content-Type header in the HTTP response to "text/xml".
10243 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10244 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10245 * will be used to make the request.
10247 Roo.data.HttpProxy = function(conn){
10248 Roo.data.HttpProxy.superclass.constructor.call(this);
10249 // is conn a conn config or a real conn?
10251 this.useAjax = !conn || !conn.events;
10255 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10256 // thse are take from connection...
10259 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10262 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10263 * extra parameters to each request made by this object. (defaults to undefined)
10266 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10267 * to each request made by this object. (defaults to undefined)
10270 * @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)
10273 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10276 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10282 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10286 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10287 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10288 * a finer-grained basis than the DataProxy events.
10290 getConnection : function(){
10291 return this.useAjax ? Roo.Ajax : this.conn;
10295 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10296 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10297 * process that block using the passed callback.
10298 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10299 * for the request to the remote server.
10300 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10301 * object into a block of Roo.data.Records.
10302 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10303 * The function must be passed <ul>
10304 * <li>The Record block object</li>
10305 * <li>The "arg" argument from the load function</li>
10306 * <li>A boolean success indicator</li>
10308 * @param {Object} scope The scope in which to call the callback
10309 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10311 load : function(params, reader, callback, scope, arg){
10312 if(this.fireEvent("beforeload", this, params) !== false){
10314 params : params || {},
10316 callback : callback,
10321 callback : this.loadResponse,
10325 Roo.applyIf(o, this.conn);
10326 if(this.activeRequest){
10327 Roo.Ajax.abort(this.activeRequest);
10329 this.activeRequest = Roo.Ajax.request(o);
10331 this.conn.request(o);
10334 callback.call(scope||this, null, arg, false);
10339 loadResponse : function(o, success, response){
10340 delete this.activeRequest;
10342 this.fireEvent("loadexception", this, o, response);
10343 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10348 result = o.reader.read(response);
10350 this.fireEvent("loadexception", this, o, response, e);
10351 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10355 this.fireEvent("load", this, o, o.request.arg);
10356 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10360 update : function(dataSet){
10365 updateResponse : function(dataSet){
10370 * Ext JS Library 1.1.1
10371 * Copyright(c) 2006-2007, Ext JS, LLC.
10373 * Originally Released Under LGPL - original licence link has changed is not relivant.
10376 * <script type="text/javascript">
10380 * @class Roo.data.ScriptTagProxy
10381 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10382 * other than the originating domain of the running page.<br><br>
10384 * <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
10385 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10387 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10388 * source code that is used as the source inside a <script> tag.<br><br>
10390 * In order for the browser to process the returned data, the server must wrap the data object
10391 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10392 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10393 * depending on whether the callback name was passed:
10396 boolean scriptTag = false;
10397 String cb = request.getParameter("callback");
10400 response.setContentType("text/javascript");
10402 response.setContentType("application/x-json");
10404 Writer out = response.getWriter();
10406 out.write(cb + "(");
10408 out.print(dataBlock.toJsonString());
10415 * @param {Object} config A configuration object.
10417 Roo.data.ScriptTagProxy = function(config){
10418 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10419 Roo.apply(this, config);
10420 this.head = document.getElementsByTagName("head")[0];
10423 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10425 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10427 * @cfg {String} url The URL from which to request the data object.
10430 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10434 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10435 * the server the name of the callback function set up by the load call to process the returned data object.
10436 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10437 * javascript output which calls this named function passing the data object as its only parameter.
10439 callbackParam : "callback",
10441 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10442 * name to the request.
10447 * Load data from the configured URL, read the data object into
10448 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10449 * process that block using the passed callback.
10450 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10451 * for the request to the remote server.
10452 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10453 * object into a block of Roo.data.Records.
10454 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10455 * The function must be passed <ul>
10456 * <li>The Record block object</li>
10457 * <li>The "arg" argument from the load function</li>
10458 * <li>A boolean success indicator</li>
10460 * @param {Object} scope The scope in which to call the callback
10461 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10463 load : function(params, reader, callback, scope, arg){
10464 if(this.fireEvent("beforeload", this, params) !== false){
10466 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10468 var url = this.url;
10469 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10471 url += "&_dc=" + (new Date().getTime());
10473 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10476 cb : "stcCallback"+transId,
10477 scriptId : "stcScript"+transId,
10481 callback : callback,
10487 window[trans.cb] = function(o){
10488 conn.handleResponse(o, trans);
10491 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10493 if(this.autoAbort !== false){
10497 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10499 var script = document.createElement("script");
10500 script.setAttribute("src", url);
10501 script.setAttribute("type", "text/javascript");
10502 script.setAttribute("id", trans.scriptId);
10503 this.head.appendChild(script);
10505 this.trans = trans;
10507 callback.call(scope||this, null, arg, false);
10512 isLoading : function(){
10513 return this.trans ? true : false;
10517 * Abort the current server request.
10519 abort : function(){
10520 if(this.isLoading()){
10521 this.destroyTrans(this.trans);
10526 destroyTrans : function(trans, isLoaded){
10527 this.head.removeChild(document.getElementById(trans.scriptId));
10528 clearTimeout(trans.timeoutId);
10530 window[trans.cb] = undefined;
10532 delete window[trans.cb];
10535 // if hasn't been loaded, wait for load to remove it to prevent script error
10536 window[trans.cb] = function(){
10537 window[trans.cb] = undefined;
10539 delete window[trans.cb];
10546 handleResponse : function(o, trans){
10547 this.trans = false;
10548 this.destroyTrans(trans, true);
10551 result = trans.reader.readRecords(o);
10553 this.fireEvent("loadexception", this, o, trans.arg, e);
10554 trans.callback.call(trans.scope||window, null, trans.arg, false);
10557 this.fireEvent("load", this, o, trans.arg);
10558 trans.callback.call(trans.scope||window, result, trans.arg, true);
10562 handleFailure : function(trans){
10563 this.trans = false;
10564 this.destroyTrans(trans, false);
10565 this.fireEvent("loadexception", this, null, trans.arg);
10566 trans.callback.call(trans.scope||window, null, trans.arg, false);
10570 * Ext JS Library 1.1.1
10571 * Copyright(c) 2006-2007, Ext JS, LLC.
10573 * Originally Released Under LGPL - original licence link has changed is not relivant.
10576 * <script type="text/javascript">
10580 * @class Roo.data.JsonReader
10581 * @extends Roo.data.DataReader
10582 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10583 * based on mappings in a provided Roo.data.Record constructor.
10585 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10586 * in the reply previously.
10591 var RecordDef = Roo.data.Record.create([
10592 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10593 {name: 'occupation'} // This field will use "occupation" as the mapping.
10595 var myReader = new Roo.data.JsonReader({
10596 totalProperty: "results", // The property which contains the total dataset size (optional)
10597 root: "rows", // The property which contains an Array of row objects
10598 id: "id" // The property within each row object that provides an ID for the record (optional)
10602 * This would consume a JSON file like this:
10604 { 'results': 2, 'rows': [
10605 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10606 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10609 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10610 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10611 * paged from the remote server.
10612 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10613 * @cfg {String} root name of the property which contains the Array of row objects.
10614 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10616 * Create a new JsonReader
10617 * @param {Object} meta Metadata configuration options
10618 * @param {Object} recordType Either an Array of field definition objects,
10619 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10621 Roo.data.JsonReader = function(meta, recordType){
10624 // set some defaults:
10625 Roo.applyIf(meta, {
10626 totalProperty: 'total',
10627 successProperty : 'success',
10632 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10634 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10637 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10638 * Used by Store query builder to append _requestMeta to params.
10641 metaFromRemote : false,
10643 * This method is only used by a DataProxy which has retrieved data from a remote server.
10644 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10645 * @return {Object} data A data block which is used by an Roo.data.Store object as
10646 * a cache of Roo.data.Records.
10648 read : function(response){
10649 var json = response.responseText;
10651 var o = /* eval:var:o */ eval("("+json+")");
10653 throw {message: "JsonReader.read: Json object not found"};
10659 this.metaFromRemote = true;
10660 this.meta = o.metaData;
10661 this.recordType = Roo.data.Record.create(o.metaData.fields);
10662 this.onMetaChange(this.meta, this.recordType, o);
10664 return this.readRecords(o);
10667 // private function a store will implement
10668 onMetaChange : function(meta, recordType, o){
10675 simpleAccess: function(obj, subsc) {
10682 getJsonAccessor: function(){
10684 return function(expr) {
10686 return(re.test(expr))
10687 ? new Function("obj", "return obj." + expr)
10692 return Roo.emptyFn;
10697 * Create a data block containing Roo.data.Records from an XML document.
10698 * @param {Object} o An object which contains an Array of row objects in the property specified
10699 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10700 * which contains the total size of the dataset.
10701 * @return {Object} data A data block which is used by an Roo.data.Store object as
10702 * a cache of Roo.data.Records.
10704 readRecords : function(o){
10706 * After any data loads, the raw JSON data is available for further custom processing.
10710 var s = this.meta, Record = this.recordType,
10711 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10713 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10715 if(s.totalProperty) {
10716 this.getTotal = this.getJsonAccessor(s.totalProperty);
10718 if(s.successProperty) {
10719 this.getSuccess = this.getJsonAccessor(s.successProperty);
10721 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10723 var g = this.getJsonAccessor(s.id);
10724 this.getId = function(rec) {
10726 return (r === undefined || r === "") ? null : r;
10729 this.getId = function(){return null;};
10732 for(var jj = 0; jj < fl; jj++){
10734 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10735 this.ef[jj] = this.getJsonAccessor(map);
10739 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10740 if(s.totalProperty){
10741 var vt = parseInt(this.getTotal(o), 10);
10746 if(s.successProperty){
10747 var vs = this.getSuccess(o);
10748 if(vs === false || vs === 'false'){
10753 for(var i = 0; i < c; i++){
10756 var id = this.getId(n);
10757 for(var j = 0; j < fl; j++){
10759 var v = this.ef[j](n);
10761 Roo.log('missing convert for ' + f.name);
10765 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10767 var record = new Record(values, id);
10769 records[i] = record;
10775 totalRecords : totalRecords
10780 * Ext JS Library 1.1.1
10781 * Copyright(c) 2006-2007, Ext JS, LLC.
10783 * Originally Released Under LGPL - original licence link has changed is not relivant.
10786 * <script type="text/javascript">
10790 * @class Roo.data.ArrayReader
10791 * @extends Roo.data.DataReader
10792 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10793 * Each element of that Array represents a row of data fields. The
10794 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10795 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10799 var RecordDef = Roo.data.Record.create([
10800 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10801 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10803 var myReader = new Roo.data.ArrayReader({
10804 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10808 * This would consume an Array like this:
10810 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10812 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10814 * Create a new JsonReader
10815 * @param {Object} meta Metadata configuration options.
10816 * @param {Object} recordType Either an Array of field definition objects
10817 * as specified to {@link Roo.data.Record#create},
10818 * or an {@link Roo.data.Record} object
10819 * created using {@link Roo.data.Record#create}.
10821 Roo.data.ArrayReader = function(meta, recordType){
10822 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10825 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10827 * Create a data block containing Roo.data.Records from an XML document.
10828 * @param {Object} o An Array of row objects which represents the dataset.
10829 * @return {Object} data A data block which is used by an Roo.data.Store object as
10830 * a cache of Roo.data.Records.
10832 readRecords : function(o){
10833 var sid = this.meta ? this.meta.id : null;
10834 var recordType = this.recordType, fields = recordType.prototype.fields;
10837 for(var i = 0; i < root.length; i++){
10840 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10841 for(var j = 0, jlen = fields.length; j < jlen; j++){
10842 var f = fields.items[j];
10843 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10844 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10846 values[f.name] = v;
10848 var record = new recordType(values, id);
10850 records[records.length] = record;
10854 totalRecords : records.length
10863 * @class Roo.bootstrap.ComboBox
10864 * @extends Roo.bootstrap.TriggerField
10865 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10866 * @cfg {Boolean} append (true|false) default false
10867 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10868 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10869 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10870 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10871 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10873 * Create a new ComboBox.
10874 * @param {Object} config Configuration options
10876 Roo.bootstrap.ComboBox = function(config){
10877 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10881 * Fires when the dropdown list is expanded
10882 * @param {Roo.bootstrap.ComboBox} combo This combo box
10887 * Fires when the dropdown list is collapsed
10888 * @param {Roo.bootstrap.ComboBox} combo This combo box
10892 * @event beforeselect
10893 * Fires before a list item is selected. Return false to cancel the selection.
10894 * @param {Roo.bootstrap.ComboBox} combo This combo box
10895 * @param {Roo.data.Record} record The data record returned from the underlying store
10896 * @param {Number} index The index of the selected item in the dropdown list
10898 'beforeselect' : true,
10901 * Fires when a list item is selected
10902 * @param {Roo.bootstrap.ComboBox} combo This combo box
10903 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10904 * @param {Number} index The index of the selected item in the dropdown list
10908 * @event beforequery
10909 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10910 * The event object passed has these properties:
10911 * @param {Roo.bootstrap.ComboBox} combo This combo box
10912 * @param {String} query The query
10913 * @param {Boolean} forceAll true to force "all" query
10914 * @param {Boolean} cancel true to cancel the query
10915 * @param {Object} e The query event object
10917 'beforequery': true,
10920 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10921 * @param {Roo.bootstrap.ComboBox} combo This combo box
10926 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10927 * @param {Roo.bootstrap.ComboBox} combo This combo box
10928 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10933 * Fires when the remove value from the combobox array
10934 * @param {Roo.bootstrap.ComboBox} combo This combo box
10938 * @event specialfilter
10939 * Fires when specialfilter
10940 * @param {Roo.bootstrap.ComboBox} combo This combo box
10942 'specialfilter' : true
10947 this.tickItems = [];
10949 this.selectedIndex = -1;
10950 if(this.mode == 'local'){
10951 if(config.queryDelay === undefined){
10952 this.queryDelay = 10;
10954 if(config.minChars === undefined){
10960 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10963 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10964 * rendering into an Roo.Editor, defaults to false)
10967 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10968 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10971 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10974 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10975 * the dropdown list (defaults to undefined, with no header element)
10979 * @cfg {String/Roo.Template} tpl The template to use to render the output
10983 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10985 listWidth: undefined,
10987 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10988 * mode = 'remote' or 'text' if mode = 'local')
10990 displayField: undefined,
10993 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
10994 * mode = 'remote' or 'value' if mode = 'local').
10995 * Note: use of a valueField requires the user make a selection
10996 * in order for a value to be mapped.
10998 valueField: undefined,
11002 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11003 * field's data value (defaults to the underlying DOM element's name)
11005 hiddenName: undefined,
11007 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11011 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11013 selectedClass: 'active',
11016 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11020 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11021 * anchor positions (defaults to 'tl-bl')
11023 listAlign: 'tl-bl?',
11025 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11029 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11030 * query specified by the allQuery config option (defaults to 'query')
11032 triggerAction: 'query',
11034 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11035 * (defaults to 4, does not apply if editable = false)
11039 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11040 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11044 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11045 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11049 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11050 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11054 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11055 * when editable = true (defaults to false)
11057 selectOnFocus:false,
11059 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11061 queryParam: 'query',
11063 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11064 * when mode = 'remote' (defaults to 'Loading...')
11066 loadingText: 'Loading...',
11068 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11072 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11076 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11077 * traditional select (defaults to true)
11081 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11085 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11089 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11090 * listWidth has a higher value)
11094 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11095 * allow the user to set arbitrary text into the field (defaults to false)
11097 forceSelection:false,
11099 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11100 * if typeAhead = true (defaults to 250)
11102 typeAheadDelay : 250,
11104 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11105 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11107 valueNotFoundText : undefined,
11109 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11111 blockFocus : false,
11114 * @cfg {Boolean} disableClear Disable showing of clear button.
11116 disableClear : false,
11118 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11120 alwaysQuery : false,
11123 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11128 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11130 invalidClass : "has-warning",
11133 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11135 validClass : "has-success",
11138 * @cfg {Boolean} specialFilter (true|false) special filter default false
11140 specialFilter : false,
11152 btnPosition : 'right',
11153 triggerList : true,
11154 showToggleBtn : true,
11155 // element that contains real text value.. (when hidden is used..)
11157 getAutoCreate : function()
11164 if(!this.tickable){
11165 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11170 * ComboBox with tickable selections
11173 var align = this.labelAlign || this.parentLabelAlign();
11176 cls : 'form-group roo-combobox-tickable' //input-group
11181 cls : 'tickable-buttons',
11186 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11193 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11200 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11207 buttons.cn.unshift({
11209 cls: 'select2-search-field-input'
11215 Roo.each(buttons.cn, function(c){
11217 c.cls += ' btn-' + _this.size;
11220 if (_this.disabled) {
11231 cls: 'form-hidden-field'
11235 cls: 'select2-choices',
11239 cls: 'select2-search-field',
11251 cls: 'select2-container input-group select2-container-multi',
11256 // cls: 'typeahead typeahead-long dropdown-menu',
11257 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11262 if(this.hasFeedback && !this.allowBlank){
11266 cls: 'glyphicon form-control-feedback'
11269 combobox.cn.push(feedback);
11272 if (align ==='left' && this.fieldLabel.length) {
11274 Roo.log("left and has label");
11280 cls : 'control-label col-sm-' + this.labelWidth,
11281 html : this.fieldLabel
11285 cls : "col-sm-" + (12 - this.labelWidth),
11292 } else if ( this.fieldLabel.length) {
11298 //cls : 'input-group-addon',
11299 html : this.fieldLabel
11309 Roo.log(" no label && no align");
11316 ['xs','sm','md','lg'].map(function(size){
11317 if (settings[size]) {
11318 cfg.cls += ' col-' + size + '-' + settings[size];
11327 initEvents: function()
11331 throw "can not find store for combo";
11333 this.store = Roo.factory(this.store, Roo.data);
11336 this.initTickableEvents();
11340 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11342 if(this.hiddenName){
11344 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11346 this.hiddenField.dom.value =
11347 this.hiddenValue !== undefined ? this.hiddenValue :
11348 this.value !== undefined ? this.value : '';
11350 // prevent input submission
11351 this.el.dom.removeAttribute('name');
11352 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11357 // this.el.dom.setAttribute('autocomplete', 'off');
11360 var cls = 'x-combo-list';
11362 //this.list = new Roo.Layer({
11363 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11369 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11370 _this.list.setWidth(lw);
11373 this.list.on('mouseover', this.onViewOver, this);
11374 this.list.on('mousemove', this.onViewMove, this);
11376 this.list.on('scroll', this.onViewScroll, this);
11379 this.list.swallowEvent('mousewheel');
11380 this.assetHeight = 0;
11383 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11384 this.assetHeight += this.header.getHeight();
11387 this.innerList = this.list.createChild({cls:cls+'-inner'});
11388 this.innerList.on('mouseover', this.onViewOver, this);
11389 this.innerList.on('mousemove', this.onViewMove, this);
11390 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11392 if(this.allowBlank && !this.pageSize && !this.disableClear){
11393 this.footer = this.list.createChild({cls:cls+'-ft'});
11394 this.pageTb = new Roo.Toolbar(this.footer);
11398 this.footer = this.list.createChild({cls:cls+'-ft'});
11399 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11400 {pageSize: this.pageSize});
11404 if (this.pageTb && this.allowBlank && !this.disableClear) {
11406 this.pageTb.add(new Roo.Toolbar.Fill(), {
11407 cls: 'x-btn-icon x-btn-clear',
11409 handler: function()
11412 _this.clearValue();
11413 _this.onSelect(false, -1);
11418 this.assetHeight += this.footer.getHeight();
11423 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11426 this.view = new Roo.View(this.list, this.tpl, {
11427 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11429 //this.view.wrapEl.setDisplayed(false);
11430 this.view.on('click', this.onViewClick, this);
11434 this.store.on('beforeload', this.onBeforeLoad, this);
11435 this.store.on('load', this.onLoad, this);
11436 this.store.on('loadexception', this.onLoadException, this);
11438 if(this.resizable){
11439 this.resizer = new Roo.Resizable(this.list, {
11440 pinned:true, handles:'se'
11442 this.resizer.on('resize', function(r, w, h){
11443 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11444 this.listWidth = w;
11445 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11446 this.restrictHeight();
11448 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11451 if(!this.editable){
11452 this.editable = true;
11453 this.setEditable(false);
11458 if (typeof(this.events.add.listeners) != 'undefined') {
11460 this.addicon = this.wrap.createChild(
11461 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11463 this.addicon.on('click', function(e) {
11464 this.fireEvent('add', this);
11467 if (typeof(this.events.edit.listeners) != 'undefined') {
11469 this.editicon = this.wrap.createChild(
11470 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11471 if (this.addicon) {
11472 this.editicon.setStyle('margin-left', '40px');
11474 this.editicon.on('click', function(e) {
11476 // we fire even if inothing is selected..
11477 this.fireEvent('edit', this, this.lastData );
11483 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11484 "up" : function(e){
11485 this.inKeyMode = true;
11489 "down" : function(e){
11490 if(!this.isExpanded()){
11491 this.onTriggerClick();
11493 this.inKeyMode = true;
11498 "enter" : function(e){
11499 // this.onViewClick();
11503 if(this.fireEvent("specialkey", this, e)){
11504 this.onViewClick(false);
11510 "esc" : function(e){
11514 "tab" : function(e){
11517 if(this.fireEvent("specialkey", this, e)){
11518 this.onViewClick(false);
11526 doRelay : function(foo, bar, hname){
11527 if(hname == 'down' || this.scope.isExpanded()){
11528 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11537 this.queryDelay = Math.max(this.queryDelay || 10,
11538 this.mode == 'local' ? 10 : 250);
11541 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11543 if(this.typeAhead){
11544 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11546 if(this.editable !== false){
11547 this.inputEl().on("keyup", this.onKeyUp, this);
11549 if(this.forceSelection){
11550 this.inputEl().on('blur', this.doForce, this);
11554 this.choices = this.el.select('ul.select2-choices', true).first();
11555 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11559 initTickableEvents: function()
11563 if(this.hiddenName){
11565 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11567 this.hiddenField.dom.value =
11568 this.hiddenValue !== undefined ? this.hiddenValue :
11569 this.value !== undefined ? this.value : '';
11571 // prevent input submission
11572 this.el.dom.removeAttribute('name');
11573 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11578 // this.list = this.el.select('ul.dropdown-menu',true).first();
11580 this.choices = this.el.select('ul.select2-choices', true).first();
11581 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11582 if(this.triggerList){
11583 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11586 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11587 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11589 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11590 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11592 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11593 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11595 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11596 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11597 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11600 this.cancelBtn.hide();
11605 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11606 _this.list.setWidth(lw);
11609 this.list.on('mouseover', this.onViewOver, this);
11610 this.list.on('mousemove', this.onViewMove, this);
11612 this.list.on('scroll', this.onViewScroll, this);
11615 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>';
11618 this.view = new Roo.View(this.list, this.tpl, {
11619 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11622 //this.view.wrapEl.setDisplayed(false);
11623 this.view.on('click', this.onViewClick, this);
11627 this.store.on('beforeload', this.onBeforeLoad, this);
11628 this.store.on('load', this.onLoad, this);
11629 this.store.on('loadexception', this.onLoadException, this);
11632 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11633 "up" : function(e){
11634 this.inKeyMode = true;
11638 "down" : function(e){
11639 this.inKeyMode = true;
11643 "enter" : function(e){
11644 if(this.fireEvent("specialkey", this, e)){
11645 this.onViewClick(false);
11651 "esc" : function(e){
11652 this.onTickableFooterButtonClick(e, false, false);
11655 "tab" : function(e){
11656 this.fireEvent("specialkey", this, e);
11658 this.onTickableFooterButtonClick(e, false, false);
11665 doRelay : function(e, fn, key){
11666 if(this.scope.isExpanded()){
11667 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11676 this.queryDelay = Math.max(this.queryDelay || 10,
11677 this.mode == 'local' ? 10 : 250);
11680 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11682 if(this.typeAhead){
11683 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11686 if(this.editable !== false){
11687 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11692 onDestroy : function(){
11694 this.view.setStore(null);
11695 this.view.el.removeAllListeners();
11696 this.view.el.remove();
11697 this.view.purgeListeners();
11700 this.list.dom.innerHTML = '';
11704 this.store.un('beforeload', this.onBeforeLoad, this);
11705 this.store.un('load', this.onLoad, this);
11706 this.store.un('loadexception', this.onLoadException, this);
11708 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11712 fireKey : function(e){
11713 if(e.isNavKeyPress() && !this.list.isVisible()){
11714 this.fireEvent("specialkey", this, e);
11719 onResize: function(w, h){
11720 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11722 // if(typeof w != 'number'){
11723 // // we do not handle it!?!?
11726 // var tw = this.trigger.getWidth();
11727 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11728 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11730 // this.inputEl().setWidth( this.adjustWidth('input', x));
11732 // //this.trigger.setStyle('left', x+'px');
11734 // if(this.list && this.listWidth === undefined){
11735 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11736 // this.list.setWidth(lw);
11737 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11745 * Allow or prevent the user from directly editing the field text. If false is passed,
11746 * the user will only be able to select from the items defined in the dropdown list. This method
11747 * is the runtime equivalent of setting the 'editable' config option at config time.
11748 * @param {Boolean} value True to allow the user to directly edit the field text
11750 setEditable : function(value){
11751 if(value == this.editable){
11754 this.editable = value;
11756 this.inputEl().dom.setAttribute('readOnly', true);
11757 this.inputEl().on('mousedown', this.onTriggerClick, this);
11758 this.inputEl().addClass('x-combo-noedit');
11760 this.inputEl().dom.setAttribute('readOnly', false);
11761 this.inputEl().un('mousedown', this.onTriggerClick, this);
11762 this.inputEl().removeClass('x-combo-noedit');
11768 onBeforeLoad : function(combo,opts){
11769 if(!this.hasFocus){
11773 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11775 this.restrictHeight();
11776 this.selectedIndex = -1;
11780 onLoad : function(){
11782 this.hasQuery = false;
11784 if(!this.hasFocus){
11788 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11789 this.loading.hide();
11792 if(this.store.getCount() > 0){
11794 this.restrictHeight();
11795 if(this.lastQuery == this.allQuery){
11796 if(this.editable && !this.tickable){
11797 this.inputEl().dom.select();
11801 !this.selectByValue(this.value, true) &&
11804 !this.store.lastOptions ||
11805 typeof(this.store.lastOptions.add) == 'undefined' ||
11806 this.store.lastOptions.add != true
11809 this.select(0, true);
11812 if(this.autoFocus){
11815 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11816 this.taTask.delay(this.typeAheadDelay);
11820 this.onEmptyResults();
11826 onLoadException : function()
11828 this.hasQuery = false;
11830 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11831 this.loading.hide();
11834 if(this.tickable && this.editable){
11840 Roo.log(this.store.reader.jsonData);
11841 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11843 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11849 onTypeAhead : function(){
11850 if(this.store.getCount() > 0){
11851 var r = this.store.getAt(0);
11852 var newValue = r.data[this.displayField];
11853 var len = newValue.length;
11854 var selStart = this.getRawValue().length;
11856 if(selStart != len){
11857 this.setRawValue(newValue);
11858 this.selectText(selStart, newValue.length);
11864 onSelect : function(record, index){
11866 if(this.fireEvent('beforeselect', this, record, index) !== false){
11868 this.setFromData(index > -1 ? record.data : false);
11871 this.fireEvent('select', this, record, index);
11876 * Returns the currently selected field value or empty string if no value is set.
11877 * @return {String} value The selected value
11879 getValue : function(){
11882 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11885 if(this.valueField){
11886 return typeof this.value != 'undefined' ? this.value : '';
11888 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11893 * Clears any text/value currently set in the field
11895 clearValue : function(){
11896 if(this.hiddenField){
11897 this.hiddenField.dom.value = '';
11900 this.setRawValue('');
11901 this.lastSelectionText = '';
11902 this.lastData = false;
11907 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11908 * will be displayed in the field. If the value does not match the data value of an existing item,
11909 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11910 * Otherwise the field will be blank (although the value will still be set).
11911 * @param {String} value The value to match
11913 setValue : function(v){
11920 if(this.valueField){
11921 var r = this.findRecord(this.valueField, v);
11923 text = r.data[this.displayField];
11924 }else if(this.valueNotFoundText !== undefined){
11925 text = this.valueNotFoundText;
11928 this.lastSelectionText = text;
11929 if(this.hiddenField){
11930 this.hiddenField.dom.value = v;
11932 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11936 * @property {Object} the last set data for the element
11941 * Sets the value of the field based on a object which is related to the record format for the store.
11942 * @param {Object} value the value to set as. or false on reset?
11944 setFromData : function(o){
11951 var dv = ''; // display value
11952 var vv = ''; // value value..
11954 if (this.displayField) {
11955 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11957 // this is an error condition!!!
11958 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11961 if(this.valueField){
11962 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11965 if(this.hiddenField){
11966 this.hiddenField.dom.value = vv;
11968 this.lastSelectionText = dv;
11969 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11973 // no hidden field.. - we store the value in 'value', but still display
11974 // display field!!!!
11975 this.lastSelectionText = dv;
11976 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11982 reset : function(){
11983 // overridden so that last data is reset..
11990 this.setValue(this.originalValue);
11991 this.clearInvalid();
11992 this.lastData = false;
11994 this.view.clearSelections();
11998 findRecord : function(prop, value){
12000 if(this.store.getCount() > 0){
12001 this.store.each(function(r){
12002 if(r.data[prop] == value){
12012 getName: function()
12014 // returns hidden if it's set..
12015 if (!this.rendered) {return ''};
12016 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12020 onViewMove : function(e, t){
12021 this.inKeyMode = false;
12025 onViewOver : function(e, t){
12026 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12029 var item = this.view.findItemFromChild(t);
12032 var index = this.view.indexOf(item);
12033 this.select(index, false);
12038 onViewClick : function(view, doFocus, el, e)
12040 var index = this.view.getSelectedIndexes()[0];
12042 var r = this.store.getAt(index);
12046 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12053 Roo.each(this.tickItems, function(v,k){
12055 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12056 _this.tickItems.splice(k, 1);
12058 if(typeof(e) == 'undefined' && view == false){
12059 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12071 this.tickItems.push(r.data);
12073 if(typeof(e) == 'undefined' && view == false){
12074 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12081 this.onSelect(r, index);
12083 if(doFocus !== false && !this.blockFocus){
12084 this.inputEl().focus();
12089 restrictHeight : function(){
12090 //this.innerList.dom.style.height = '';
12091 //var inner = this.innerList.dom;
12092 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12093 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12094 //this.list.beginUpdate();
12095 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12096 this.list.alignTo(this.inputEl(), this.listAlign);
12097 this.list.alignTo(this.inputEl(), this.listAlign);
12098 //this.list.endUpdate();
12102 onEmptyResults : function(){
12104 if(this.tickable && this.editable){
12105 this.restrictHeight();
12113 * Returns true if the dropdown list is expanded, else false.
12115 isExpanded : function(){
12116 return this.list.isVisible();
12120 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12121 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12122 * @param {String} value The data value of the item to select
12123 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12124 * selected item if it is not currently in view (defaults to true)
12125 * @return {Boolean} True if the value matched an item in the list, else false
12127 selectByValue : function(v, scrollIntoView){
12128 if(v !== undefined && v !== null){
12129 var r = this.findRecord(this.valueField || this.displayField, v);
12131 this.select(this.store.indexOf(r), scrollIntoView);
12139 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12140 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12141 * @param {Number} index The zero-based index of the list item to select
12142 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12143 * selected item if it is not currently in view (defaults to true)
12145 select : function(index, scrollIntoView){
12146 this.selectedIndex = index;
12147 this.view.select(index);
12148 if(scrollIntoView !== false){
12149 var el = this.view.getNode(index);
12151 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12154 this.list.scrollChildIntoView(el, false);
12160 selectNext : function(){
12161 var ct = this.store.getCount();
12163 if(this.selectedIndex == -1){
12165 }else if(this.selectedIndex < ct-1){
12166 this.select(this.selectedIndex+1);
12172 selectPrev : function(){
12173 var ct = this.store.getCount();
12175 if(this.selectedIndex == -1){
12177 }else if(this.selectedIndex != 0){
12178 this.select(this.selectedIndex-1);
12184 onKeyUp : function(e){
12185 if(this.editable !== false && !e.isSpecialKey()){
12186 this.lastKey = e.getKey();
12187 this.dqTask.delay(this.queryDelay);
12192 validateBlur : function(){
12193 return !this.list || !this.list.isVisible();
12197 initQuery : function(){
12199 var v = this.getRawValue();
12201 if(this.tickable && this.editable){
12202 v = this.tickableInputEl().getValue();
12209 doForce : function(){
12210 if(this.inputEl().dom.value.length > 0){
12211 this.inputEl().dom.value =
12212 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12218 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12219 * query allowing the query action to be canceled if needed.
12220 * @param {String} query The SQL query to execute
12221 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12222 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12223 * saved in the current store (defaults to false)
12225 doQuery : function(q, forceAll){
12227 if(q === undefined || q === null){
12232 forceAll: forceAll,
12236 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12241 forceAll = qe.forceAll;
12242 if(forceAll === true || (q.length >= this.minChars)){
12244 this.hasQuery = true;
12246 if(this.lastQuery != q || this.alwaysQuery){
12247 this.lastQuery = q;
12248 if(this.mode == 'local'){
12249 this.selectedIndex = -1;
12251 this.store.clearFilter();
12254 if(this.specialFilter){
12255 this.fireEvent('specialfilter', this);
12260 this.store.filter(this.displayField, q);
12263 this.store.fireEvent("datachanged", this.store);
12270 this.store.baseParams[this.queryParam] = q;
12272 var options = {params : this.getParams(q)};
12275 options.add = true;
12276 options.params.start = this.page * this.pageSize;
12279 this.store.load(options);
12282 * this code will make the page width larger, at the beginning, the list not align correctly,
12283 * we should expand the list on onLoad
12284 * so command out it
12289 this.selectedIndex = -1;
12294 this.loadNext = false;
12298 getParams : function(q){
12300 //p[this.queryParam] = q;
12304 p.limit = this.pageSize;
12310 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12312 collapse : function(){
12313 if(!this.isExpanded()){
12320 this.hasFocus = false;
12322 this.cancelBtn.hide();
12323 this.trigger.show();
12326 this.tickableInputEl().dom.value = '';
12327 this.tickableInputEl().blur();
12332 Roo.get(document).un('mousedown', this.collapseIf, this);
12333 Roo.get(document).un('mousewheel', this.collapseIf, this);
12334 if (!this.editable) {
12335 Roo.get(document).un('keydown', this.listKeyPress, this);
12337 this.fireEvent('collapse', this);
12341 collapseIf : function(e){
12342 var in_combo = e.within(this.el);
12343 var in_list = e.within(this.list);
12344 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12346 if (in_combo || in_list || is_list) {
12347 //e.stopPropagation();
12352 this.onTickableFooterButtonClick(e, false, false);
12360 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12362 expand : function(){
12364 if(this.isExpanded() || !this.hasFocus){
12368 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12369 this.list.setWidth(lw);
12376 this.restrictHeight();
12380 this.tickItems = Roo.apply([], this.item);
12383 this.cancelBtn.show();
12384 this.trigger.hide();
12387 this.tickableInputEl().focus();
12392 Roo.get(document).on('mousedown', this.collapseIf, this);
12393 Roo.get(document).on('mousewheel', this.collapseIf, this);
12394 if (!this.editable) {
12395 Roo.get(document).on('keydown', this.listKeyPress, this);
12398 this.fireEvent('expand', this);
12402 // Implements the default empty TriggerField.onTriggerClick function
12403 onTriggerClick : function(e)
12405 Roo.log('trigger click');
12407 if(this.disabled || !this.triggerList){
12412 this.loadNext = false;
12414 if(this.isExpanded()){
12416 if (!this.blockFocus) {
12417 this.inputEl().focus();
12421 this.hasFocus = true;
12422 if(this.triggerAction == 'all') {
12423 this.doQuery(this.allQuery, true);
12425 this.doQuery(this.getRawValue());
12427 if (!this.blockFocus) {
12428 this.inputEl().focus();
12433 onTickableTriggerClick : function(e)
12440 this.loadNext = false;
12441 this.hasFocus = true;
12443 if(this.triggerAction == 'all') {
12444 this.doQuery(this.allQuery, true);
12446 this.doQuery(this.getRawValue());
12450 onSearchFieldClick : function(e)
12452 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12453 this.onTickableFooterButtonClick(e, false, false);
12457 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12462 this.loadNext = false;
12463 this.hasFocus = true;
12465 if(this.triggerAction == 'all') {
12466 this.doQuery(this.allQuery, true);
12468 this.doQuery(this.getRawValue());
12472 listKeyPress : function(e)
12474 //Roo.log('listkeypress');
12475 // scroll to first matching element based on key pres..
12476 if (e.isSpecialKey()) {
12479 var k = String.fromCharCode(e.getKey()).toUpperCase();
12482 var csel = this.view.getSelectedNodes();
12483 var cselitem = false;
12485 var ix = this.view.indexOf(csel[0]);
12486 cselitem = this.store.getAt(ix);
12487 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12493 this.store.each(function(v) {
12495 // start at existing selection.
12496 if (cselitem.id == v.id) {
12502 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12503 match = this.store.indexOf(v);
12509 if (match === false) {
12510 return true; // no more action?
12513 this.view.select(match);
12514 var sn = Roo.get(this.view.getSelectedNodes()[0])
12515 sn.scrollIntoView(sn.dom.parentNode, false);
12518 onViewScroll : function(e, t){
12520 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){
12524 this.hasQuery = true;
12526 this.loading = this.list.select('.loading', true).first();
12528 if(this.loading === null){
12529 this.list.createChild({
12531 cls: 'loading select2-more-results select2-active',
12532 html: 'Loading more results...'
12535 this.loading = this.list.select('.loading', true).first();
12537 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12539 this.loading.hide();
12542 this.loading.show();
12547 this.loadNext = true;
12549 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12554 addItem : function(o)
12556 var dv = ''; // display value
12558 if (this.displayField) {
12559 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12561 // this is an error condition!!!
12562 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12569 var choice = this.choices.createChild({
12571 cls: 'select2-search-choice',
12580 cls: 'select2-search-choice-close',
12585 }, this.searchField);
12587 var close = choice.select('a.select2-search-choice-close', true).first()
12589 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12597 this.inputEl().dom.value = '';
12602 onRemoveItem : function(e, _self, o)
12604 e.preventDefault();
12606 this.lastItem = Roo.apply([], this.item);
12608 var index = this.item.indexOf(o.data) * 1;
12611 Roo.log('not this item?!');
12615 this.item.splice(index, 1);
12620 this.fireEvent('remove', this, e);
12626 syncValue : function()
12628 if(!this.item.length){
12635 Roo.each(this.item, function(i){
12636 if(_this.valueField){
12637 value.push(i[_this.valueField]);
12644 this.value = value.join(',');
12646 if(this.hiddenField){
12647 this.hiddenField.dom.value = this.value;
12650 this.store.fireEvent("datachanged", this.store);
12653 clearItem : function()
12655 if(!this.multiple){
12661 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12670 inputEl: function ()
12673 return this.searchField;
12675 return this.el.select('input.form-control',true).first();
12679 onTickableFooterButtonClick : function(e, btn, el)
12681 e.preventDefault();
12683 this.lastItem = Roo.apply([], this.item);
12685 if(btn && btn.name == 'cancel'){
12686 this.tickItems = Roo.apply([], this.item);
12695 Roo.each(this.tickItems, function(o){
12703 validate : function()
12705 var v = this.getRawValue();
12708 v = this.getValue();
12711 if(this.disabled || this.allowBlank || v.length){
12716 this.markInvalid();
12720 tickableInputEl : function()
12722 if(!this.tickable || !this.editable){
12723 return this.inputEl();
12726 return this.inputEl().select('.select2-search-field-input', true).first();
12732 * @cfg {Boolean} grow
12736 * @cfg {Number} growMin
12740 * @cfg {Number} growMax
12750 * Ext JS Library 1.1.1
12751 * Copyright(c) 2006-2007, Ext JS, LLC.
12753 * Originally Released Under LGPL - original licence link has changed is not relivant.
12756 * <script type="text/javascript">
12761 * @extends Roo.util.Observable
12762 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12763 * This class also supports single and multi selection modes. <br>
12764 * Create a data model bound view:
12766 var store = new Roo.data.Store(...);
12768 var view = new Roo.View({
12770 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12772 singleSelect: true,
12773 selectedClass: "ydataview-selected",
12777 // listen for node click?
12778 view.on("click", function(vw, index, node, e){
12779 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12783 dataModel.load("foobar.xml");
12785 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12787 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12788 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12790 * Note: old style constructor is still suported (container, template, config)
12793 * Create a new View
12794 * @param {Object} config The config object
12797 Roo.View = function(config, depreciated_tpl, depreciated_config){
12799 this.parent = false;
12801 if (typeof(depreciated_tpl) == 'undefined') {
12802 // new way.. - universal constructor.
12803 Roo.apply(this, config);
12804 this.el = Roo.get(this.el);
12807 this.el = Roo.get(config);
12808 this.tpl = depreciated_tpl;
12809 Roo.apply(this, depreciated_config);
12811 this.wrapEl = this.el.wrap().wrap();
12812 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12815 if(typeof(this.tpl) == "string"){
12816 this.tpl = new Roo.Template(this.tpl);
12818 // support xtype ctors..
12819 this.tpl = new Roo.factory(this.tpl, Roo);
12823 this.tpl.compile();
12828 * @event beforeclick
12829 * Fires before a click is processed. Returns false to cancel the default action.
12830 * @param {Roo.View} this
12831 * @param {Number} index The index of the target node
12832 * @param {HTMLElement} node The target node
12833 * @param {Roo.EventObject} e The raw event object
12835 "beforeclick" : true,
12838 * Fires when a template node is clicked.
12839 * @param {Roo.View} this
12840 * @param {Number} index The index of the target node
12841 * @param {HTMLElement} node The target node
12842 * @param {Roo.EventObject} e The raw event object
12847 * Fires when a template node is double clicked.
12848 * @param {Roo.View} this
12849 * @param {Number} index The index of the target node
12850 * @param {HTMLElement} node The target node
12851 * @param {Roo.EventObject} e The raw event object
12855 * @event contextmenu
12856 * Fires when a template node is right clicked.
12857 * @param {Roo.View} this
12858 * @param {Number} index The index of the target node
12859 * @param {HTMLElement} node The target node
12860 * @param {Roo.EventObject} e The raw event object
12862 "contextmenu" : true,
12864 * @event selectionchange
12865 * Fires when the selected nodes change.
12866 * @param {Roo.View} this
12867 * @param {Array} selections Array of the selected nodes
12869 "selectionchange" : true,
12872 * @event beforeselect
12873 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12874 * @param {Roo.View} this
12875 * @param {HTMLElement} node The node to be selected
12876 * @param {Array} selections Array of currently selected nodes
12878 "beforeselect" : true,
12880 * @event preparedata
12881 * Fires on every row to render, to allow you to change the data.
12882 * @param {Roo.View} this
12883 * @param {Object} data to be rendered (change this)
12885 "preparedata" : true
12893 "click": this.onClick,
12894 "dblclick": this.onDblClick,
12895 "contextmenu": this.onContextMenu,
12899 this.selections = [];
12901 this.cmp = new Roo.CompositeElementLite([]);
12903 this.store = Roo.factory(this.store, Roo.data);
12904 this.setStore(this.store, true);
12907 if ( this.footer && this.footer.xtype) {
12909 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12911 this.footer.dataSource = this.store
12912 this.footer.container = fctr;
12913 this.footer = Roo.factory(this.footer, Roo);
12914 fctr.insertFirst(this.el);
12916 // this is a bit insane - as the paging toolbar seems to detach the el..
12917 // dom.parentNode.parentNode.parentNode
12918 // they get detached?
12922 Roo.View.superclass.constructor.call(this);
12927 Roo.extend(Roo.View, Roo.util.Observable, {
12930 * @cfg {Roo.data.Store} store Data store to load data from.
12935 * @cfg {String|Roo.Element} el The container element.
12940 * @cfg {String|Roo.Template} tpl The template used by this View
12944 * @cfg {String} dataName the named area of the template to use as the data area
12945 * Works with domtemplates roo-name="name"
12949 * @cfg {String} selectedClass The css class to add to selected nodes
12951 selectedClass : "x-view-selected",
12953 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12958 * @cfg {String} text to display on mask (default Loading)
12962 * @cfg {Boolean} multiSelect Allow multiple selection
12964 multiSelect : false,
12966 * @cfg {Boolean} singleSelect Allow single selection
12968 singleSelect: false,
12971 * @cfg {Boolean} toggleSelect - selecting
12973 toggleSelect : false,
12976 * @cfg {Boolean} tickable - selecting
12981 * Returns the element this view is bound to.
12982 * @return {Roo.Element}
12984 getEl : function(){
12985 return this.wrapEl;
12991 * Refreshes the view. - called by datachanged on the store. - do not call directly.
12993 refresh : function(){
12994 //Roo.log('refresh');
12997 // if we are using something like 'domtemplate', then
12998 // the what gets used is:
12999 // t.applySubtemplate(NAME, data, wrapping data..)
13000 // the outer template then get' applied with
13001 // the store 'extra data'
13002 // and the body get's added to the
13003 // roo-name="data" node?
13004 // <span class='roo-tpl-{name}'></span> ?????
13008 this.clearSelections();
13009 this.el.update("");
13011 var records = this.store.getRange();
13012 if(records.length < 1) {
13014 // is this valid?? = should it render a template??
13016 this.el.update(this.emptyText);
13020 if (this.dataName) {
13021 this.el.update(t.apply(this.store.meta)); //????
13022 el = this.el.child('.roo-tpl-' + this.dataName);
13025 for(var i = 0, len = records.length; i < len; i++){
13026 var data = this.prepareData(records[i].data, i, records[i]);
13027 this.fireEvent("preparedata", this, data, i, records[i]);
13029 var d = Roo.apply({}, data);
13032 Roo.apply(d, {'roo-id' : Roo.id()});
13036 Roo.each(this.parent.item, function(item){
13037 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
13040 Roo.apply(d, {'roo-data-checked' : 'checked'});
13044 html[html.length] = Roo.util.Format.trim(
13046 t.applySubtemplate(this.dataName, d, this.store.meta) :
13053 el.update(html.join(""));
13054 this.nodes = el.dom.childNodes;
13055 this.updateIndexes(0);
13060 * Function to override to reformat the data that is sent to
13061 * the template for each node.
13062 * DEPRICATED - use the preparedata event handler.
13063 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
13064 * a JSON object for an UpdateManager bound view).
13066 prepareData : function(data, index, record)
13068 this.fireEvent("preparedata", this, data, index, record);
13072 onUpdate : function(ds, record){
13073 // Roo.log('on update');
13074 this.clearSelections();
13075 var index = this.store.indexOf(record);
13076 var n = this.nodes[index];
13077 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
13078 n.parentNode.removeChild(n);
13079 this.updateIndexes(index, index);
13085 onAdd : function(ds, records, index)
13087 //Roo.log(['on Add', ds, records, index] );
13088 this.clearSelections();
13089 if(this.nodes.length == 0){
13093 var n = this.nodes[index];
13094 for(var i = 0, len = records.length; i < len; i++){
13095 var d = this.prepareData(records[i].data, i, records[i]);
13097 this.tpl.insertBefore(n, d);
13100 this.tpl.append(this.el, d);
13103 this.updateIndexes(index);
13106 onRemove : function(ds, record, index){
13107 // Roo.log('onRemove');
13108 this.clearSelections();
13109 var el = this.dataName ?
13110 this.el.child('.roo-tpl-' + this.dataName) :
13113 el.dom.removeChild(this.nodes[index]);
13114 this.updateIndexes(index);
13118 * Refresh an individual node.
13119 * @param {Number} index
13121 refreshNode : function(index){
13122 this.onUpdate(this.store, this.store.getAt(index));
13125 updateIndexes : function(startIndex, endIndex){
13126 var ns = this.nodes;
13127 startIndex = startIndex || 0;
13128 endIndex = endIndex || ns.length - 1;
13129 for(var i = startIndex; i <= endIndex; i++){
13130 ns[i].nodeIndex = i;
13135 * Changes the data store this view uses and refresh the view.
13136 * @param {Store} store
13138 setStore : function(store, initial){
13139 if(!initial && this.store){
13140 this.store.un("datachanged", this.refresh);
13141 this.store.un("add", this.onAdd);
13142 this.store.un("remove", this.onRemove);
13143 this.store.un("update", this.onUpdate);
13144 this.store.un("clear", this.refresh);
13145 this.store.un("beforeload", this.onBeforeLoad);
13146 this.store.un("load", this.onLoad);
13147 this.store.un("loadexception", this.onLoad);
13151 store.on("datachanged", this.refresh, this);
13152 store.on("add", this.onAdd, this);
13153 store.on("remove", this.onRemove, this);
13154 store.on("update", this.onUpdate, this);
13155 store.on("clear", this.refresh, this);
13156 store.on("beforeload", this.onBeforeLoad, this);
13157 store.on("load", this.onLoad, this);
13158 store.on("loadexception", this.onLoad, this);
13166 * onbeforeLoad - masks the loading area.
13169 onBeforeLoad : function(store,opts)
13171 //Roo.log('onBeforeLoad');
13173 this.el.update("");
13175 this.el.mask(this.mask ? this.mask : "Loading" );
13177 onLoad : function ()
13184 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13185 * @param {HTMLElement} node
13186 * @return {HTMLElement} The template node
13188 findItemFromChild : function(node){
13189 var el = this.dataName ?
13190 this.el.child('.roo-tpl-' + this.dataName,true) :
13193 if(!node || node.parentNode == el){
13196 var p = node.parentNode;
13197 while(p && p != el){
13198 if(p.parentNode == el){
13207 onClick : function(e){
13208 var item = this.findItemFromChild(e.getTarget());
13210 var index = this.indexOf(item);
13211 if(this.onItemClick(item, index, e) !== false){
13212 this.fireEvent("click", this, index, item, e);
13215 this.clearSelections();
13220 onContextMenu : function(e){
13221 var item = this.findItemFromChild(e.getTarget());
13223 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13228 onDblClick : function(e){
13229 var item = this.findItemFromChild(e.getTarget());
13231 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13235 onItemClick : function(item, index, e)
13237 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13240 if (this.toggleSelect) {
13241 var m = this.isSelected(item) ? 'unselect' : 'select';
13244 _t[m](item, true, false);
13247 if(this.multiSelect || this.singleSelect){
13248 if(this.multiSelect && e.shiftKey && this.lastSelection){
13249 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13251 this.select(item, this.multiSelect && e.ctrlKey);
13252 this.lastSelection = item;
13255 if(!this.tickable){
13256 e.preventDefault();
13264 * Get the number of selected nodes.
13267 getSelectionCount : function(){
13268 return this.selections.length;
13272 * Get the currently selected nodes.
13273 * @return {Array} An array of HTMLElements
13275 getSelectedNodes : function(){
13276 return this.selections;
13280 * Get the indexes of the selected nodes.
13283 getSelectedIndexes : function(){
13284 var indexes = [], s = this.selections;
13285 for(var i = 0, len = s.length; i < len; i++){
13286 indexes.push(s[i].nodeIndex);
13292 * Clear all selections
13293 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13295 clearSelections : function(suppressEvent){
13296 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13297 this.cmp.elements = this.selections;
13298 this.cmp.removeClass(this.selectedClass);
13299 this.selections = [];
13300 if(!suppressEvent){
13301 this.fireEvent("selectionchange", this, this.selections);
13307 * Returns true if the passed node is selected
13308 * @param {HTMLElement/Number} node The node or node index
13309 * @return {Boolean}
13311 isSelected : function(node){
13312 var s = this.selections;
13316 node = this.getNode(node);
13317 return s.indexOf(node) !== -1;
13322 * @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
13323 * @param {Boolean} keepExisting (optional) true to keep existing selections
13324 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13326 select : function(nodeInfo, keepExisting, suppressEvent){
13327 if(nodeInfo instanceof Array){
13329 this.clearSelections(true);
13331 for(var i = 0, len = nodeInfo.length; i < len; i++){
13332 this.select(nodeInfo[i], true, true);
13336 var node = this.getNode(nodeInfo);
13337 if(!node || this.isSelected(node)){
13338 return; // already selected.
13341 this.clearSelections(true);
13344 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13345 Roo.fly(node).addClass(this.selectedClass);
13346 this.selections.push(node);
13347 if(!suppressEvent){
13348 this.fireEvent("selectionchange", this, this.selections);
13356 * @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
13357 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13358 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13360 unselect : function(nodeInfo, keepExisting, suppressEvent)
13362 if(nodeInfo instanceof Array){
13363 Roo.each(this.selections, function(s) {
13364 this.unselect(s, nodeInfo);
13368 var node = this.getNode(nodeInfo);
13369 if(!node || !this.isSelected(node)){
13370 //Roo.log("not selected");
13371 return; // not selected.
13375 Roo.each(this.selections, function(s) {
13377 Roo.fly(node).removeClass(this.selectedClass);
13384 this.selections= ns;
13385 this.fireEvent("selectionchange", this, this.selections);
13389 * Gets a template node.
13390 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13391 * @return {HTMLElement} The node or null if it wasn't found
13393 getNode : function(nodeInfo){
13394 if(typeof nodeInfo == "string"){
13395 return document.getElementById(nodeInfo);
13396 }else if(typeof nodeInfo == "number"){
13397 return this.nodes[nodeInfo];
13403 * Gets a range template nodes.
13404 * @param {Number} startIndex
13405 * @param {Number} endIndex
13406 * @return {Array} An array of nodes
13408 getNodes : function(start, end){
13409 var ns = this.nodes;
13410 start = start || 0;
13411 end = typeof end == "undefined" ? ns.length - 1 : end;
13414 for(var i = start; i <= end; i++){
13418 for(var i = start; i >= end; i--){
13426 * Finds the index of the passed node
13427 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13428 * @return {Number} The index of the node or -1
13430 indexOf : function(node){
13431 node = this.getNode(node);
13432 if(typeof node.nodeIndex == "number"){
13433 return node.nodeIndex;
13435 var ns = this.nodes;
13436 for(var i = 0, len = ns.length; i < len; i++){
13447 * based on jquery fullcalendar
13451 Roo.bootstrap = Roo.bootstrap || {};
13453 * @class Roo.bootstrap.Calendar
13454 * @extends Roo.bootstrap.Component
13455 * Bootstrap Calendar class
13456 * @cfg {Boolean} loadMask (true|false) default false
13457 * @cfg {Object} header generate the user specific header of the calendar, default false
13460 * Create a new Container
13461 * @param {Object} config The config object
13466 Roo.bootstrap.Calendar = function(config){
13467 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13471 * Fires when a date is selected
13472 * @param {DatePicker} this
13473 * @param {Date} date The selected date
13477 * @event monthchange
13478 * Fires when the displayed month changes
13479 * @param {DatePicker} this
13480 * @param {Date} date The selected month
13482 'monthchange': true,
13484 * @event evententer
13485 * Fires when mouse over an event
13486 * @param {Calendar} this
13487 * @param {event} Event
13489 'evententer': true,
13491 * @event eventleave
13492 * Fires when the mouse leaves an
13493 * @param {Calendar} this
13496 'eventleave': true,
13498 * @event eventclick
13499 * Fires when the mouse click an
13500 * @param {Calendar} this
13509 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13512 * @cfg {Number} startDay
13513 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13521 getAutoCreate : function(){
13524 var fc_button = function(name, corner, style, content ) {
13525 return Roo.apply({},{
13527 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13529 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13532 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13543 style : 'width:100%',
13550 cls : 'fc-header-left',
13552 fc_button('prev', 'left', 'arrow', '‹' ),
13553 fc_button('next', 'right', 'arrow', '›' ),
13554 { tag: 'span', cls: 'fc-header-space' },
13555 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13563 cls : 'fc-header-center',
13567 cls: 'fc-header-title',
13570 html : 'month / year'
13578 cls : 'fc-header-right',
13580 /* fc_button('month', 'left', '', 'month' ),
13581 fc_button('week', '', '', 'week' ),
13582 fc_button('day', 'right', '', 'day' )
13594 header = this.header;
13597 var cal_heads = function() {
13599 // fixme - handle this.
13601 for (var i =0; i < Date.dayNames.length; i++) {
13602 var d = Date.dayNames[i];
13605 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13606 html : d.substring(0,3)
13610 ret[0].cls += ' fc-first';
13611 ret[6].cls += ' fc-last';
13614 var cal_cell = function(n) {
13617 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13622 cls: 'fc-day-number',
13626 cls: 'fc-day-content',
13630 style: 'position: relative;' // height: 17px;
13642 var cal_rows = function() {
13645 for (var r = 0; r < 6; r++) {
13652 for (var i =0; i < Date.dayNames.length; i++) {
13653 var d = Date.dayNames[i];
13654 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13657 row.cn[0].cls+=' fc-first';
13658 row.cn[0].cn[0].style = 'min-height:90px';
13659 row.cn[6].cls+=' fc-last';
13663 ret[0].cls += ' fc-first';
13664 ret[4].cls += ' fc-prev-last';
13665 ret[5].cls += ' fc-last';
13672 cls: 'fc-border-separate',
13673 style : 'width:100%',
13681 cls : 'fc-first fc-last',
13699 cls : 'fc-content',
13700 style : "position: relative;",
13703 cls : 'fc-view fc-view-month fc-grid',
13704 style : 'position: relative',
13705 unselectable : 'on',
13708 cls : 'fc-event-container',
13709 style : 'position:absolute;z-index:8;top:0;left:0;'
13727 initEvents : function()
13730 throw "can not find store for calendar";
13736 style: "text-align:center",
13740 style: "background-color:white;width:50%;margin:250 auto",
13744 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13755 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13757 var size = this.el.select('.fc-content', true).first().getSize();
13758 this.maskEl.setSize(size.width, size.height);
13759 this.maskEl.enableDisplayMode("block");
13760 if(!this.loadMask){
13761 this.maskEl.hide();
13764 this.store = Roo.factory(this.store, Roo.data);
13765 this.store.on('load', this.onLoad, this);
13766 this.store.on('beforeload', this.onBeforeLoad, this);
13770 this.cells = this.el.select('.fc-day',true);
13771 //Roo.log(this.cells);
13772 this.textNodes = this.el.query('.fc-day-number');
13773 this.cells.addClassOnOver('fc-state-hover');
13775 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13776 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13777 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13778 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13780 this.on('monthchange', this.onMonthChange, this);
13782 this.update(new Date().clearTime());
13785 resize : function() {
13786 var sz = this.el.getSize();
13788 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13789 this.el.select('.fc-day-content div',true).setHeight(34);
13794 showPrevMonth : function(e){
13795 this.update(this.activeDate.add("mo", -1));
13797 showToday : function(e){
13798 this.update(new Date().clearTime());
13801 showNextMonth : function(e){
13802 this.update(this.activeDate.add("mo", 1));
13806 showPrevYear : function(){
13807 this.update(this.activeDate.add("y", -1));
13811 showNextYear : function(){
13812 this.update(this.activeDate.add("y", 1));
13817 update : function(date)
13819 var vd = this.activeDate;
13820 this.activeDate = date;
13821 // if(vd && this.el){
13822 // var t = date.getTime();
13823 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13824 // Roo.log('using add remove');
13826 // this.fireEvent('monthchange', this, date);
13828 // this.cells.removeClass("fc-state-highlight");
13829 // this.cells.each(function(c){
13830 // if(c.dateValue == t){
13831 // c.addClass("fc-state-highlight");
13832 // setTimeout(function(){
13833 // try{c.dom.firstChild.focus();}catch(e){}
13843 var days = date.getDaysInMonth();
13845 var firstOfMonth = date.getFirstDateOfMonth();
13846 var startingPos = firstOfMonth.getDay()-this.startDay;
13848 if(startingPos < this.startDay){
13852 var pm = date.add(Date.MONTH, -1);
13853 var prevStart = pm.getDaysInMonth()-startingPos;
13855 this.cells = this.el.select('.fc-day',true);
13856 this.textNodes = this.el.query('.fc-day-number');
13857 this.cells.addClassOnOver('fc-state-hover');
13859 var cells = this.cells.elements;
13860 var textEls = this.textNodes;
13862 Roo.each(cells, function(cell){
13863 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13866 days += startingPos;
13868 // convert everything to numbers so it's fast
13869 var day = 86400000;
13870 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13873 //Roo.log(prevStart);
13875 var today = new Date().clearTime().getTime();
13876 var sel = date.clearTime().getTime();
13877 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13878 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13879 var ddMatch = this.disabledDatesRE;
13880 var ddText = this.disabledDatesText;
13881 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13882 var ddaysText = this.disabledDaysText;
13883 var format = this.format;
13885 var setCellClass = function(cal, cell){
13889 //Roo.log('set Cell Class');
13891 var t = d.getTime();
13895 cell.dateValue = t;
13897 cell.className += " fc-today";
13898 cell.className += " fc-state-highlight";
13899 cell.title = cal.todayText;
13902 // disable highlight in other month..
13903 //cell.className += " fc-state-highlight";
13908 cell.className = " fc-state-disabled";
13909 cell.title = cal.minText;
13913 cell.className = " fc-state-disabled";
13914 cell.title = cal.maxText;
13918 if(ddays.indexOf(d.getDay()) != -1){
13919 cell.title = ddaysText;
13920 cell.className = " fc-state-disabled";
13923 if(ddMatch && format){
13924 var fvalue = d.dateFormat(format);
13925 if(ddMatch.test(fvalue)){
13926 cell.title = ddText.replace("%0", fvalue);
13927 cell.className = " fc-state-disabled";
13931 if (!cell.initialClassName) {
13932 cell.initialClassName = cell.dom.className;
13935 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13940 for(; i < startingPos; i++) {
13941 textEls[i].innerHTML = (++prevStart);
13942 d.setDate(d.getDate()+1);
13944 cells[i].className = "fc-past fc-other-month";
13945 setCellClass(this, cells[i]);
13950 for(; i < days; i++){
13951 intDay = i - startingPos + 1;
13952 textEls[i].innerHTML = (intDay);
13953 d.setDate(d.getDate()+1);
13955 cells[i].className = ''; // "x-date-active";
13956 setCellClass(this, cells[i]);
13960 for(; i < 42; i++) {
13961 textEls[i].innerHTML = (++extraDays);
13962 d.setDate(d.getDate()+1);
13964 cells[i].className = "fc-future fc-other-month";
13965 setCellClass(this, cells[i]);
13968 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13970 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13972 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13973 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13975 if(totalRows != 6){
13976 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13977 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13980 this.fireEvent('monthchange', this, date);
13984 if(!this.internalRender){
13985 var main = this.el.dom.firstChild;
13986 var w = main.offsetWidth;
13987 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13988 Roo.fly(main).setWidth(w);
13989 this.internalRender = true;
13990 // opera does not respect the auto grow header center column
13991 // then, after it gets a width opera refuses to recalculate
13992 // without a second pass
13993 if(Roo.isOpera && !this.secondPass){
13994 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
13995 this.secondPass = true;
13996 this.update.defer(10, this, [date]);
14003 findCell : function(dt) {
14004 dt = dt.clearTime().getTime();
14006 this.cells.each(function(c){
14007 //Roo.log("check " +c.dateValue + '?=' + dt);
14008 if(c.dateValue == dt){
14018 findCells : function(ev) {
14019 var s = ev.start.clone().clearTime().getTime();
14021 var e= ev.end.clone().clearTime().getTime();
14024 this.cells.each(function(c){
14025 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
14027 if(c.dateValue > e){
14030 if(c.dateValue < s){
14039 // findBestRow: function(cells)
14043 // for (var i =0 ; i < cells.length;i++) {
14044 // ret = Math.max(cells[i].rows || 0,ret);
14051 addItem : function(ev)
14053 // look for vertical location slot in
14054 var cells = this.findCells(ev);
14056 // ev.row = this.findBestRow(cells);
14058 // work out the location.
14062 for(var i =0; i < cells.length; i++) {
14064 cells[i].row = cells[0].row;
14067 cells[i].row = cells[i].row + 1;
14077 if (crow.start.getY() == cells[i].getY()) {
14079 crow.end = cells[i];
14096 cells[0].events.push(ev);
14098 this.calevents.push(ev);
14101 clearEvents: function() {
14103 if(!this.calevents){
14107 Roo.each(this.cells.elements, function(c){
14113 Roo.each(this.calevents, function(e) {
14114 Roo.each(e.els, function(el) {
14115 el.un('mouseenter' ,this.onEventEnter, this);
14116 el.un('mouseleave' ,this.onEventLeave, this);
14121 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14127 renderEvents: function()
14131 this.cells.each(function(c) {
14140 if(c.row != c.events.length){
14141 r = 4 - (4 - (c.row - c.events.length));
14144 c.events = ev.slice(0, r);
14145 c.more = ev.slice(r);
14147 if(c.more.length && c.more.length == 1){
14148 c.events.push(c.more.pop());
14151 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14155 this.cells.each(function(c) {
14157 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14160 for (var e = 0; e < c.events.length; e++){
14161 var ev = c.events[e];
14162 var rows = ev.rows;
14164 for(var i = 0; i < rows.length; i++) {
14166 // how many rows should it span..
14169 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14170 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14172 unselectable : "on",
14175 cls: 'fc-event-inner',
14179 // cls: 'fc-event-time',
14180 // html : cells.length > 1 ? '' : ev.time
14184 cls: 'fc-event-title',
14185 html : String.format('{0}', ev.title)
14192 cls: 'ui-resizable-handle ui-resizable-e',
14193 html : '  '
14200 cfg.cls += ' fc-event-start';
14202 if ((i+1) == rows.length) {
14203 cfg.cls += ' fc-event-end';
14206 var ctr = _this.el.select('.fc-event-container',true).first();
14207 var cg = ctr.createChild(cfg);
14209 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14210 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14212 var r = (c.more.length) ? 1 : 0;
14213 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14214 cg.setWidth(ebox.right - sbox.x -2);
14216 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14217 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14218 cg.on('click', _this.onEventClick, _this, ev);
14229 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14230 style : 'position: absolute',
14231 unselectable : "on",
14234 cls: 'fc-event-inner',
14238 cls: 'fc-event-title',
14246 cls: 'ui-resizable-handle ui-resizable-e',
14247 html : '  '
14253 var ctr = _this.el.select('.fc-event-container',true).first();
14254 var cg = ctr.createChild(cfg);
14256 var sbox = c.select('.fc-day-content',true).first().getBox();
14257 var ebox = c.select('.fc-day-content',true).first().getBox();
14259 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14260 cg.setWidth(ebox.right - sbox.x -2);
14262 cg.on('click', _this.onMoreEventClick, _this, c.more);
14272 onEventEnter: function (e, el,event,d) {
14273 this.fireEvent('evententer', this, el, event);
14276 onEventLeave: function (e, el,event,d) {
14277 this.fireEvent('eventleave', this, el, event);
14280 onEventClick: function (e, el,event,d) {
14281 this.fireEvent('eventclick', this, el, event);
14284 onMonthChange: function () {
14288 onMoreEventClick: function(e, el, more)
14292 this.calpopover.placement = 'right';
14293 this.calpopover.setTitle('More');
14295 this.calpopover.setContent('');
14297 var ctr = this.calpopover.el.select('.popover-content', true).first();
14299 Roo.each(more, function(m){
14301 cls : 'fc-event-hori fc-event-draggable',
14304 var cg = ctr.createChild(cfg);
14306 cg.on('click', _this.onEventClick, _this, m);
14309 this.calpopover.show(el);
14314 onLoad: function ()
14316 this.calevents = [];
14319 if(this.store.getCount() > 0){
14320 this.store.data.each(function(d){
14323 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14324 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14325 time : d.data.start_time,
14326 title : d.data.title,
14327 description : d.data.description,
14328 venue : d.data.venue
14333 this.renderEvents();
14335 if(this.calevents.length && this.loadMask){
14336 this.maskEl.hide();
14340 onBeforeLoad: function()
14342 this.clearEvents();
14344 this.maskEl.show();
14358 * @class Roo.bootstrap.Popover
14359 * @extends Roo.bootstrap.Component
14360 * Bootstrap Popover class
14361 * @cfg {String} html contents of the popover (or false to use children..)
14362 * @cfg {String} title of popover (or false to hide)
14363 * @cfg {String} placement how it is placed
14364 * @cfg {String} trigger click || hover (or false to trigger manually)
14365 * @cfg {String} over what (parent or false to trigger manually.)
14366 * @cfg {Number} delay - delay before showing
14369 * Create a new Popover
14370 * @param {Object} config The config object
14373 Roo.bootstrap.Popover = function(config){
14374 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14377 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14379 title: 'Fill in a title',
14382 placement : 'right',
14383 trigger : 'hover', // hover
14389 can_build_overlaid : false,
14391 getChildContainer : function()
14393 return this.el.select('.popover-content',true).first();
14396 getAutoCreate : function(){
14397 Roo.log('make popover?');
14399 cls : 'popover roo-dynamic',
14400 style: 'display:block',
14406 cls : 'popover-inner',
14410 cls: 'popover-title',
14414 cls : 'popover-content',
14425 setTitle: function(str)
14427 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14429 setContent: function(str)
14431 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14433 // as it get's added to the bottom of the page.
14434 onRender : function(ct, position)
14436 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14438 var cfg = Roo.apply({}, this.getAutoCreate());
14442 cfg.cls += ' ' + this.cls;
14445 cfg.style = this.style;
14447 Roo.log("adding to ")
14448 this.el = Roo.get(document.body).createChild(cfg, position);
14454 initEvents : function()
14456 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14457 this.el.enableDisplayMode('block');
14459 if (this.over === false) {
14462 if (this.triggers === false) {
14465 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14466 var triggers = this.trigger ? this.trigger.split(' ') : [];
14467 Roo.each(triggers, function(trigger) {
14469 if (trigger == 'click') {
14470 on_el.on('click', this.toggle, this);
14471 } else if (trigger != 'manual') {
14472 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14473 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14475 on_el.on(eventIn ,this.enter, this);
14476 on_el.on(eventOut, this.leave, this);
14487 toggle : function () {
14488 this.hoverState == 'in' ? this.leave() : this.enter();
14491 enter : function () {
14494 clearTimeout(this.timeout);
14496 this.hoverState = 'in';
14498 if (!this.delay || !this.delay.show) {
14503 this.timeout = setTimeout(function () {
14504 if (_t.hoverState == 'in') {
14507 }, this.delay.show)
14509 leave : function() {
14510 clearTimeout(this.timeout);
14512 this.hoverState = 'out';
14514 if (!this.delay || !this.delay.hide) {
14519 this.timeout = setTimeout(function () {
14520 if (_t.hoverState == 'out') {
14523 }, this.delay.hide)
14526 show : function (on_el)
14529 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14532 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14533 if (this.html !== false) {
14534 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14536 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14537 if (!this.title.length) {
14538 this.el.select('.popover-title',true).hide();
14541 var placement = typeof this.placement == 'function' ?
14542 this.placement.call(this, this.el, on_el) :
14545 var autoToken = /\s?auto?\s?/i;
14546 var autoPlace = autoToken.test(placement);
14548 placement = placement.replace(autoToken, '') || 'top';
14552 //this.el.setXY([0,0]);
14554 this.el.dom.style.display='block';
14555 this.el.addClass(placement);
14557 //this.el.appendTo(on_el);
14559 var p = this.getPosition();
14560 var box = this.el.getBox();
14565 var align = Roo.bootstrap.Popover.alignment[placement];
14566 this.el.alignTo(on_el, align[0],align[1]);
14567 //var arrow = this.el.select('.arrow',true).first();
14568 //arrow.set(align[2],
14570 this.el.addClass('in');
14571 this.hoverState = null;
14573 if (this.el.hasClass('fade')) {
14580 this.el.setXY([0,0]);
14581 this.el.removeClass('in');
14588 Roo.bootstrap.Popover.alignment = {
14589 'left' : ['r-l', [-10,0], 'right'],
14590 'right' : ['l-r', [10,0], 'left'],
14591 'bottom' : ['t-b', [0,10], 'top'],
14592 'top' : [ 'b-t', [0,-10], 'bottom']
14603 * @class Roo.bootstrap.Progress
14604 * @extends Roo.bootstrap.Component
14605 * Bootstrap Progress class
14606 * @cfg {Boolean} striped striped of the progress bar
14607 * @cfg {Boolean} active animated of the progress bar
14611 * Create a new Progress
14612 * @param {Object} config The config object
14615 Roo.bootstrap.Progress = function(config){
14616 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14619 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14624 getAutoCreate : function(){
14632 cfg.cls += ' progress-striped';
14636 cfg.cls += ' active';
14655 * @class Roo.bootstrap.ProgressBar
14656 * @extends Roo.bootstrap.Component
14657 * Bootstrap ProgressBar class
14658 * @cfg {Number} aria_valuenow aria-value now
14659 * @cfg {Number} aria_valuemin aria-value min
14660 * @cfg {Number} aria_valuemax aria-value max
14661 * @cfg {String} label label for the progress bar
14662 * @cfg {String} panel (success | info | warning | danger )
14663 * @cfg {String} role role of the progress bar
14664 * @cfg {String} sr_only text
14668 * Create a new ProgressBar
14669 * @param {Object} config The config object
14672 Roo.bootstrap.ProgressBar = function(config){
14673 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14676 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14680 aria_valuemax : 100,
14686 getAutoCreate : function()
14691 cls: 'progress-bar',
14692 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14704 cfg.role = this.role;
14707 if(this.aria_valuenow){
14708 cfg['aria-valuenow'] = this.aria_valuenow;
14711 if(this.aria_valuemin){
14712 cfg['aria-valuemin'] = this.aria_valuemin;
14715 if(this.aria_valuemax){
14716 cfg['aria-valuemax'] = this.aria_valuemax;
14719 if(this.label && !this.sr_only){
14720 cfg.html = this.label;
14724 cfg.cls += ' progress-bar-' + this.panel;
14730 update : function(aria_valuenow)
14732 this.aria_valuenow = aria_valuenow;
14734 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14749 * @class Roo.bootstrap.TabGroup
14750 * @extends Roo.bootstrap.Column
14751 * Bootstrap Column class
14752 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14753 * @cfg {Boolean} carousel true to make the group behave like a carousel
14754 * @cfg {Number} bullets show the panel pointer.. default 0
14755 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
14756 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
14757 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14760 * Create a new TabGroup
14761 * @param {Object} config The config object
14764 Roo.bootstrap.TabGroup = function(config){
14765 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14767 this.navId = Roo.id();
14770 Roo.bootstrap.TabGroup.register(this);
14774 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14777 transition : false,
14782 slideOnTouch : false,
14784 getAutoCreate : function()
14786 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14788 cfg.cls += ' tab-content';
14790 Roo.log('get auto create...............');
14792 if (this.carousel) {
14793 cfg.cls += ' carousel slide';
14796 cls : 'carousel-inner'
14799 if(this.bullets > 0 && !Roo.isTouch){
14802 cls : 'carousel-bullets',
14806 if(this.bullets_cls){
14807 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14810 for (var i = 0; i < this.bullets; i++){
14812 cls : 'bullet bullet-' + i
14820 cfg.cn[0].cn = bullets;
14827 initEvents: function()
14829 Roo.log('-------- init events on tab group ---------');
14831 if(this.bullets > 0 && !Roo.isTouch){
14837 if(Roo.isTouch && this.slideOnTouch){
14838 this.el.on("touchstart", this.onTouchStart, this);
14841 if(this.autoslide){
14844 this.slideFn = window.setInterval(function() {
14845 _this.showPanelNext();
14851 onTouchStart : function(e, el, o)
14853 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
14857 this.showPanelNext();
14860 getChildContainer : function()
14862 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14866 * register a Navigation item
14867 * @param {Roo.bootstrap.NavItem} the navitem to add
14869 register : function(item)
14871 this.tabs.push( item);
14872 item.navId = this.navId; // not really needed..
14876 getActivePanel : function()
14879 Roo.each(this.tabs, function(t) {
14889 getPanelByName : function(n)
14892 Roo.each(this.tabs, function(t) {
14893 if (t.tabId == n) {
14901 indexOfPanel : function(p)
14904 Roo.each(this.tabs, function(t,i) {
14905 if (t.tabId == p.tabId) {
14914 * show a specific panel
14915 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14916 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14918 showPanel : function (pan)
14920 if(this.transition){
14921 Roo.log("waiting for the transitionend");
14925 if (typeof(pan) == 'number') {
14926 pan = this.tabs[pan];
14928 if (typeof(pan) == 'string') {
14929 pan = this.getPanelByName(pan);
14931 if (pan.tabId == this.getActivePanel().tabId) {
14934 var cur = this.getActivePanel();
14936 if (false === cur.fireEvent('beforedeactivate')) {
14940 if(this.bullets > 0 && !Roo.isTouch){
14941 this.setActiveBullet(this.indexOfPanel(pan));
14944 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14946 this.transition = true;
14947 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14948 var lr = dir == 'next' ? 'left' : 'right';
14949 pan.el.addClass(dir); // or prev
14950 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14951 cur.el.addClass(lr); // or right
14952 pan.el.addClass(lr);
14955 cur.el.on('transitionend', function() {
14956 Roo.log("trans end?");
14958 pan.el.removeClass([lr,dir]);
14959 pan.setActive(true);
14961 cur.el.removeClass([lr]);
14962 cur.setActive(false);
14964 _this.transition = false;
14966 }, this, { single: true } );
14971 cur.setActive(false);
14972 pan.setActive(true);
14977 showPanelNext : function()
14979 var i = this.indexOfPanel(this.getActivePanel());
14981 if (i >= this.tabs.length - 1 && !this.autoslide) {
14985 if (i >= this.tabs.length - 1 && this.autoslide) {
14989 this.showPanel(this.tabs[i+1]);
14992 showPanelPrev : function()
14994 var i = this.indexOfPanel(this.getActivePanel());
14996 if (i < 1 && !this.autoslide) {
15000 if (i < 1 && this.autoslide) {
15001 i = this.tabs.length;
15004 this.showPanel(this.tabs[i-1]);
15007 initBullet : function()
15015 for (var i = 0; i < this.bullets; i++){
15016 var bullet = this.el.select('.bullet-' + i, true).first();
15022 bullet.on('click', (function(e, el, o, ii, t){
15024 e.preventDefault();
15026 _this.showPanel(ii);
15028 if(_this.autoslide && _this.slideFn){
15029 clearInterval(_this.slideFn);
15030 _this.slideFn = window.setInterval(function() {
15031 _this.showPanelNext();
15035 }).createDelegate(this, [i, bullet], true));
15039 setActiveBullet : function(i)
15045 Roo.each(this.el.select('.bullet', true).elements, function(el){
15046 el.removeClass('selected');
15049 var bullet = this.el.select('.bullet-' + i, true).first();
15055 bullet.addClass('selected');
15066 Roo.apply(Roo.bootstrap.TabGroup, {
15070 * register a Navigation Group
15071 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15073 register : function(navgrp)
15075 this.groups[navgrp.navId] = navgrp;
15079 * fetch a Navigation Group based on the navigation ID
15080 * if one does not exist , it will get created.
15081 * @param {string} the navgroup to add
15082 * @returns {Roo.bootstrap.NavGroup} the navgroup
15084 get: function(navId) {
15085 if (typeof(this.groups[navId]) == 'undefined') {
15086 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15088 return this.groups[navId] ;
15103 * @class Roo.bootstrap.TabPanel
15104 * @extends Roo.bootstrap.Component
15105 * Bootstrap TabPanel class
15106 * @cfg {Boolean} active panel active
15107 * @cfg {String} html panel content
15108 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15109 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15113 * Create a new TabPanel
15114 * @param {Object} config The config object
15117 Roo.bootstrap.TabPanel = function(config){
15118 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15122 * Fires when the active status changes
15123 * @param {Roo.bootstrap.TabPanel} this
15124 * @param {Boolean} state the new state
15129 * @event beforedeactivate
15130 * Fires before a tab is de-activated - can be used to do validation on a form.
15131 * @param {Roo.bootstrap.TabPanel} this
15132 * @return {Boolean} false if there is an error
15135 'beforedeactivate': true
15138 this.tabId = this.tabId || Roo.id();
15142 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15149 getAutoCreate : function(){
15152 // item is needed for carousel - not sure if it has any effect otherwise
15153 cls: 'tab-pane item',
15154 html: this.html || ''
15158 cfg.cls += ' active';
15162 cfg.tabId = this.tabId;
15169 initEvents: function()
15171 Roo.log('-------- init events on tab panel ---------');
15173 var p = this.parent();
15174 this.navId = this.navId || p.navId;
15176 if (typeof(this.navId) != 'undefined') {
15177 // not really needed.. but just in case.. parent should be a NavGroup.
15178 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15179 Roo.log(['register', tg, this]);
15182 var i = tg.tabs.length - 1;
15184 if(this.active && tg.bullets > 0 && i < tg.bullets){
15185 tg.setActiveBullet(i);
15192 onRender : function(ct, position)
15194 // Roo.log("Call onRender: " + this.xtype);
15196 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15204 setActive: function(state)
15206 Roo.log("panel - set active " + this.tabId + "=" + state);
15208 this.active = state;
15210 this.el.removeClass('active');
15212 } else if (!this.el.hasClass('active')) {
15213 this.el.addClass('active');
15216 this.fireEvent('changed', this, state);
15233 * @class Roo.bootstrap.DateField
15234 * @extends Roo.bootstrap.Input
15235 * Bootstrap DateField class
15236 * @cfg {Number} weekStart default 0
15237 * @cfg {String} viewMode default empty, (months|years)
15238 * @cfg {String} minViewMode default empty, (months|years)
15239 * @cfg {Number} startDate default -Infinity
15240 * @cfg {Number} endDate default Infinity
15241 * @cfg {Boolean} todayHighlight default false
15242 * @cfg {Boolean} todayBtn default false
15243 * @cfg {Boolean} calendarWeeks default false
15244 * @cfg {Object} daysOfWeekDisabled default empty
15245 * @cfg {Boolean} singleMode default false (true | false)
15247 * @cfg {Boolean} keyboardNavigation default true
15248 * @cfg {String} language default en
15251 * Create a new DateField
15252 * @param {Object} config The config object
15255 Roo.bootstrap.DateField = function(config){
15256 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15260 * Fires when this field show.
15261 * @param {Roo.bootstrap.DateField} this
15262 * @param {Mixed} date The date value
15267 * Fires when this field hide.
15268 * @param {Roo.bootstrap.DateField} this
15269 * @param {Mixed} date The date value
15274 * Fires when select a date.
15275 * @param {Roo.bootstrap.DateField} this
15276 * @param {Mixed} date The date value
15282 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15285 * @cfg {String} format
15286 * The default date format string which can be overriden for localization support. The format must be
15287 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15291 * @cfg {String} altFormats
15292 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15293 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15295 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15303 todayHighlight : false,
15309 keyboardNavigation: true,
15311 calendarWeeks: false,
15313 startDate: -Infinity,
15317 daysOfWeekDisabled: [],
15321 singleMode : false,
15323 UTCDate: function()
15325 return new Date(Date.UTC.apply(Date, arguments));
15328 UTCToday: function()
15330 var today = new Date();
15331 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15334 getDate: function() {
15335 var d = this.getUTCDate();
15336 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15339 getUTCDate: function() {
15343 setDate: function(d) {
15344 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15347 setUTCDate: function(d) {
15349 this.setValue(this.formatDate(this.date));
15352 onRender: function(ct, position)
15355 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15357 this.language = this.language || 'en';
15358 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15359 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15361 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15362 this.format = this.format || 'm/d/y';
15363 this.isInline = false;
15364 this.isInput = true;
15365 this.component = this.el.select('.add-on', true).first() || false;
15366 this.component = (this.component && this.component.length === 0) ? false : this.component;
15367 this.hasInput = this.component && this.inputEL().length;
15369 if (typeof(this.minViewMode === 'string')) {
15370 switch (this.minViewMode) {
15372 this.minViewMode = 1;
15375 this.minViewMode = 2;
15378 this.minViewMode = 0;
15383 if (typeof(this.viewMode === 'string')) {
15384 switch (this.viewMode) {
15397 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15399 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15401 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15403 this.picker().on('mousedown', this.onMousedown, this);
15404 this.picker().on('click', this.onClick, this);
15406 this.picker().addClass('datepicker-dropdown');
15408 this.startViewMode = this.viewMode;
15410 if(this.singleMode){
15411 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15412 v.setVisibilityMode(Roo.Element.DISPLAY)
15416 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15417 v.setStyle('width', '189px');
15421 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15422 if(!this.calendarWeeks){
15427 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15428 v.attr('colspan', function(i, val){
15429 return parseInt(val) + 1;
15434 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15436 this.setStartDate(this.startDate);
15437 this.setEndDate(this.endDate);
15439 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15446 if(this.isInline) {
15451 picker : function()
15453 return this.pickerEl;
15454 // return this.el.select('.datepicker', true).first();
15457 fillDow: function()
15459 var dowCnt = this.weekStart;
15468 if(this.calendarWeeks){
15476 while (dowCnt < this.weekStart + 7) {
15480 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15484 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15487 fillMonths: function()
15490 var months = this.picker().select('>.datepicker-months td', true).first();
15492 months.dom.innerHTML = '';
15498 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15501 months.createChild(month);
15508 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;
15510 if (this.date < this.startDate) {
15511 this.viewDate = new Date(this.startDate);
15512 } else if (this.date > this.endDate) {
15513 this.viewDate = new Date(this.endDate);
15515 this.viewDate = new Date(this.date);
15523 var d = new Date(this.viewDate),
15524 year = d.getUTCFullYear(),
15525 month = d.getUTCMonth(),
15526 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15527 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15528 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15529 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15530 currentDate = this.date && this.date.valueOf(),
15531 today = this.UTCToday();
15533 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15535 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15537 // this.picker.select('>tfoot th.today').
15538 // .text(dates[this.language].today)
15539 // .toggle(this.todayBtn !== false);
15541 this.updateNavArrows();
15544 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15546 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15548 prevMonth.setUTCDate(day);
15550 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15552 var nextMonth = new Date(prevMonth);
15554 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15556 nextMonth = nextMonth.valueOf();
15558 var fillMonths = false;
15560 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15562 while(prevMonth.valueOf() < nextMonth) {
15565 if (prevMonth.getUTCDay() === this.weekStart) {
15567 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15575 if(this.calendarWeeks){
15576 // ISO 8601: First week contains first thursday.
15577 // ISO also states week starts on Monday, but we can be more abstract here.
15579 // Start of current week: based on weekstart/current date
15580 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15581 // Thursday of this week
15582 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15583 // First Thursday of year, year from thursday
15584 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15585 // Calendar week: ms between thursdays, div ms per day, div 7 days
15586 calWeek = (th - yth) / 864e5 / 7 + 1;
15588 fillMonths.cn.push({
15596 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15598 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15601 if (this.todayHighlight &&
15602 prevMonth.getUTCFullYear() == today.getFullYear() &&
15603 prevMonth.getUTCMonth() == today.getMonth() &&
15604 prevMonth.getUTCDate() == today.getDate()) {
15605 clsName += ' today';
15608 if (currentDate && prevMonth.valueOf() === currentDate) {
15609 clsName += ' active';
15612 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15613 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15614 clsName += ' disabled';
15617 fillMonths.cn.push({
15619 cls: 'day ' + clsName,
15620 html: prevMonth.getDate()
15623 prevMonth.setDate(prevMonth.getDate()+1);
15626 var currentYear = this.date && this.date.getUTCFullYear();
15627 var currentMonth = this.date && this.date.getUTCMonth();
15629 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15631 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15632 v.removeClass('active');
15634 if(currentYear === year && k === currentMonth){
15635 v.addClass('active');
15638 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15639 v.addClass('disabled');
15645 year = parseInt(year/10, 10) * 10;
15647 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15649 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15652 for (var i = -1; i < 11; i++) {
15653 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15655 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15663 showMode: function(dir)
15666 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15669 Roo.each(this.picker().select('>div',true).elements, function(v){
15670 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15673 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15678 if(this.isInline) return;
15680 this.picker().removeClass(['bottom', 'top']);
15682 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15684 * place to the top of element!
15688 this.picker().addClass('top');
15689 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15694 this.picker().addClass('bottom');
15696 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15699 parseDate : function(value)
15701 if(!value || value instanceof Date){
15704 var v = Date.parseDate(value, this.format);
15705 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15706 v = Date.parseDate(value, 'Y-m-d');
15708 if(!v && this.altFormats){
15709 if(!this.altFormatsArray){
15710 this.altFormatsArray = this.altFormats.split("|");
15712 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15713 v = Date.parseDate(value, this.altFormatsArray[i]);
15719 formatDate : function(date, fmt)
15721 return (!date || !(date instanceof Date)) ?
15722 date : date.dateFormat(fmt || this.format);
15725 onFocus : function()
15727 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15731 onBlur : function()
15733 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15735 var d = this.inputEl().getValue();
15744 this.picker().show();
15748 this.fireEvent('show', this, this.date);
15753 if(this.isInline) return;
15754 this.picker().hide();
15755 this.viewMode = this.startViewMode;
15758 this.fireEvent('hide', this, this.date);
15762 onMousedown: function(e)
15764 e.stopPropagation();
15765 e.preventDefault();
15770 Roo.bootstrap.DateField.superclass.keyup.call(this);
15774 setValue: function(v)
15777 // v can be a string or a date..
15780 var d = new Date(this.parseDate(v) ).clearTime();
15782 if(isNaN(d.getTime())){
15783 this.date = this.viewDate = '';
15784 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15788 v = this.formatDate(d);
15790 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15792 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15796 this.fireEvent('select', this, this.date);
15800 getValue: function()
15802 return this.formatDate(this.date);
15805 fireKey: function(e)
15807 if (!this.picker().isVisible()){
15808 if (e.keyCode == 27) // allow escape to hide and re-show picker
15813 var dateChanged = false,
15815 newDate, newViewDate;
15820 e.preventDefault();
15824 if (!this.keyboardNavigation) break;
15825 dir = e.keyCode == 37 ? -1 : 1;
15828 newDate = this.moveYear(this.date, dir);
15829 newViewDate = this.moveYear(this.viewDate, dir);
15830 } else if (e.shiftKey){
15831 newDate = this.moveMonth(this.date, dir);
15832 newViewDate = this.moveMonth(this.viewDate, dir);
15834 newDate = new Date(this.date);
15835 newDate.setUTCDate(this.date.getUTCDate() + dir);
15836 newViewDate = new Date(this.viewDate);
15837 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15839 if (this.dateWithinRange(newDate)){
15840 this.date = newDate;
15841 this.viewDate = newViewDate;
15842 this.setValue(this.formatDate(this.date));
15844 e.preventDefault();
15845 dateChanged = true;
15850 if (!this.keyboardNavigation) break;
15851 dir = e.keyCode == 38 ? -1 : 1;
15853 newDate = this.moveYear(this.date, dir);
15854 newViewDate = this.moveYear(this.viewDate, dir);
15855 } else if (e.shiftKey){
15856 newDate = this.moveMonth(this.date, dir);
15857 newViewDate = this.moveMonth(this.viewDate, dir);
15859 newDate = new Date(this.date);
15860 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15861 newViewDate = new Date(this.viewDate);
15862 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15864 if (this.dateWithinRange(newDate)){
15865 this.date = newDate;
15866 this.viewDate = newViewDate;
15867 this.setValue(this.formatDate(this.date));
15869 e.preventDefault();
15870 dateChanged = true;
15874 this.setValue(this.formatDate(this.date));
15876 e.preventDefault();
15879 this.setValue(this.formatDate(this.date));
15893 onClick: function(e)
15895 e.stopPropagation();
15896 e.preventDefault();
15898 var target = e.getTarget();
15900 if(target.nodeName.toLowerCase() === 'i'){
15901 target = Roo.get(target).dom.parentNode;
15904 var nodeName = target.nodeName;
15905 var className = target.className;
15906 var html = target.innerHTML;
15907 //Roo.log(nodeName);
15909 switch(nodeName.toLowerCase()) {
15911 switch(className) {
15917 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15918 switch(this.viewMode){
15920 this.viewDate = this.moveMonth(this.viewDate, dir);
15924 this.viewDate = this.moveYear(this.viewDate, dir);
15930 var date = new Date();
15931 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15933 this.setValue(this.formatDate(this.date));
15940 if (className.indexOf('disabled') < 0) {
15941 this.viewDate.setUTCDate(1);
15942 if (className.indexOf('month') > -1) {
15943 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15945 var year = parseInt(html, 10) || 0;
15946 this.viewDate.setUTCFullYear(year);
15950 if(this.singleMode){
15951 this.setValue(this.formatDate(this.viewDate));
15962 //Roo.log(className);
15963 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15964 var day = parseInt(html, 10) || 1;
15965 var year = this.viewDate.getUTCFullYear(),
15966 month = this.viewDate.getUTCMonth();
15968 if (className.indexOf('old') > -1) {
15975 } else if (className.indexOf('new') > -1) {
15983 //Roo.log([year,month,day]);
15984 this.date = this.UTCDate(year, month, day,0,0,0,0);
15985 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15987 //Roo.log(this.formatDate(this.date));
15988 this.setValue(this.formatDate(this.date));
15995 setStartDate: function(startDate)
15997 this.startDate = startDate || -Infinity;
15998 if (this.startDate !== -Infinity) {
15999 this.startDate = this.parseDate(this.startDate);
16002 this.updateNavArrows();
16005 setEndDate: function(endDate)
16007 this.endDate = endDate || Infinity;
16008 if (this.endDate !== Infinity) {
16009 this.endDate = this.parseDate(this.endDate);
16012 this.updateNavArrows();
16015 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16017 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16018 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16019 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16021 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16022 return parseInt(d, 10);
16025 this.updateNavArrows();
16028 updateNavArrows: function()
16030 if(this.singleMode){
16034 var d = new Date(this.viewDate),
16035 year = d.getUTCFullYear(),
16036 month = d.getUTCMonth();
16038 Roo.each(this.picker().select('.prev', true).elements, function(v){
16040 switch (this.viewMode) {
16043 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16049 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16056 Roo.each(this.picker().select('.next', true).elements, function(v){
16058 switch (this.viewMode) {
16061 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16067 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16075 moveMonth: function(date, dir)
16077 if (!dir) return date;
16078 var new_date = new Date(date.valueOf()),
16079 day = new_date.getUTCDate(),
16080 month = new_date.getUTCMonth(),
16081 mag = Math.abs(dir),
16083 dir = dir > 0 ? 1 : -1;
16086 // If going back one month, make sure month is not current month
16087 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16089 return new_date.getUTCMonth() == month;
16091 // If going forward one month, make sure month is as expected
16092 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16094 return new_date.getUTCMonth() != new_month;
16096 new_month = month + dir;
16097 new_date.setUTCMonth(new_month);
16098 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16099 if (new_month < 0 || new_month > 11)
16100 new_month = (new_month + 12) % 12;
16102 // For magnitudes >1, move one month at a time...
16103 for (var i=0; i<mag; i++)
16104 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16105 new_date = this.moveMonth(new_date, dir);
16106 // ...then reset the day, keeping it in the new month
16107 new_month = new_date.getUTCMonth();
16108 new_date.setUTCDate(day);
16110 return new_month != new_date.getUTCMonth();
16113 // Common date-resetting loop -- if date is beyond end of month, make it
16116 new_date.setUTCDate(--day);
16117 new_date.setUTCMonth(new_month);
16122 moveYear: function(date, dir)
16124 return this.moveMonth(date, dir*12);
16127 dateWithinRange: function(date)
16129 return date >= this.startDate && date <= this.endDate;
16135 this.picker().remove();
16140 Roo.apply(Roo.bootstrap.DateField, {
16151 html: '<i class="fa fa-arrow-left"/>'
16161 html: '<i class="fa fa-arrow-right"/>'
16203 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16204 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16205 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16206 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16207 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16220 navFnc: 'FullYear',
16225 navFnc: 'FullYear',
16230 Roo.apply(Roo.bootstrap.DateField, {
16234 cls: 'datepicker dropdown-menu roo-dynamic',
16238 cls: 'datepicker-days',
16242 cls: 'table-condensed',
16244 Roo.bootstrap.DateField.head,
16248 Roo.bootstrap.DateField.footer
16255 cls: 'datepicker-months',
16259 cls: 'table-condensed',
16261 Roo.bootstrap.DateField.head,
16262 Roo.bootstrap.DateField.content,
16263 Roo.bootstrap.DateField.footer
16270 cls: 'datepicker-years',
16274 cls: 'table-condensed',
16276 Roo.bootstrap.DateField.head,
16277 Roo.bootstrap.DateField.content,
16278 Roo.bootstrap.DateField.footer
16297 * @class Roo.bootstrap.TimeField
16298 * @extends Roo.bootstrap.Input
16299 * Bootstrap DateField class
16303 * Create a new TimeField
16304 * @param {Object} config The config object
16307 Roo.bootstrap.TimeField = function(config){
16308 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16312 * Fires when this field show.
16313 * @param {Roo.bootstrap.DateField} thisthis
16314 * @param {Mixed} date The date value
16319 * Fires when this field hide.
16320 * @param {Roo.bootstrap.DateField} this
16321 * @param {Mixed} date The date value
16326 * Fires when select a date.
16327 * @param {Roo.bootstrap.DateField} this
16328 * @param {Mixed} date The date value
16334 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16337 * @cfg {String} format
16338 * The default time format string which can be overriden for localization support. The format must be
16339 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16343 onRender: function(ct, position)
16346 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16348 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16350 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16352 this.pop = this.picker().select('>.datepicker-time',true).first();
16353 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16355 this.picker().on('mousedown', this.onMousedown, this);
16356 this.picker().on('click', this.onClick, this);
16358 this.picker().addClass('datepicker-dropdown');
16363 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16364 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16365 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16366 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16367 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16368 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16372 fireKey: function(e){
16373 if (!this.picker().isVisible()){
16374 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16380 e.preventDefault();
16388 this.onTogglePeriod();
16391 this.onIncrementMinutes();
16394 this.onDecrementMinutes();
16403 onClick: function(e) {
16404 e.stopPropagation();
16405 e.preventDefault();
16408 picker : function()
16410 return this.el.select('.datepicker', true).first();
16413 fillTime: function()
16415 var time = this.pop.select('tbody', true).first();
16417 time.dom.innerHTML = '';
16432 cls: 'hours-up glyphicon glyphicon-chevron-up'
16452 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16473 cls: 'timepicker-hour',
16488 cls: 'timepicker-minute',
16503 cls: 'btn btn-primary period',
16525 cls: 'hours-down glyphicon glyphicon-chevron-down'
16545 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16563 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16570 var hours = this.time.getHours();
16571 var minutes = this.time.getMinutes();
16584 hours = hours - 12;
16588 hours = '0' + hours;
16592 minutes = '0' + minutes;
16595 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16596 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16597 this.pop.select('button', true).first().dom.innerHTML = period;
16603 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16605 var cls = ['bottom'];
16607 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16614 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16619 this.picker().addClass(cls.join('-'));
16623 Roo.each(cls, function(c){
16625 _this.picker().setTop(_this.inputEl().getHeight());
16629 _this.picker().setTop(0 - _this.picker().getHeight());
16634 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16638 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16645 onFocus : function()
16647 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16651 onBlur : function()
16653 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16659 this.picker().show();
16664 this.fireEvent('show', this, this.date);
16669 this.picker().hide();
16672 this.fireEvent('hide', this, this.date);
16675 setTime : function()
16678 this.setValue(this.time.format(this.format));
16680 this.fireEvent('select', this, this.date);
16685 onMousedown: function(e){
16686 e.stopPropagation();
16687 e.preventDefault();
16690 onIncrementHours: function()
16692 Roo.log('onIncrementHours');
16693 this.time = this.time.add(Date.HOUR, 1);
16698 onDecrementHours: function()
16700 Roo.log('onDecrementHours');
16701 this.time = this.time.add(Date.HOUR, -1);
16705 onIncrementMinutes: function()
16707 Roo.log('onIncrementMinutes');
16708 this.time = this.time.add(Date.MINUTE, 1);
16712 onDecrementMinutes: function()
16714 Roo.log('onDecrementMinutes');
16715 this.time = this.time.add(Date.MINUTE, -1);
16719 onTogglePeriod: function()
16721 Roo.log('onTogglePeriod');
16722 this.time = this.time.add(Date.HOUR, 12);
16729 Roo.apply(Roo.bootstrap.TimeField, {
16759 cls: 'btn btn-info ok',
16771 Roo.apply(Roo.bootstrap.TimeField, {
16775 cls: 'datepicker dropdown-menu',
16779 cls: 'datepicker-time',
16783 cls: 'table-condensed',
16785 Roo.bootstrap.TimeField.content,
16786 Roo.bootstrap.TimeField.footer
16805 * @class Roo.bootstrap.MonthField
16806 * @extends Roo.bootstrap.Input
16807 * Bootstrap MonthField class
16809 * @cfg {String} language default en
16812 * Create a new MonthField
16813 * @param {Object} config The config object
16816 Roo.bootstrap.MonthField = function(config){
16817 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16822 * Fires when this field show.
16823 * @param {Roo.bootstrap.MonthField} this
16824 * @param {Mixed} date The date value
16829 * Fires when this field hide.
16830 * @param {Roo.bootstrap.MonthField} this
16831 * @param {Mixed} date The date value
16836 * Fires when select a date.
16837 * @param {Roo.bootstrap.MonthField} this
16838 * @param {String} oldvalue The old value
16839 * @param {String} newvalue The new value
16845 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16847 onRender: function(ct, position)
16850 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16852 this.language = this.language || 'en';
16853 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16854 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16856 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16857 this.isInline = false;
16858 this.isInput = true;
16859 this.component = this.el.select('.add-on', true).first() || false;
16860 this.component = (this.component && this.component.length === 0) ? false : this.component;
16861 this.hasInput = this.component && this.inputEL().length;
16863 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16865 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16867 this.picker().on('mousedown', this.onMousedown, this);
16868 this.picker().on('click', this.onClick, this);
16870 this.picker().addClass('datepicker-dropdown');
16872 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16873 v.setStyle('width', '189px');
16880 if(this.isInline) {
16886 setValue: function(v, suppressEvent)
16888 var o = this.getValue();
16890 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16894 if(suppressEvent !== true){
16895 this.fireEvent('select', this, o, v);
16900 getValue: function()
16905 onClick: function(e)
16907 e.stopPropagation();
16908 e.preventDefault();
16910 var target = e.getTarget();
16912 if(target.nodeName.toLowerCase() === 'i'){
16913 target = Roo.get(target).dom.parentNode;
16916 var nodeName = target.nodeName;
16917 var className = target.className;
16918 var html = target.innerHTML;
16920 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16924 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16926 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16932 picker : function()
16934 return this.pickerEl;
16937 fillMonths: function()
16940 var months = this.picker().select('>.datepicker-months td', true).first();
16942 months.dom.innerHTML = '';
16948 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16951 months.createChild(month);
16960 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16961 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16964 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16965 e.removeClass('active');
16967 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16968 e.addClass('active');
16975 if(this.isInline) return;
16977 this.picker().removeClass(['bottom', 'top']);
16979 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16981 * place to the top of element!
16985 this.picker().addClass('top');
16986 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
16991 this.picker().addClass('bottom');
16993 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
16996 onFocus : function()
16998 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17002 onBlur : function()
17004 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17006 var d = this.inputEl().getValue();
17015 this.picker().show();
17016 this.picker().select('>.datepicker-months', true).first().show();
17020 this.fireEvent('show', this, this.date);
17025 if(this.isInline) return;
17026 this.picker().hide();
17027 this.fireEvent('hide', this, this.date);
17031 onMousedown: function(e)
17033 e.stopPropagation();
17034 e.preventDefault();
17039 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17043 fireKey: function(e)
17045 if (!this.picker().isVisible()){
17046 if (e.keyCode == 27) // allow escape to hide and re-show picker
17056 e.preventDefault();
17060 dir = e.keyCode == 37 ? -1 : 1;
17062 this.vIndex = this.vIndex + dir;
17064 if(this.vIndex < 0){
17068 if(this.vIndex > 11){
17072 if(isNaN(this.vIndex)){
17076 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17082 dir = e.keyCode == 38 ? -1 : 1;
17084 this.vIndex = this.vIndex + dir * 4;
17086 if(this.vIndex < 0){
17090 if(this.vIndex > 11){
17094 if(isNaN(this.vIndex)){
17098 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17103 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17104 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17108 e.preventDefault();
17111 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17112 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17128 this.picker().remove();
17133 Roo.apply(Roo.bootstrap.MonthField, {
17152 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17153 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17158 Roo.apply(Roo.bootstrap.MonthField, {
17162 cls: 'datepicker dropdown-menu roo-dynamic',
17166 cls: 'datepicker-months',
17170 cls: 'table-condensed',
17172 Roo.bootstrap.DateField.content
17192 * @class Roo.bootstrap.CheckBox
17193 * @extends Roo.bootstrap.Input
17194 * Bootstrap CheckBox class
17196 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17197 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17198 * @cfg {String} boxLabel The text that appears beside the checkbox
17199 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17200 * @cfg {Boolean} checked initnal the element
17201 * @cfg {Boolean} inline inline the element (default false)
17202 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17205 * Create a new CheckBox
17206 * @param {Object} config The config object
17209 Roo.bootstrap.CheckBox = function(config){
17210 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17215 * Fires when the element is checked or unchecked.
17216 * @param {Roo.bootstrap.CheckBox} this This input
17217 * @param {Boolean} checked The new checked value
17224 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17226 inputType: 'checkbox',
17234 getAutoCreate : function()
17236 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17242 cfg.cls = 'form-group ' + this.inputType; //input-group
17245 cfg.cls += ' ' + this.inputType + '-inline';
17251 type : this.inputType,
17252 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17253 cls : 'roo-' + this.inputType, //'form-box',
17254 placeholder : this.placeholder || ''
17258 if (this.weight) { // Validity check?
17259 cfg.cls += " " + this.inputType + "-" + this.weight;
17262 if (this.disabled) {
17263 input.disabled=true;
17267 input.checked = this.checked;
17271 input.name = this.name;
17275 input.cls += ' input-' + this.size;
17280 ['xs','sm','md','lg'].map(function(size){
17281 if (settings[size]) {
17282 cfg.cls += ' col-' + size + '-' + settings[size];
17286 var inputblock = input;
17288 if (this.before || this.after) {
17291 cls : 'input-group',
17296 inputblock.cn.push({
17298 cls : 'input-group-addon',
17303 inputblock.cn.push(input);
17306 inputblock.cn.push({
17308 cls : 'input-group-addon',
17315 if (align ==='left' && this.fieldLabel.length) {
17316 Roo.log("left and has label");
17322 cls : 'control-label col-md-' + this.labelWidth,
17323 html : this.fieldLabel
17327 cls : "col-md-" + (12 - this.labelWidth),
17334 } else if ( this.fieldLabel.length) {
17339 tag: this.boxLabel ? 'span' : 'label',
17341 cls: 'control-label box-input-label',
17342 //cls : 'input-group-addon',
17343 html : this.fieldLabel
17353 Roo.log(" no label && no align");
17354 cfg.cn = [ inputblock ] ;
17359 var boxLabelCfg = {
17361 //'for': id, // box label is handled by onclick - so no for...
17363 html: this.boxLabel
17367 boxLabelCfg.tooltip = this.tooltip;
17370 cfg.cn.push(boxLabelCfg);
17380 * return the real input element.
17382 inputEl: function ()
17384 return this.el.select('input.roo-' + this.inputType,true).first();
17387 labelEl: function()
17389 return this.el.select('label.control-label',true).first();
17391 /* depricated... */
17395 return this.labelEl();
17398 initEvents : function()
17400 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17402 this.inputEl().on('click', this.onClick, this);
17404 if (this.boxLabel) {
17405 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17408 this.startValue = this.getValue();
17411 Roo.bootstrap.CheckBox.register(this);
17415 onClick : function()
17417 this.setChecked(!this.checked);
17420 setChecked : function(state,suppressEvent)
17422 this.startValue = this.getValue();
17424 if(this.inputType == 'radio'){
17426 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17427 e.dom.checked = false;
17430 this.inputEl().dom.checked = true;
17432 this.inputEl().dom.value = this.inputValue;
17434 if(suppressEvent !== true){
17435 this.fireEvent('check', this, true);
17443 this.checked = state;
17445 this.inputEl().dom.checked = state;
17447 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17449 if(suppressEvent !== true){
17450 this.fireEvent('check', this, state);
17456 getValue : function()
17458 if(this.inputType == 'radio'){
17459 return this.getGroupValue();
17462 return this.inputEl().getValue();
17466 getGroupValue : function()
17468 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17472 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17475 setValue : function(v,suppressEvent)
17477 if(this.inputType == 'radio'){
17478 this.setGroupValue(v, suppressEvent);
17482 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17487 setGroupValue : function(v, suppressEvent)
17489 this.startValue = this.getValue();
17491 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17492 e.dom.checked = false;
17494 if(e.dom.value == v){
17495 e.dom.checked = true;
17499 if(suppressEvent !== true){
17500 this.fireEvent('check', this, true);
17508 validate : function()
17512 (this.inputType == 'radio' && this.validateRadio()) ||
17513 (this.inputType == 'checkbox' && this.validateCheckbox())
17519 this.markInvalid();
17523 validateRadio : function()
17527 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17528 if(!e.dom.checked){
17540 validateCheckbox : function()
17543 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17546 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17554 for(var i in group){
17559 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17566 * Mark this field as valid
17568 markValid : function()
17570 if(this.allowBlank){
17576 this.fireEvent('valid', this);
17578 if(this.inputType == 'radio'){
17579 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17580 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17581 e.findParent('.form-group', false, true).addClass(_this.validClass);
17588 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17589 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17593 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17599 for(var i in group){
17600 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17601 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17606 * Mark this field as invalid
17607 * @param {String} msg The validation message
17609 markInvalid : function(msg)
17611 if(this.allowBlank){
17617 this.fireEvent('invalid', this, msg);
17619 if(this.inputType == 'radio'){
17620 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17621 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17622 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17629 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17630 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17634 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17640 for(var i in group){
17641 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17642 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17649 Roo.apply(Roo.bootstrap.CheckBox, {
17654 * register a CheckBox Group
17655 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17657 register : function(checkbox)
17659 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17660 this.groups[checkbox.groupId] = {};
17663 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17667 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17671 * fetch a CheckBox Group based on the group ID
17672 * @param {string} the group ID
17673 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17675 get: function(groupId) {
17676 if (typeof(this.groups[groupId]) == 'undefined') {
17680 return this.groups[groupId] ;
17692 *<div class="radio">
17694 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17695 Option one is this and that—be sure to include why it's great
17702 *<label class="radio-inline">fieldLabel</label>
17703 *<label class="radio-inline">
17704 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17712 * @class Roo.bootstrap.Radio
17713 * @extends Roo.bootstrap.CheckBox
17714 * Bootstrap Radio class
17717 * Create a new Radio
17718 * @param {Object} config The config object
17721 Roo.bootstrap.Radio = function(config){
17722 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17726 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17728 inputType: 'radio',
17732 getAutoCreate : function()
17734 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17735 align = align || 'left'; // default...
17742 tag : this.inline ? 'span' : 'div',
17747 var inline = this.inline ? ' radio-inline' : '';
17751 // does not need for, as we wrap the input with it..
17753 cls : 'control-label box-label' + inline,
17756 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17760 //cls : 'control-label' + inline,
17761 html : this.fieldLabel,
17762 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17771 type : this.inputType,
17772 //value : (!this.checked) ? this.valueOff : this.inputValue,
17773 value : this.inputValue,
17775 placeholder : this.placeholder || '' // ?? needed????
17778 if (this.weight) { // Validity check?
17779 input.cls += " radio-" + this.weight;
17781 if (this.disabled) {
17782 input.disabled=true;
17786 input.checked = this.checked;
17790 input.name = this.name;
17794 input.cls += ' input-' + this.size;
17797 //?? can span's inline have a width??
17800 ['xs','sm','md','lg'].map(function(size){
17801 if (settings[size]) {
17802 cfg.cls += ' col-' + size + '-' + settings[size];
17806 var inputblock = input;
17808 if (this.before || this.after) {
17811 cls : 'input-group',
17816 inputblock.cn.push({
17818 cls : 'input-group-addon',
17822 inputblock.cn.push(input);
17824 inputblock.cn.push({
17826 cls : 'input-group-addon',
17834 if (this.fieldLabel && this.fieldLabel.length) {
17835 cfg.cn.push(fieldLabel);
17838 // normal bootstrap puts the input inside the label.
17839 // however with our styled version - it has to go after the input.
17841 //lbl.cn.push(inputblock);
17845 cls: 'radio' + inline,
17852 cfg.cn.push( lblwrap);
17857 html: this.boxLabel
17866 initEvents : function()
17868 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17870 this.inputEl().on('click', this.onClick, this);
17871 if (this.boxLabel) {
17872 Roo.log('find label')
17873 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17878 inputEl: function ()
17880 return this.el.select('input.roo-radio',true).first();
17882 onClick : function()
17885 this.setChecked(true);
17888 setChecked : function(state,suppressEvent)
17891 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17892 v.dom.checked = false;
17895 Roo.log(this.inputEl().dom);
17896 this.checked = state;
17897 this.inputEl().dom.checked = state;
17899 if(suppressEvent !== true){
17900 this.fireEvent('check', this, state);
17903 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17907 getGroupValue : function()
17910 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17911 if(v.dom.checked == true){
17912 value = v.dom.value;
17920 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17921 * @return {Mixed} value The field value
17923 getValue : function(){
17924 return this.getGroupValue();
17930 //<script type="text/javascript">
17933 * Based Ext JS Library 1.1.1
17934 * Copyright(c) 2006-2007, Ext JS, LLC.
17940 * @class Roo.HtmlEditorCore
17941 * @extends Roo.Component
17942 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17944 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17947 Roo.HtmlEditorCore = function(config){
17950 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17955 * @event initialize
17956 * Fires when the editor is fully initialized (including the iframe)
17957 * @param {Roo.HtmlEditorCore} this
17962 * Fires when the editor is first receives the focus. Any insertion must wait
17963 * until after this event.
17964 * @param {Roo.HtmlEditorCore} this
17968 * @event beforesync
17969 * Fires before the textarea is updated with content from the editor iframe. Return false
17970 * to cancel the sync.
17971 * @param {Roo.HtmlEditorCore} this
17972 * @param {String} html
17976 * @event beforepush
17977 * Fires before the iframe editor is updated with content from the textarea. Return false
17978 * to cancel the push.
17979 * @param {Roo.HtmlEditorCore} this
17980 * @param {String} html
17985 * Fires when the textarea is updated with content from the editor iframe.
17986 * @param {Roo.HtmlEditorCore} this
17987 * @param {String} html
17992 * Fires when the iframe editor is updated with content from the textarea.
17993 * @param {Roo.HtmlEditorCore} this
17994 * @param {String} html
17999 * @event editorevent
18000 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18001 * @param {Roo.HtmlEditorCore} this
18007 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18009 // defaults : white / black...
18010 this.applyBlacklists();
18017 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18021 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18027 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18032 * @cfg {Number} height (in pixels)
18036 * @cfg {Number} width (in pixels)
18041 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18044 stylesheets: false,
18049 // private properties
18050 validationEvent : false,
18052 initialized : false,
18054 sourceEditMode : false,
18055 onFocus : Roo.emptyFn,
18057 hideMode:'offsets',
18061 // blacklist + whitelisted elements..
18068 * Protected method that will not generally be called directly. It
18069 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18070 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18072 getDocMarkup : function(){
18076 // inherit styels from page...??
18077 if (this.stylesheets === false) {
18079 Roo.get(document.head).select('style').each(function(node) {
18080 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18083 Roo.get(document.head).select('link').each(function(node) {
18084 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18087 } else if (!this.stylesheets.length) {
18089 st = '<style type="text/css">' +
18090 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18096 st += '<style type="text/css">' +
18097 'IMG { cursor: pointer } ' +
18101 return '<html><head>' + st +
18102 //<style type="text/css">' +
18103 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18105 ' </head><body class="roo-htmleditor-body"></body></html>';
18109 onRender : function(ct, position)
18112 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18113 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18116 this.el.dom.style.border = '0 none';
18117 this.el.dom.setAttribute('tabIndex', -1);
18118 this.el.addClass('x-hidden hide');
18122 if(Roo.isIE){ // fix IE 1px bogus margin
18123 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18127 this.frameId = Roo.id();
18131 var iframe = this.owner.wrap.createChild({
18133 cls: 'form-control', // bootstrap..
18135 name: this.frameId,
18136 frameBorder : 'no',
18137 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18142 this.iframe = iframe.dom;
18144 this.assignDocWin();
18146 this.doc.designMode = 'on';
18149 this.doc.write(this.getDocMarkup());
18153 var task = { // must defer to wait for browser to be ready
18155 //console.log("run task?" + this.doc.readyState);
18156 this.assignDocWin();
18157 if(this.doc.body || this.doc.readyState == 'complete'){
18159 this.doc.designMode="on";
18163 Roo.TaskMgr.stop(task);
18164 this.initEditor.defer(10, this);
18171 Roo.TaskMgr.start(task);
18176 onResize : function(w, h)
18178 Roo.log('resize: ' +w + ',' + h );
18179 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18183 if(typeof w == 'number'){
18185 this.iframe.style.width = w + 'px';
18187 if(typeof h == 'number'){
18189 this.iframe.style.height = h + 'px';
18191 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18198 * Toggles the editor between standard and source edit mode.
18199 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18201 toggleSourceEdit : function(sourceEditMode){
18203 this.sourceEditMode = sourceEditMode === true;
18205 if(this.sourceEditMode){
18207 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18210 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18211 //this.iframe.className = '';
18214 //this.setSize(this.owner.wrap.getSize());
18215 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18222 * Protected method that will not generally be called directly. If you need/want
18223 * custom HTML cleanup, this is the method you should override.
18224 * @param {String} html The HTML to be cleaned
18225 * return {String} The cleaned HTML
18227 cleanHtml : function(html){
18228 html = String(html);
18229 if(html.length > 5){
18230 if(Roo.isSafari){ // strip safari nonsense
18231 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18234 if(html == ' '){
18241 * HTML Editor -> Textarea
18242 * Protected method that will not generally be called directly. Syncs the contents
18243 * of the editor iframe with the textarea.
18245 syncValue : function(){
18246 if(this.initialized){
18247 var bd = (this.doc.body || this.doc.documentElement);
18248 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18249 var html = bd.innerHTML;
18251 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18252 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18254 html = '<div style="'+m[0]+'">' + html + '</div>';
18257 html = this.cleanHtml(html);
18258 // fix up the special chars.. normaly like back quotes in word...
18259 // however we do not want to do this with chinese..
18260 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18261 var cc = b.charCodeAt();
18263 (cc >= 0x4E00 && cc < 0xA000 ) ||
18264 (cc >= 0x3400 && cc < 0x4E00 ) ||
18265 (cc >= 0xf900 && cc < 0xfb00 )
18271 if(this.owner.fireEvent('beforesync', this, html) !== false){
18272 this.el.dom.value = html;
18273 this.owner.fireEvent('sync', this, html);
18279 * Protected method that will not generally be called directly. Pushes the value of the textarea
18280 * into the iframe editor.
18282 pushValue : function(){
18283 if(this.initialized){
18284 var v = this.el.dom.value.trim();
18286 // if(v.length < 1){
18290 if(this.owner.fireEvent('beforepush', this, v) !== false){
18291 var d = (this.doc.body || this.doc.documentElement);
18293 this.cleanUpPaste();
18294 this.el.dom.value = d.innerHTML;
18295 this.owner.fireEvent('push', this, v);
18301 deferFocus : function(){
18302 this.focus.defer(10, this);
18306 focus : function(){
18307 if(this.win && !this.sourceEditMode){
18314 assignDocWin: function()
18316 var iframe = this.iframe;
18319 this.doc = iframe.contentWindow.document;
18320 this.win = iframe.contentWindow;
18322 // if (!Roo.get(this.frameId)) {
18325 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18326 // this.win = Roo.get(this.frameId).dom.contentWindow;
18328 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18332 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18333 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18338 initEditor : function(){
18339 //console.log("INIT EDITOR");
18340 this.assignDocWin();
18344 this.doc.designMode="on";
18346 this.doc.write(this.getDocMarkup());
18349 var dbody = (this.doc.body || this.doc.documentElement);
18350 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18351 // this copies styles from the containing element into thsi one..
18352 // not sure why we need all of this..
18353 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18355 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18356 //ss['background-attachment'] = 'fixed'; // w3c
18357 dbody.bgProperties = 'fixed'; // ie
18358 //Roo.DomHelper.applyStyles(dbody, ss);
18359 Roo.EventManager.on(this.doc, {
18360 //'mousedown': this.onEditorEvent,
18361 'mouseup': this.onEditorEvent,
18362 'dblclick': this.onEditorEvent,
18363 'click': this.onEditorEvent,
18364 'keyup': this.onEditorEvent,
18369 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18371 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18372 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18374 this.initialized = true;
18376 this.owner.fireEvent('initialize', this);
18381 onDestroy : function(){
18387 //for (var i =0; i < this.toolbars.length;i++) {
18388 // // fixme - ask toolbars for heights?
18389 // this.toolbars[i].onDestroy();
18392 //this.wrap.dom.innerHTML = '';
18393 //this.wrap.remove();
18398 onFirstFocus : function(){
18400 this.assignDocWin();
18403 this.activated = true;
18406 if(Roo.isGecko){ // prevent silly gecko errors
18408 var s = this.win.getSelection();
18409 if(!s.focusNode || s.focusNode.nodeType != 3){
18410 var r = s.getRangeAt(0);
18411 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18416 this.execCmd('useCSS', true);
18417 this.execCmd('styleWithCSS', false);
18420 this.owner.fireEvent('activate', this);
18424 adjustFont: function(btn){
18425 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18426 //if(Roo.isSafari){ // safari
18429 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18430 if(Roo.isSafari){ // safari
18431 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18432 v = (v < 10) ? 10 : v;
18433 v = (v > 48) ? 48 : v;
18434 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18439 v = Math.max(1, v+adjust);
18441 this.execCmd('FontSize', v );
18444 onEditorEvent : function(e){
18445 this.owner.fireEvent('editorevent', this, e);
18446 // this.updateToolbar();
18447 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18450 insertTag : function(tg)
18452 // could be a bit smarter... -> wrap the current selected tRoo..
18453 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18455 range = this.createRange(this.getSelection());
18456 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18457 wrappingNode.appendChild(range.extractContents());
18458 range.insertNode(wrappingNode);
18465 this.execCmd("formatblock", tg);
18469 insertText : function(txt)
18473 var range = this.createRange();
18474 range.deleteContents();
18475 //alert(Sender.getAttribute('label'));
18477 range.insertNode(this.doc.createTextNode(txt));
18483 * Executes a Midas editor command on the editor document and performs necessary focus and
18484 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18485 * @param {String} cmd The Midas command
18486 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18488 relayCmd : function(cmd, value){
18490 this.execCmd(cmd, value);
18491 this.owner.fireEvent('editorevent', this);
18492 //this.updateToolbar();
18493 this.owner.deferFocus();
18497 * Executes a Midas editor command directly on the editor document.
18498 * For visual commands, you should use {@link #relayCmd} instead.
18499 * <b>This should only be called after the editor is initialized.</b>
18500 * @param {String} cmd The Midas command
18501 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18503 execCmd : function(cmd, value){
18504 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18511 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18513 * @param {String} text | dom node..
18515 insertAtCursor : function(text)
18520 if(!this.activated){
18526 var r = this.doc.selection.createRange();
18537 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18541 // from jquery ui (MIT licenced)
18543 var win = this.win;
18545 if (win.getSelection && win.getSelection().getRangeAt) {
18546 range = win.getSelection().getRangeAt(0);
18547 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18548 range.insertNode(node);
18549 } else if (win.document.selection && win.document.selection.createRange) {
18550 // no firefox support
18551 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18552 win.document.selection.createRange().pasteHTML(txt);
18554 // no firefox support
18555 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18556 this.execCmd('InsertHTML', txt);
18565 mozKeyPress : function(e){
18567 var c = e.getCharCode(), cmd;
18570 c = String.fromCharCode(c).toLowerCase();
18584 this.cleanUpPaste.defer(100, this);
18592 e.preventDefault();
18600 fixKeys : function(){ // load time branching for fastest keydown performance
18602 return function(e){
18603 var k = e.getKey(), r;
18606 r = this.doc.selection.createRange();
18609 r.pasteHTML('    ');
18616 r = this.doc.selection.createRange();
18618 var target = r.parentElement();
18619 if(!target || target.tagName.toLowerCase() != 'li'){
18621 r.pasteHTML('<br />');
18627 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18628 this.cleanUpPaste.defer(100, this);
18634 }else if(Roo.isOpera){
18635 return function(e){
18636 var k = e.getKey();
18640 this.execCmd('InsertHTML','    ');
18643 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18644 this.cleanUpPaste.defer(100, this);
18649 }else if(Roo.isSafari){
18650 return function(e){
18651 var k = e.getKey();
18655 this.execCmd('InsertText','\t');
18659 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18660 this.cleanUpPaste.defer(100, this);
18668 getAllAncestors: function()
18670 var p = this.getSelectedNode();
18673 a.push(p); // push blank onto stack..
18674 p = this.getParentElement();
18678 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18682 a.push(this.doc.body);
18686 lastSelNode : false,
18689 getSelection : function()
18691 this.assignDocWin();
18692 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18695 getSelectedNode: function()
18697 // this may only work on Gecko!!!
18699 // should we cache this!!!!
18704 var range = this.createRange(this.getSelection()).cloneRange();
18707 var parent = range.parentElement();
18709 var testRange = range.duplicate();
18710 testRange.moveToElementText(parent);
18711 if (testRange.inRange(range)) {
18714 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18717 parent = parent.parentElement;
18722 // is ancestor a text element.
18723 var ac = range.commonAncestorContainer;
18724 if (ac.nodeType == 3) {
18725 ac = ac.parentNode;
18728 var ar = ac.childNodes;
18731 var other_nodes = [];
18732 var has_other_nodes = false;
18733 for (var i=0;i<ar.length;i++) {
18734 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18737 // fullly contained node.
18739 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18744 // probably selected..
18745 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18746 other_nodes.push(ar[i]);
18750 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18755 has_other_nodes = true;
18757 if (!nodes.length && other_nodes.length) {
18758 nodes= other_nodes;
18760 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18766 createRange: function(sel)
18768 // this has strange effects when using with
18769 // top toolbar - not sure if it's a great idea.
18770 //this.editor.contentWindow.focus();
18771 if (typeof sel != "undefined") {
18773 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18775 return this.doc.createRange();
18778 return this.doc.createRange();
18781 getParentElement: function()
18784 this.assignDocWin();
18785 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18787 var range = this.createRange(sel);
18790 var p = range.commonAncestorContainer;
18791 while (p.nodeType == 3) { // text node
18802 * Range intersection.. the hard stuff...
18806 * [ -- selected range --- ]
18810 * if end is before start or hits it. fail.
18811 * if start is after end or hits it fail.
18813 * if either hits (but other is outside. - then it's not
18819 // @see http://www.thismuchiknow.co.uk/?p=64.
18820 rangeIntersectsNode : function(range, node)
18822 var nodeRange = node.ownerDocument.createRange();
18824 nodeRange.selectNode(node);
18826 nodeRange.selectNodeContents(node);
18829 var rangeStartRange = range.cloneRange();
18830 rangeStartRange.collapse(true);
18832 var rangeEndRange = range.cloneRange();
18833 rangeEndRange.collapse(false);
18835 var nodeStartRange = nodeRange.cloneRange();
18836 nodeStartRange.collapse(true);
18838 var nodeEndRange = nodeRange.cloneRange();
18839 nodeEndRange.collapse(false);
18841 return rangeStartRange.compareBoundaryPoints(
18842 Range.START_TO_START, nodeEndRange) == -1 &&
18843 rangeEndRange.compareBoundaryPoints(
18844 Range.START_TO_START, nodeStartRange) == 1;
18848 rangeCompareNode : function(range, node)
18850 var nodeRange = node.ownerDocument.createRange();
18852 nodeRange.selectNode(node);
18854 nodeRange.selectNodeContents(node);
18858 range.collapse(true);
18860 nodeRange.collapse(true);
18862 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18863 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18865 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18867 var nodeIsBefore = ss == 1;
18868 var nodeIsAfter = ee == -1;
18870 if (nodeIsBefore && nodeIsAfter)
18872 if (!nodeIsBefore && nodeIsAfter)
18873 return 1; //right trailed.
18875 if (nodeIsBefore && !nodeIsAfter)
18876 return 2; // left trailed.
18881 // private? - in a new class?
18882 cleanUpPaste : function()
18884 // cleans up the whole document..
18885 Roo.log('cleanuppaste');
18887 this.cleanUpChildren(this.doc.body);
18888 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18889 if (clean != this.doc.body.innerHTML) {
18890 this.doc.body.innerHTML = clean;
18895 cleanWordChars : function(input) {// change the chars to hex code
18896 var he = Roo.HtmlEditorCore;
18898 var output = input;
18899 Roo.each(he.swapCodes, function(sw) {
18900 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18902 output = output.replace(swapper, sw[1]);
18909 cleanUpChildren : function (n)
18911 if (!n.childNodes.length) {
18914 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18915 this.cleanUpChild(n.childNodes[i]);
18922 cleanUpChild : function (node)
18925 //console.log(node);
18926 if (node.nodeName == "#text") {
18927 // clean up silly Windows -- stuff?
18930 if (node.nodeName == "#comment") {
18931 node.parentNode.removeChild(node);
18932 // clean up silly Windows -- stuff?
18935 var lcname = node.tagName.toLowerCase();
18936 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18937 // whitelist of tags..
18939 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18941 node.parentNode.removeChild(node);
18946 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18948 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18949 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18951 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18952 // remove_keep_children = true;
18955 if (remove_keep_children) {
18956 this.cleanUpChildren(node);
18957 // inserts everything just before this node...
18958 while (node.childNodes.length) {
18959 var cn = node.childNodes[0];
18960 node.removeChild(cn);
18961 node.parentNode.insertBefore(cn, node);
18963 node.parentNode.removeChild(node);
18967 if (!node.attributes || !node.attributes.length) {
18968 this.cleanUpChildren(node);
18972 function cleanAttr(n,v)
18975 if (v.match(/^\./) || v.match(/^\//)) {
18978 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18981 if (v.match(/^#/)) {
18984 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18985 node.removeAttribute(n);
18989 var cwhite = this.cwhite;
18990 var cblack = this.cblack;
18992 function cleanStyle(n,v)
18994 if (v.match(/expression/)) { //XSS?? should we even bother..
18995 node.removeAttribute(n);
18999 var parts = v.split(/;/);
19002 Roo.each(parts, function(p) {
19003 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19007 var l = p.split(':').shift().replace(/\s+/g,'');
19008 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19010 if ( cwhite.length && cblack.indexOf(l) > -1) {
19011 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19012 //node.removeAttribute(n);
19016 // only allow 'c whitelisted system attributes'
19017 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19018 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19019 //node.removeAttribute(n);
19029 if (clean.length) {
19030 node.setAttribute(n, clean.join(';'));
19032 node.removeAttribute(n);
19038 for (var i = node.attributes.length-1; i > -1 ; i--) {
19039 var a = node.attributes[i];
19042 if (a.name.toLowerCase().substr(0,2)=='on') {
19043 node.removeAttribute(a.name);
19046 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19047 node.removeAttribute(a.name);
19050 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19051 cleanAttr(a.name,a.value); // fixme..
19054 if (a.name == 'style') {
19055 cleanStyle(a.name,a.value);
19058 /// clean up MS crap..
19059 // tecnically this should be a list of valid class'es..
19062 if (a.name == 'class') {
19063 if (a.value.match(/^Mso/)) {
19064 node.className = '';
19067 if (a.value.match(/body/)) {
19068 node.className = '';
19079 this.cleanUpChildren(node);
19084 * Clean up MS wordisms...
19086 cleanWord : function(node)
19089 var cleanWordChildren = function()
19091 if (!node.childNodes.length) {
19094 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19095 _t.cleanWord(node.childNodes[i]);
19101 this.cleanWord(this.doc.body);
19104 if (node.nodeName == "#text") {
19105 // clean up silly Windows -- stuff?
19108 if (node.nodeName == "#comment") {
19109 node.parentNode.removeChild(node);
19110 // clean up silly Windows -- stuff?
19114 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19115 node.parentNode.removeChild(node);
19119 // remove - but keep children..
19120 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19121 while (node.childNodes.length) {
19122 var cn = node.childNodes[0];
19123 node.removeChild(cn);
19124 node.parentNode.insertBefore(cn, node);
19126 node.parentNode.removeChild(node);
19127 cleanWordChildren();
19131 if (node.className.length) {
19133 var cn = node.className.split(/\W+/);
19135 Roo.each(cn, function(cls) {
19136 if (cls.match(/Mso[a-zA-Z]+/)) {
19141 node.className = cna.length ? cna.join(' ') : '';
19143 node.removeAttribute("class");
19147 if (node.hasAttribute("lang")) {
19148 node.removeAttribute("lang");
19151 if (node.hasAttribute("style")) {
19153 var styles = node.getAttribute("style").split(";");
19155 Roo.each(styles, function(s) {
19156 if (!s.match(/:/)) {
19159 var kv = s.split(":");
19160 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19163 // what ever is left... we allow.
19166 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19167 if (!nstyle.length) {
19168 node.removeAttribute('style');
19172 cleanWordChildren();
19176 domToHTML : function(currentElement, depth, nopadtext) {
19178 depth = depth || 0;
19179 nopadtext = nopadtext || false;
19181 if (!currentElement) {
19182 return this.domToHTML(this.doc.body);
19185 //Roo.log(currentElement);
19187 var allText = false;
19188 var nodeName = currentElement.nodeName;
19189 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19191 if (nodeName == '#text') {
19193 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19198 if (nodeName != 'BODY') {
19201 // Prints the node tagName, such as <A>, <IMG>, etc
19204 for(i = 0; i < currentElement.attributes.length;i++) {
19206 var aname = currentElement.attributes.item(i).name;
19207 if (!currentElement.attributes.item(i).value.length) {
19210 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19213 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19222 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19225 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19230 // Traverse the tree
19232 var currentElementChild = currentElement.childNodes.item(i);
19233 var allText = true;
19234 var innerHTML = '';
19236 while (currentElementChild) {
19237 // Formatting code (indent the tree so it looks nice on the screen)
19238 var nopad = nopadtext;
19239 if (lastnode == 'SPAN') {
19243 if (currentElementChild.nodeName == '#text') {
19244 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19245 toadd = nopadtext ? toadd : toadd.trim();
19246 if (!nopad && toadd.length > 80) {
19247 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19249 innerHTML += toadd;
19252 currentElementChild = currentElement.childNodes.item(i);
19258 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19260 // Recursively traverse the tree structure of the child node
19261 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19262 lastnode = currentElementChild.nodeName;
19264 currentElementChild=currentElement.childNodes.item(i);
19270 // The remaining code is mostly for formatting the tree
19271 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19276 ret+= "</"+tagName+">";
19282 applyBlacklists : function()
19284 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19285 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19289 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19290 if (b.indexOf(tag) > -1) {
19293 this.white.push(tag);
19297 Roo.each(w, function(tag) {
19298 if (b.indexOf(tag) > -1) {
19301 if (this.white.indexOf(tag) > -1) {
19304 this.white.push(tag);
19309 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19310 if (w.indexOf(tag) > -1) {
19313 this.black.push(tag);
19317 Roo.each(b, function(tag) {
19318 if (w.indexOf(tag) > -1) {
19321 if (this.black.indexOf(tag) > -1) {
19324 this.black.push(tag);
19329 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19330 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19334 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19335 if (b.indexOf(tag) > -1) {
19338 this.cwhite.push(tag);
19342 Roo.each(w, function(tag) {
19343 if (b.indexOf(tag) > -1) {
19346 if (this.cwhite.indexOf(tag) > -1) {
19349 this.cwhite.push(tag);
19354 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19355 if (w.indexOf(tag) > -1) {
19358 this.cblack.push(tag);
19362 Roo.each(b, function(tag) {
19363 if (w.indexOf(tag) > -1) {
19366 if (this.cblack.indexOf(tag) > -1) {
19369 this.cblack.push(tag);
19374 setStylesheets : function(stylesheets)
19376 if(typeof(stylesheets) == 'string'){
19377 Roo.get(this.iframe.contentDocument.head).createChild({
19379 rel : 'stylesheet',
19388 Roo.each(stylesheets, function(s) {
19393 Roo.get(_this.iframe.contentDocument.head).createChild({
19395 rel : 'stylesheet',
19404 removeStylesheets : function()
19408 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19413 // hide stuff that is not compatible
19427 * @event specialkey
19431 * @cfg {String} fieldClass @hide
19434 * @cfg {String} focusClass @hide
19437 * @cfg {String} autoCreate @hide
19440 * @cfg {String} inputType @hide
19443 * @cfg {String} invalidClass @hide
19446 * @cfg {String} invalidText @hide
19449 * @cfg {String} msgFx @hide
19452 * @cfg {String} validateOnBlur @hide
19456 Roo.HtmlEditorCore.white = [
19457 'area', 'br', 'img', 'input', 'hr', 'wbr',
19459 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19460 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19461 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19462 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19463 'table', 'ul', 'xmp',
19465 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19468 'dir', 'menu', 'ol', 'ul', 'dl',
19474 Roo.HtmlEditorCore.black = [
19475 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19477 'base', 'basefont', 'bgsound', 'blink', 'body',
19478 'frame', 'frameset', 'head', 'html', 'ilayer',
19479 'iframe', 'layer', 'link', 'meta', 'object',
19480 'script', 'style' ,'title', 'xml' // clean later..
19482 Roo.HtmlEditorCore.clean = [
19483 'script', 'style', 'title', 'xml'
19485 Roo.HtmlEditorCore.remove = [
19490 Roo.HtmlEditorCore.ablack = [
19494 Roo.HtmlEditorCore.aclean = [
19495 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19499 Roo.HtmlEditorCore.pwhite= [
19500 'http', 'https', 'mailto'
19503 // white listed style attributes.
19504 Roo.HtmlEditorCore.cwhite= [
19505 // 'text-align', /// default is to allow most things..
19511 // black listed style attributes.
19512 Roo.HtmlEditorCore.cblack= [
19513 // 'font-size' -- this can be set by the project
19517 Roo.HtmlEditorCore.swapCodes =[
19536 * @class Roo.bootstrap.HtmlEditor
19537 * @extends Roo.bootstrap.TextArea
19538 * Bootstrap HtmlEditor class
19541 * Create a new HtmlEditor
19542 * @param {Object} config The config object
19545 Roo.bootstrap.HtmlEditor = function(config){
19546 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19547 if (!this.toolbars) {
19548 this.toolbars = [];
19550 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19553 * @event initialize
19554 * Fires when the editor is fully initialized (including the iframe)
19555 * @param {HtmlEditor} this
19560 * Fires when the editor is first receives the focus. Any insertion must wait
19561 * until after this event.
19562 * @param {HtmlEditor} this
19566 * @event beforesync
19567 * Fires before the textarea is updated with content from the editor iframe. Return false
19568 * to cancel the sync.
19569 * @param {HtmlEditor} this
19570 * @param {String} html
19574 * @event beforepush
19575 * Fires before the iframe editor is updated with content from the textarea. Return false
19576 * to cancel the push.
19577 * @param {HtmlEditor} this
19578 * @param {String} html
19583 * Fires when the textarea is updated with content from the editor iframe.
19584 * @param {HtmlEditor} this
19585 * @param {String} html
19590 * Fires when the iframe editor is updated with content from the textarea.
19591 * @param {HtmlEditor} this
19592 * @param {String} html
19596 * @event editmodechange
19597 * Fires when the editor switches edit modes
19598 * @param {HtmlEditor} this
19599 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19601 editmodechange: true,
19603 * @event editorevent
19604 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19605 * @param {HtmlEditor} this
19609 * @event firstfocus
19610 * Fires when on first focus - needed by toolbars..
19611 * @param {HtmlEditor} this
19616 * Auto save the htmlEditor value as a file into Events
19617 * @param {HtmlEditor} this
19621 * @event savedpreview
19622 * preview the saved version of htmlEditor
19623 * @param {HtmlEditor} this
19630 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19634 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19639 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19644 * @cfg {Number} height (in pixels)
19648 * @cfg {Number} width (in pixels)
19653 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19656 stylesheets: false,
19661 // private properties
19662 validationEvent : false,
19664 initialized : false,
19667 onFocus : Roo.emptyFn,
19669 hideMode:'offsets',
19672 tbContainer : false,
19674 toolbarContainer :function() {
19675 return this.wrap.select('.x-html-editor-tb',true).first();
19679 * Protected method that will not generally be called directly. It
19680 * is called when the editor creates its toolbar. Override this method if you need to
19681 * add custom toolbar buttons.
19682 * @param {HtmlEditor} editor
19684 createToolbar : function(){
19686 Roo.log("create toolbars");
19688 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19689 this.toolbars[0].render(this.toolbarContainer());
19693 // if (!editor.toolbars || !editor.toolbars.length) {
19694 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19697 // for (var i =0 ; i < editor.toolbars.length;i++) {
19698 // editor.toolbars[i] = Roo.factory(
19699 // typeof(editor.toolbars[i]) == 'string' ?
19700 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19701 // Roo.bootstrap.HtmlEditor);
19702 // editor.toolbars[i].init(editor);
19708 onRender : function(ct, position)
19710 // Roo.log("Call onRender: " + this.xtype);
19712 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19714 this.wrap = this.inputEl().wrap({
19715 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19718 this.editorcore.onRender(ct, position);
19720 if (this.resizable) {
19721 this.resizeEl = new Roo.Resizable(this.wrap, {
19725 minHeight : this.height,
19726 height: this.height,
19727 handles : this.resizable,
19730 resize : function(r, w, h) {
19731 _t.onResize(w,h); // -something
19737 this.createToolbar(this);
19740 if(!this.width && this.resizable){
19741 this.setSize(this.wrap.getSize());
19743 if (this.resizeEl) {
19744 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19745 // should trigger onReize..
19751 onResize : function(w, h)
19753 Roo.log('resize: ' +w + ',' + h );
19754 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19758 if(this.inputEl() ){
19759 if(typeof w == 'number'){
19760 var aw = w - this.wrap.getFrameWidth('lr');
19761 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19764 if(typeof h == 'number'){
19765 var tbh = -11; // fixme it needs to tool bar size!
19766 for (var i =0; i < this.toolbars.length;i++) {
19767 // fixme - ask toolbars for heights?
19768 tbh += this.toolbars[i].el.getHeight();
19769 //if (this.toolbars[i].footer) {
19770 // tbh += this.toolbars[i].footer.el.getHeight();
19778 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19779 ah -= 5; // knock a few pixes off for look..
19780 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19784 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19785 this.editorcore.onResize(ew,eh);
19790 * Toggles the editor between standard and source edit mode.
19791 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19793 toggleSourceEdit : function(sourceEditMode)
19795 this.editorcore.toggleSourceEdit(sourceEditMode);
19797 if(this.editorcore.sourceEditMode){
19798 Roo.log('editor - showing textarea');
19801 // Roo.log(this.syncValue());
19803 this.inputEl().removeClass(['hide', 'x-hidden']);
19804 this.inputEl().dom.removeAttribute('tabIndex');
19805 this.inputEl().focus();
19807 Roo.log('editor - hiding textarea');
19809 // Roo.log(this.pushValue());
19812 this.inputEl().addClass(['hide', 'x-hidden']);
19813 this.inputEl().dom.setAttribute('tabIndex', -1);
19814 //this.deferFocus();
19817 if(this.resizable){
19818 this.setSize(this.wrap.getSize());
19821 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19824 // private (for BoxComponent)
19825 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19827 // private (for BoxComponent)
19828 getResizeEl : function(){
19832 // private (for BoxComponent)
19833 getPositionEl : function(){
19838 initEvents : function(){
19839 this.originalValue = this.getValue();
19843 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19846 // markInvalid : Roo.emptyFn,
19848 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19851 // clearInvalid : Roo.emptyFn,
19853 setValue : function(v){
19854 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19855 this.editorcore.pushValue();
19860 deferFocus : function(){
19861 this.focus.defer(10, this);
19865 focus : function(){
19866 this.editorcore.focus();
19872 onDestroy : function(){
19878 for (var i =0; i < this.toolbars.length;i++) {
19879 // fixme - ask toolbars for heights?
19880 this.toolbars[i].onDestroy();
19883 this.wrap.dom.innerHTML = '';
19884 this.wrap.remove();
19889 onFirstFocus : function(){
19890 //Roo.log("onFirstFocus");
19891 this.editorcore.onFirstFocus();
19892 for (var i =0; i < this.toolbars.length;i++) {
19893 this.toolbars[i].onFirstFocus();
19899 syncValue : function()
19901 this.editorcore.syncValue();
19904 pushValue : function()
19906 this.editorcore.pushValue();
19910 // hide stuff that is not compatible
19924 * @event specialkey
19928 * @cfg {String} fieldClass @hide
19931 * @cfg {String} focusClass @hide
19934 * @cfg {String} autoCreate @hide
19937 * @cfg {String} inputType @hide
19940 * @cfg {String} invalidClass @hide
19943 * @cfg {String} invalidText @hide
19946 * @cfg {String} msgFx @hide
19949 * @cfg {String} validateOnBlur @hide
19958 Roo.namespace('Roo.bootstrap.htmleditor');
19960 * @class Roo.bootstrap.HtmlEditorToolbar1
19965 new Roo.bootstrap.HtmlEditor({
19968 new Roo.bootstrap.HtmlEditorToolbar1({
19969 disable : { fonts: 1 , format: 1, ..., ... , ...],
19975 * @cfg {Object} disable List of elements to disable..
19976 * @cfg {Array} btns List of additional buttons.
19980 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19983 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19986 Roo.apply(this, config);
19988 // default disabled, based on 'good practice'..
19989 this.disable = this.disable || {};
19990 Roo.applyIf(this.disable, {
19993 specialElements : true
19995 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
19997 this.editor = config.editor;
19998 this.editorcore = config.editor.editorcore;
20000 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20002 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20003 // dont call parent... till later.
20005 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20010 editorcore : false,
20015 "h1","h2","h3","h4","h5","h6",
20017 "abbr", "acronym", "address", "cite", "samp", "var",
20021 onRender : function(ct, position)
20023 // Roo.log("Call onRender: " + this.xtype);
20025 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20027 this.el.dom.style.marginBottom = '0';
20029 var editorcore = this.editorcore;
20030 var editor= this.editor;
20033 var btn = function(id,cmd , toggle, handler){
20035 var event = toggle ? 'toggle' : 'click';
20040 xns: Roo.bootstrap,
20043 enableToggle:toggle !== false,
20045 pressed : toggle ? false : null,
20048 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20049 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20058 xns: Roo.bootstrap,
20059 glyphicon : 'font',
20063 xns: Roo.bootstrap,
20067 Roo.each(this.formats, function(f) {
20068 style.menu.items.push({
20070 xns: Roo.bootstrap,
20071 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20076 editorcore.insertTag(this.tagname);
20083 children.push(style);
20086 btn('bold',false,true);
20087 btn('italic',false,true);
20088 btn('align-left', 'justifyleft',true);
20089 btn('align-center', 'justifycenter',true);
20090 btn('align-right' , 'justifyright',true);
20091 btn('link', false, false, function(btn) {
20092 //Roo.log("create link?");
20093 var url = prompt(this.createLinkText, this.defaultLinkValue);
20094 if(url && url != 'http:/'+'/'){
20095 this.editorcore.relayCmd('createlink', url);
20098 btn('list','insertunorderedlist',true);
20099 btn('pencil', false,true, function(btn){
20102 this.toggleSourceEdit(btn.pressed);
20108 xns: Roo.bootstrap,
20113 xns: Roo.bootstrap,
20118 cog.menu.items.push({
20120 xns: Roo.bootstrap,
20121 html : Clean styles,
20126 editorcore.insertTag(this.tagname);
20135 this.xtype = 'NavSimplebar';
20137 for(var i=0;i< children.length;i++) {
20139 this.buttons.add(this.addxtypeChild(children[i]));
20143 editor.on('editorevent', this.updateToolbar, this);
20145 onBtnClick : function(id)
20147 this.editorcore.relayCmd(id);
20148 this.editorcore.focus();
20152 * Protected method that will not generally be called directly. It triggers
20153 * a toolbar update by reading the markup state of the current selection in the editor.
20155 updateToolbar: function(){
20157 if(!this.editorcore.activated){
20158 this.editor.onFirstFocus(); // is this neeed?
20162 var btns = this.buttons;
20163 var doc = this.editorcore.doc;
20164 btns.get('bold').setActive(doc.queryCommandState('bold'));
20165 btns.get('italic').setActive(doc.queryCommandState('italic'));
20166 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20168 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20169 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20170 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20172 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20173 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20176 var ans = this.editorcore.getAllAncestors();
20177 if (this.formatCombo) {
20180 var store = this.formatCombo.store;
20181 this.formatCombo.setValue("");
20182 for (var i =0; i < ans.length;i++) {
20183 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20185 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20193 // hides menus... - so this cant be on a menu...
20194 Roo.bootstrap.MenuMgr.hideAll();
20196 Roo.bootstrap.MenuMgr.hideAll();
20197 //this.editorsyncValue();
20199 onFirstFocus: function() {
20200 this.buttons.each(function(item){
20204 toggleSourceEdit : function(sourceEditMode){
20207 if(sourceEditMode){
20208 Roo.log("disabling buttons");
20209 this.buttons.each( function(item){
20210 if(item.cmd != 'pencil'){
20216 Roo.log("enabling buttons");
20217 if(this.editorcore.initialized){
20218 this.buttons.each( function(item){
20224 Roo.log("calling toggole on editor");
20225 // tell the editor that it's been pressed..
20226 this.editor.toggleSourceEdit(sourceEditMode);
20236 * @class Roo.bootstrap.Table.AbstractSelectionModel
20237 * @extends Roo.util.Observable
20238 * Abstract base class for grid SelectionModels. It provides the interface that should be
20239 * implemented by descendant classes. This class should not be directly instantiated.
20242 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20243 this.locked = false;
20244 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20248 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20249 /** @ignore Called by the grid automatically. Do not call directly. */
20250 init : function(grid){
20256 * Locks the selections.
20259 this.locked = true;
20263 * Unlocks the selections.
20265 unlock : function(){
20266 this.locked = false;
20270 * Returns true if the selections are locked.
20271 * @return {Boolean}
20273 isLocked : function(){
20274 return this.locked;
20278 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20279 * @class Roo.bootstrap.Table.RowSelectionModel
20280 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20281 * It supports multiple selections and keyboard selection/navigation.
20283 * @param {Object} config
20286 Roo.bootstrap.Table.RowSelectionModel = function(config){
20287 Roo.apply(this, config);
20288 this.selections = new Roo.util.MixedCollection(false, function(o){
20293 this.lastActive = false;
20297 * @event selectionchange
20298 * Fires when the selection changes
20299 * @param {SelectionModel} this
20301 "selectionchange" : true,
20303 * @event afterselectionchange
20304 * Fires after the selection changes (eg. by key press or clicking)
20305 * @param {SelectionModel} this
20307 "afterselectionchange" : true,
20309 * @event beforerowselect
20310 * Fires when a row is selected being selected, return false to cancel.
20311 * @param {SelectionModel} this
20312 * @param {Number} rowIndex The selected index
20313 * @param {Boolean} keepExisting False if other selections will be cleared
20315 "beforerowselect" : true,
20318 * Fires when a row is selected.
20319 * @param {SelectionModel} this
20320 * @param {Number} rowIndex The selected index
20321 * @param {Roo.data.Record} r The record
20323 "rowselect" : true,
20325 * @event rowdeselect
20326 * Fires when a row is deselected.
20327 * @param {SelectionModel} this
20328 * @param {Number} rowIndex The selected index
20330 "rowdeselect" : true
20332 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20333 this.locked = false;
20336 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20338 * @cfg {Boolean} singleSelect
20339 * True to allow selection of only one row at a time (defaults to false)
20341 singleSelect : false,
20344 initEvents : function(){
20346 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20347 this.grid.on("mousedown", this.handleMouseDown, this);
20348 }else{ // allow click to work like normal
20349 this.grid.on("rowclick", this.handleDragableRowClick, this);
20352 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20353 "up" : function(e){
20355 this.selectPrevious(e.shiftKey);
20356 }else if(this.last !== false && this.lastActive !== false){
20357 var last = this.last;
20358 this.selectRange(this.last, this.lastActive-1);
20359 this.grid.getView().focusRow(this.lastActive);
20360 if(last !== false){
20364 this.selectFirstRow();
20366 this.fireEvent("afterselectionchange", this);
20368 "down" : function(e){
20370 this.selectNext(e.shiftKey);
20371 }else if(this.last !== false && this.lastActive !== false){
20372 var last = this.last;
20373 this.selectRange(this.last, this.lastActive+1);
20374 this.grid.getView().focusRow(this.lastActive);
20375 if(last !== false){
20379 this.selectFirstRow();
20381 this.fireEvent("afterselectionchange", this);
20386 var view = this.grid.view;
20387 view.on("refresh", this.onRefresh, this);
20388 view.on("rowupdated", this.onRowUpdated, this);
20389 view.on("rowremoved", this.onRemove, this);
20393 onRefresh : function(){
20394 var ds = this.grid.dataSource, i, v = this.grid.view;
20395 var s = this.selections;
20396 s.each(function(r){
20397 if((i = ds.indexOfId(r.id)) != -1){
20406 onRemove : function(v, index, r){
20407 this.selections.remove(r);
20411 onRowUpdated : function(v, index, r){
20412 if(this.isSelected(r)){
20413 v.onRowSelect(index);
20419 * @param {Array} records The records to select
20420 * @param {Boolean} keepExisting (optional) True to keep existing selections
20422 selectRecords : function(records, keepExisting){
20424 this.clearSelections();
20426 var ds = this.grid.dataSource;
20427 for(var i = 0, len = records.length; i < len; i++){
20428 this.selectRow(ds.indexOf(records[i]), true);
20433 * Gets the number of selected rows.
20436 getCount : function(){
20437 return this.selections.length;
20441 * Selects the first row in the grid.
20443 selectFirstRow : function(){
20448 * Select the last row.
20449 * @param {Boolean} keepExisting (optional) True to keep existing selections
20451 selectLastRow : function(keepExisting){
20452 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20456 * Selects the row immediately following the last selected row.
20457 * @param {Boolean} keepExisting (optional) True to keep existing selections
20459 selectNext : function(keepExisting){
20460 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20461 this.selectRow(this.last+1, keepExisting);
20462 this.grid.getView().focusRow(this.last);
20467 * Selects the row that precedes the last selected row.
20468 * @param {Boolean} keepExisting (optional) True to keep existing selections
20470 selectPrevious : function(keepExisting){
20472 this.selectRow(this.last-1, keepExisting);
20473 this.grid.getView().focusRow(this.last);
20478 * Returns the selected records
20479 * @return {Array} Array of selected records
20481 getSelections : function(){
20482 return [].concat(this.selections.items);
20486 * Returns the first selected record.
20489 getSelected : function(){
20490 return this.selections.itemAt(0);
20495 * Clears all selections.
20497 clearSelections : function(fast){
20498 if(this.locked) return;
20500 var ds = this.grid.dataSource;
20501 var s = this.selections;
20502 s.each(function(r){
20503 this.deselectRow(ds.indexOfId(r.id));
20507 this.selections.clear();
20514 * Selects all rows.
20516 selectAll : function(){
20517 if(this.locked) return;
20518 this.selections.clear();
20519 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20520 this.selectRow(i, true);
20525 * Returns True if there is a selection.
20526 * @return {Boolean}
20528 hasSelection : function(){
20529 return this.selections.length > 0;
20533 * Returns True if the specified row is selected.
20534 * @param {Number/Record} record The record or index of the record to check
20535 * @return {Boolean}
20537 isSelected : function(index){
20538 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20539 return (r && this.selections.key(r.id) ? true : false);
20543 * Returns True if the specified record id is selected.
20544 * @param {String} id The id of record to check
20545 * @return {Boolean}
20547 isIdSelected : function(id){
20548 return (this.selections.key(id) ? true : false);
20552 handleMouseDown : function(e, t){
20553 var view = this.grid.getView(), rowIndex;
20554 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20557 if(e.shiftKey && this.last !== false){
20558 var last = this.last;
20559 this.selectRange(last, rowIndex, e.ctrlKey);
20560 this.last = last; // reset the last
20561 view.focusRow(rowIndex);
20563 var isSelected = this.isSelected(rowIndex);
20564 if(e.button !== 0 && isSelected){
20565 view.focusRow(rowIndex);
20566 }else if(e.ctrlKey && isSelected){
20567 this.deselectRow(rowIndex);
20568 }else if(!isSelected){
20569 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20570 view.focusRow(rowIndex);
20573 this.fireEvent("afterselectionchange", this);
20576 handleDragableRowClick : function(grid, rowIndex, e)
20578 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20579 this.selectRow(rowIndex, false);
20580 grid.view.focusRow(rowIndex);
20581 this.fireEvent("afterselectionchange", this);
20586 * Selects multiple rows.
20587 * @param {Array} rows Array of the indexes of the row to select
20588 * @param {Boolean} keepExisting (optional) True to keep existing selections
20590 selectRows : function(rows, keepExisting){
20592 this.clearSelections();
20594 for(var i = 0, len = rows.length; i < len; i++){
20595 this.selectRow(rows[i], true);
20600 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20601 * @param {Number} startRow The index of the first row in the range
20602 * @param {Number} endRow The index of the last row in the range
20603 * @param {Boolean} keepExisting (optional) True to retain existing selections
20605 selectRange : function(startRow, endRow, keepExisting){
20606 if(this.locked) return;
20608 this.clearSelections();
20610 if(startRow <= endRow){
20611 for(var i = startRow; i <= endRow; i++){
20612 this.selectRow(i, true);
20615 for(var i = startRow; i >= endRow; i--){
20616 this.selectRow(i, true);
20622 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20623 * @param {Number} startRow The index of the first row in the range
20624 * @param {Number} endRow The index of the last row in the range
20626 deselectRange : function(startRow, endRow, preventViewNotify){
20627 if(this.locked) return;
20628 for(var i = startRow; i <= endRow; i++){
20629 this.deselectRow(i, preventViewNotify);
20635 * @param {Number} row The index of the row to select
20636 * @param {Boolean} keepExisting (optional) True to keep existing selections
20638 selectRow : function(index, keepExisting, preventViewNotify){
20639 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20640 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20641 if(!keepExisting || this.singleSelect){
20642 this.clearSelections();
20644 var r = this.grid.dataSource.getAt(index);
20645 this.selections.add(r);
20646 this.last = this.lastActive = index;
20647 if(!preventViewNotify){
20648 this.grid.getView().onRowSelect(index);
20650 this.fireEvent("rowselect", this, index, r);
20651 this.fireEvent("selectionchange", this);
20657 * @param {Number} row The index of the row to deselect
20659 deselectRow : function(index, preventViewNotify){
20660 if(this.locked) return;
20661 if(this.last == index){
20664 if(this.lastActive == index){
20665 this.lastActive = false;
20667 var r = this.grid.dataSource.getAt(index);
20668 this.selections.remove(r);
20669 if(!preventViewNotify){
20670 this.grid.getView().onRowDeselect(index);
20672 this.fireEvent("rowdeselect", this, index);
20673 this.fireEvent("selectionchange", this);
20677 restoreLast : function(){
20679 this.last = this._last;
20684 acceptsNav : function(row, col, cm){
20685 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20689 onEditorKey : function(field, e){
20690 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20695 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20697 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20699 }else if(k == e.ENTER && !e.ctrlKey){
20703 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20705 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20707 }else if(k == e.ESC){
20711 g.startEditing(newCell[0], newCell[1]);
20716 * Ext JS Library 1.1.1
20717 * Copyright(c) 2006-2007, Ext JS, LLC.
20719 * Originally Released Under LGPL - original licence link has changed is not relivant.
20722 * <script type="text/javascript">
20726 * @class Roo.bootstrap.PagingToolbar
20728 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20730 * Create a new PagingToolbar
20731 * @param {Object} config The config object
20733 Roo.bootstrap.PagingToolbar = function(config)
20735 // old args format still supported... - xtype is prefered..
20736 // created from xtype...
20737 var ds = config.dataSource;
20738 this.toolbarItems = [];
20739 if (config.items) {
20740 this.toolbarItems = config.items;
20741 // config.items = [];
20744 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20751 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20755 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20757 * @cfg {Roo.data.Store} dataSource
20758 * The underlying data store providing the paged data
20761 * @cfg {String/HTMLElement/Element} container
20762 * container The id or element that will contain the toolbar
20765 * @cfg {Boolean} displayInfo
20766 * True to display the displayMsg (defaults to false)
20769 * @cfg {Number} pageSize
20770 * The number of records to display per page (defaults to 20)
20774 * @cfg {String} displayMsg
20775 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20777 displayMsg : 'Displaying {0} - {1} of {2}',
20779 * @cfg {String} emptyMsg
20780 * The message to display when no records are found (defaults to "No data to display")
20782 emptyMsg : 'No data to display',
20784 * Customizable piece of the default paging text (defaults to "Page")
20787 beforePageText : "Page",
20789 * Customizable piece of the default paging text (defaults to "of %0")
20792 afterPageText : "of {0}",
20794 * Customizable piece of the default paging text (defaults to "First Page")
20797 firstText : "First Page",
20799 * Customizable piece of the default paging text (defaults to "Previous Page")
20802 prevText : "Previous Page",
20804 * Customizable piece of the default paging text (defaults to "Next Page")
20807 nextText : "Next Page",
20809 * Customizable piece of the default paging text (defaults to "Last Page")
20812 lastText : "Last Page",
20814 * Customizable piece of the default paging text (defaults to "Refresh")
20817 refreshText : "Refresh",
20821 onRender : function(ct, position)
20823 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20824 this.navgroup.parentId = this.id;
20825 this.navgroup.onRender(this.el, null);
20826 // add the buttons to the navgroup
20828 if(this.displayInfo){
20829 Roo.log(this.el.select('ul.navbar-nav',true).first());
20830 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20831 this.displayEl = this.el.select('.x-paging-info', true).first();
20832 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20833 // this.displayEl = navel.el.select('span',true).first();
20839 Roo.each(_this.buttons, function(e){
20840 Roo.factory(e).onRender(_this.el, null);
20844 Roo.each(_this.toolbarItems, function(e) {
20845 _this.navgroup.addItem(e);
20849 this.first = this.navgroup.addItem({
20850 tooltip: this.firstText,
20852 icon : 'fa fa-backward',
20854 preventDefault: true,
20855 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20858 this.prev = this.navgroup.addItem({
20859 tooltip: this.prevText,
20861 icon : 'fa fa-step-backward',
20863 preventDefault: true,
20864 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20866 //this.addSeparator();
20869 var field = this.navgroup.addItem( {
20871 cls : 'x-paging-position',
20873 html : this.beforePageText +
20874 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20875 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20878 this.field = field.el.select('input', true).first();
20879 this.field.on("keydown", this.onPagingKeydown, this);
20880 this.field.on("focus", function(){this.dom.select();});
20883 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20884 //this.field.setHeight(18);
20885 //this.addSeparator();
20886 this.next = this.navgroup.addItem({
20887 tooltip: this.nextText,
20889 html : ' <i class="fa fa-step-forward">',
20891 preventDefault: true,
20892 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20894 this.last = this.navgroup.addItem({
20895 tooltip: this.lastText,
20896 icon : 'fa fa-forward',
20899 preventDefault: true,
20900 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20902 //this.addSeparator();
20903 this.loading = this.navgroup.addItem({
20904 tooltip: this.refreshText,
20905 icon: 'fa fa-refresh',
20906 preventDefault: true,
20907 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20913 updateInfo : function(){
20914 if(this.displayEl){
20915 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20916 var msg = count == 0 ?
20920 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20922 this.displayEl.update(msg);
20927 onLoad : function(ds, r, o){
20928 this.cursor = o.params ? o.params.start : 0;
20929 var d = this.getPageData(),
20933 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20934 this.field.dom.value = ap;
20935 this.first.setDisabled(ap == 1);
20936 this.prev.setDisabled(ap == 1);
20937 this.next.setDisabled(ap == ps);
20938 this.last.setDisabled(ap == ps);
20939 this.loading.enable();
20944 getPageData : function(){
20945 var total = this.ds.getTotalCount();
20948 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20949 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20954 onLoadError : function(){
20955 this.loading.enable();
20959 onPagingKeydown : function(e){
20960 var k = e.getKey();
20961 var d = this.getPageData();
20963 var v = this.field.dom.value, pageNum;
20964 if(!v || isNaN(pageNum = parseInt(v, 10))){
20965 this.field.dom.value = d.activePage;
20968 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20969 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20972 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))
20974 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20975 this.field.dom.value = pageNum;
20976 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20979 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20981 var v = this.field.dom.value, pageNum;
20982 var increment = (e.shiftKey) ? 10 : 1;
20983 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20985 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20986 this.field.dom.value = d.activePage;
20989 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
20991 this.field.dom.value = parseInt(v, 10) + increment;
20992 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
20993 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21000 beforeLoad : function(){
21002 this.loading.disable();
21007 onClick : function(which){
21016 ds.load({params:{start: 0, limit: this.pageSize}});
21019 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21022 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21025 var total = ds.getTotalCount();
21026 var extra = total % this.pageSize;
21027 var lastStart = extra ? (total - extra) : total-this.pageSize;
21028 ds.load({params:{start: lastStart, limit: this.pageSize}});
21031 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21037 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21038 * @param {Roo.data.Store} store The data store to unbind
21040 unbind : function(ds){
21041 ds.un("beforeload", this.beforeLoad, this);
21042 ds.un("load", this.onLoad, this);
21043 ds.un("loadexception", this.onLoadError, this);
21044 ds.un("remove", this.updateInfo, this);
21045 ds.un("add", this.updateInfo, this);
21046 this.ds = undefined;
21050 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21051 * @param {Roo.data.Store} store The data store to bind
21053 bind : function(ds){
21054 ds.on("beforeload", this.beforeLoad, this);
21055 ds.on("load", this.onLoad, this);
21056 ds.on("loadexception", this.onLoadError, this);
21057 ds.on("remove", this.updateInfo, this);
21058 ds.on("add", this.updateInfo, this);
21069 * @class Roo.bootstrap.MessageBar
21070 * @extends Roo.bootstrap.Component
21071 * Bootstrap MessageBar class
21072 * @cfg {String} html contents of the MessageBar
21073 * @cfg {String} weight (info | success | warning | danger) default info
21074 * @cfg {String} beforeClass insert the bar before the given class
21075 * @cfg {Boolean} closable (true | false) default false
21076 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21079 * Create a new Element
21080 * @param {Object} config The config object
21083 Roo.bootstrap.MessageBar = function(config){
21084 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21087 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21093 beforeClass: 'bootstrap-sticky-wrap',
21095 getAutoCreate : function(){
21099 cls: 'alert alert-dismissable alert-' + this.weight,
21104 html: this.html || ''
21110 cfg.cls += ' alert-messages-fixed';
21124 onRender : function(ct, position)
21126 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21129 var cfg = Roo.apply({}, this.getAutoCreate());
21133 cfg.cls += ' ' + this.cls;
21136 cfg.style = this.style;
21138 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21140 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21143 this.el.select('>button.close').on('click', this.hide, this);
21149 if (!this.rendered) {
21155 this.fireEvent('show', this);
21161 if (!this.rendered) {
21167 this.fireEvent('hide', this);
21170 update : function()
21172 // var e = this.el.dom.firstChild;
21174 // if(this.closable){
21175 // e = e.nextSibling;
21178 // e.data = this.html || '';
21180 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21196 * @class Roo.bootstrap.Graph
21197 * @extends Roo.bootstrap.Component
21198 * Bootstrap Graph class
21202 @cfg {String} graphtype bar | vbar | pie
21203 @cfg {number} g_x coodinator | centre x (pie)
21204 @cfg {number} g_y coodinator | centre y (pie)
21205 @cfg {number} g_r radius (pie)
21206 @cfg {number} g_height height of the chart (respected by all elements in the set)
21207 @cfg {number} g_width width of the chart (respected by all elements in the set)
21208 @cfg {Object} title The title of the chart
21211 -opts (object) options for the chart
21213 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21214 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21216 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.
21217 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21219 o stretch (boolean)
21221 -opts (object) options for the pie
21224 o startAngle (number)
21225 o endAngle (number)
21229 * Create a new Input
21230 * @param {Object} config The config object
21233 Roo.bootstrap.Graph = function(config){
21234 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21240 * The img click event for the img.
21241 * @param {Roo.EventObject} e
21247 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21258 //g_colors: this.colors,
21265 getAutoCreate : function(){
21276 onRender : function(ct,position){
21277 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21278 this.raphael = Raphael(this.el.dom);
21280 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21281 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21282 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21283 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21285 r.text(160, 10, "Single Series Chart").attr(txtattr);
21286 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21287 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21288 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21290 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21291 r.barchart(330, 10, 300, 220, data1);
21292 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21293 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21296 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21297 // r.barchart(30, 30, 560, 250, xdata, {
21298 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21299 // axis : "0 0 1 1",
21300 // axisxlabels : xdata
21301 // //yvalues : cols,
21304 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21306 // this.load(null,xdata,{
21307 // axis : "0 0 1 1",
21308 // axisxlabels : xdata
21313 load : function(graphtype,xdata,opts){
21314 this.raphael.clear();
21316 graphtype = this.graphtype;
21321 var r = this.raphael,
21322 fin = function () {
21323 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21325 fout = function () {
21326 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21328 pfin = function() {
21329 this.sector.stop();
21330 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21333 this.label[0].stop();
21334 this.label[0].attr({ r: 7.5 });
21335 this.label[1].attr({ "font-weight": 800 });
21338 pfout = function() {
21339 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21342 this.label[0].animate({ r: 5 }, 500, "bounce");
21343 this.label[1].attr({ "font-weight": 400 });
21349 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21352 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21355 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21356 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21358 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21365 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21370 setTitle: function(o)
21375 initEvents: function() {
21378 this.el.on('click', this.onClick, this);
21382 onClick : function(e)
21384 Roo.log('img onclick');
21385 this.fireEvent('click', this, e);
21397 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21400 * @class Roo.bootstrap.dash.NumberBox
21401 * @extends Roo.bootstrap.Component
21402 * Bootstrap NumberBox class
21403 * @cfg {String} headline Box headline
21404 * @cfg {String} content Box content
21405 * @cfg {String} icon Box icon
21406 * @cfg {String} footer Footer text
21407 * @cfg {String} fhref Footer href
21410 * Create a new NumberBox
21411 * @param {Object} config The config object
21415 Roo.bootstrap.dash.NumberBox = function(config){
21416 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21420 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21429 getAutoCreate : function(){
21433 cls : 'small-box ',
21441 cls : 'roo-headline',
21442 html : this.headline
21446 cls : 'roo-content',
21447 html : this.content
21461 cls : 'ion ' + this.icon
21470 cls : 'small-box-footer',
21471 href : this.fhref || '#',
21475 cfg.cn.push(footer);
21482 onRender : function(ct,position){
21483 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21490 setHeadline: function (value)
21492 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21495 setFooter: function (value, href)
21497 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21500 this.el.select('a.small-box-footer',true).first().attr('href', href);
21505 setContent: function (value)
21507 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21510 initEvents: function()
21524 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21527 * @class Roo.bootstrap.dash.TabBox
21528 * @extends Roo.bootstrap.Component
21529 * Bootstrap TabBox class
21530 * @cfg {String} title Title of the TabBox
21531 * @cfg {String} icon Icon of the TabBox
21532 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21533 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21536 * Create a new TabBox
21537 * @param {Object} config The config object
21541 Roo.bootstrap.dash.TabBox = function(config){
21542 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21547 * When a pane is added
21548 * @param {Roo.bootstrap.dash.TabPane} pane
21552 * @event activatepane
21553 * When a pane is activated
21554 * @param {Roo.bootstrap.dash.TabPane} pane
21556 "activatepane" : true
21564 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21569 tabScrollable : false,
21571 getChildContainer : function()
21573 return this.el.select('.tab-content', true).first();
21576 getAutoCreate : function(){
21580 cls: 'pull-left header',
21588 cls: 'fa ' + this.icon
21594 cls: 'nav nav-tabs pull-right',
21600 if(this.tabScrollable){
21607 cls: 'nav nav-tabs pull-right',
21618 cls: 'nav-tabs-custom',
21623 cls: 'tab-content no-padding',
21631 initEvents : function()
21633 //Roo.log('add add pane handler');
21634 this.on('addpane', this.onAddPane, this);
21637 * Updates the box title
21638 * @param {String} html to set the title to.
21640 setTitle : function(value)
21642 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21644 onAddPane : function(pane)
21646 this.panes.push(pane);
21647 //Roo.log('addpane');
21649 // tabs are rendere left to right..
21650 if(!this.showtabs){
21654 var ctr = this.el.select('.nav-tabs', true).first();
21657 var existing = ctr.select('.nav-tab',true);
21658 var qty = existing.getCount();;
21661 var tab = ctr.createChild({
21663 cls : 'nav-tab' + (qty ? '' : ' active'),
21671 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21674 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21676 pane.el.addClass('active');
21681 onTabClick : function(ev,un,ob,pane)
21683 //Roo.log('tab - prev default');
21684 ev.preventDefault();
21687 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21688 pane.tab.addClass('active');
21689 //Roo.log(pane.title);
21690 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21691 // technically we should have a deactivate event.. but maybe add later.
21692 // and it should not de-activate the selected tab...
21693 this.fireEvent('activatepane', pane);
21694 pane.el.addClass('active');
21695 pane.fireEvent('activate');
21700 getActivePane : function()
21703 Roo.each(this.panes, function(p) {
21704 if(p.el.hasClass('active')){
21725 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21727 * @class Roo.bootstrap.TabPane
21728 * @extends Roo.bootstrap.Component
21729 * Bootstrap TabPane class
21730 * @cfg {Boolean} active (false | true) Default false
21731 * @cfg {String} title title of panel
21735 * Create a new TabPane
21736 * @param {Object} config The config object
21739 Roo.bootstrap.dash.TabPane = function(config){
21740 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21746 * When a pane is activated
21747 * @param {Roo.bootstrap.dash.TabPane} pane
21754 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21759 // the tabBox that this is attached to.
21762 getAutoCreate : function()
21770 cfg.cls += ' active';
21775 initEvents : function()
21777 //Roo.log('trigger add pane handler');
21778 this.parent().fireEvent('addpane', this)
21782 * Updates the tab title
21783 * @param {String} html to set the title to.
21785 setTitle: function(str)
21791 this.tab.select('a', true).first().dom.innerHTML = str;
21808 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21811 * @class Roo.bootstrap.menu.Menu
21812 * @extends Roo.bootstrap.Component
21813 * Bootstrap Menu class - container for Menu
21814 * @cfg {String} html Text of the menu
21815 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21816 * @cfg {String} icon Font awesome icon
21817 * @cfg {String} pos Menu align to (top | bottom) default bottom
21821 * Create a new Menu
21822 * @param {Object} config The config object
21826 Roo.bootstrap.menu.Menu = function(config){
21827 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21831 * @event beforeshow
21832 * Fires before this menu is displayed
21833 * @param {Roo.bootstrap.menu.Menu} this
21837 * @event beforehide
21838 * Fires before this menu is hidden
21839 * @param {Roo.bootstrap.menu.Menu} this
21844 * Fires after this menu is displayed
21845 * @param {Roo.bootstrap.menu.Menu} this
21850 * Fires after this menu is hidden
21851 * @param {Roo.bootstrap.menu.Menu} this
21856 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21857 * @param {Roo.bootstrap.menu.Menu} this
21858 * @param {Roo.EventObject} e
21865 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21869 weight : 'default',
21874 getChildContainer : function() {
21875 if(this.isSubMenu){
21879 return this.el.select('ul.dropdown-menu', true).first();
21882 getAutoCreate : function()
21887 cls : 'roo-menu-text',
21895 cls : 'fa ' + this.icon
21906 cls : 'dropdown-button btn btn-' + this.weight,
21911 cls : 'dropdown-toggle btn btn-' + this.weight,
21921 cls : 'dropdown-menu'
21927 if(this.pos == 'top'){
21928 cfg.cls += ' dropup';
21931 if(this.isSubMenu){
21934 cls : 'dropdown-menu'
21941 onRender : function(ct, position)
21943 this.isSubMenu = ct.hasClass('dropdown-submenu');
21945 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21948 initEvents : function()
21950 if(this.isSubMenu){
21954 this.hidden = true;
21956 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21957 this.triggerEl.on('click', this.onTriggerPress, this);
21959 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21960 this.buttonEl.on('click', this.onClick, this);
21966 if(this.isSubMenu){
21970 return this.el.select('ul.dropdown-menu', true).first();
21973 onClick : function(e)
21975 this.fireEvent("click", this, e);
21978 onTriggerPress : function(e)
21980 if (this.isVisible()) {
21987 isVisible : function(){
21988 return !this.hidden;
21993 this.fireEvent("beforeshow", this);
21995 this.hidden = false;
21996 this.el.addClass('open');
21998 Roo.get(document).on("mouseup", this.onMouseUp, this);
22000 this.fireEvent("show", this);
22007 this.fireEvent("beforehide", this);
22009 this.hidden = true;
22010 this.el.removeClass('open');
22012 Roo.get(document).un("mouseup", this.onMouseUp);
22014 this.fireEvent("hide", this);
22017 onMouseUp : function()
22031 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22034 * @class Roo.bootstrap.menu.Item
22035 * @extends Roo.bootstrap.Component
22036 * Bootstrap MenuItem class
22037 * @cfg {Boolean} submenu (true | false) default false
22038 * @cfg {String} html text of the item
22039 * @cfg {String} href the link
22040 * @cfg {Boolean} disable (true | false) default false
22041 * @cfg {Boolean} preventDefault (true | false) default true
22042 * @cfg {String} icon Font awesome icon
22043 * @cfg {String} pos Submenu align to (left | right) default right
22047 * Create a new Item
22048 * @param {Object} config The config object
22052 Roo.bootstrap.menu.Item = function(config){
22053 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22057 * Fires when the mouse is hovering over this menu
22058 * @param {Roo.bootstrap.menu.Item} this
22059 * @param {Roo.EventObject} e
22064 * Fires when the mouse exits this menu
22065 * @param {Roo.bootstrap.menu.Item} this
22066 * @param {Roo.EventObject} e
22072 * The raw click event for the entire grid.
22073 * @param {Roo.EventObject} e
22079 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22084 preventDefault: true,
22089 getAutoCreate : function()
22094 cls : 'roo-menu-item-text',
22102 cls : 'fa ' + this.icon
22111 href : this.href || '#',
22118 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22122 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22124 if(this.pos == 'left'){
22125 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22132 initEvents : function()
22134 this.el.on('mouseover', this.onMouseOver, this);
22135 this.el.on('mouseout', this.onMouseOut, this);
22137 this.el.select('a', true).first().on('click', this.onClick, this);
22141 onClick : function(e)
22143 if(this.preventDefault){
22144 e.preventDefault();
22147 this.fireEvent("click", this, e);
22150 onMouseOver : function(e)
22152 if(this.submenu && this.pos == 'left'){
22153 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
22156 this.fireEvent("mouseover", this, e);
22159 onMouseOut : function(e)
22161 this.fireEvent("mouseout", this, e);
22173 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22176 * @class Roo.bootstrap.menu.Separator
22177 * @extends Roo.bootstrap.Component
22178 * Bootstrap Separator class
22181 * Create a new Separator
22182 * @param {Object} config The config object
22186 Roo.bootstrap.menu.Separator = function(config){
22187 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22190 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22192 getAutoCreate : function(){
22213 * @class Roo.bootstrap.Tooltip
22214 * Bootstrap Tooltip class
22215 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22216 * to determine which dom element triggers the tooltip.
22218 * It needs to add support for additional attributes like tooltip-position
22221 * Create a new Toolti
22222 * @param {Object} config The config object
22225 Roo.bootstrap.Tooltip = function(config){
22226 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22229 Roo.apply(Roo.bootstrap.Tooltip, {
22231 * @function init initialize tooltip monitoring.
22235 currentTip : false,
22236 currentRegion : false,
22242 Roo.get(document).on('mouseover', this.enter ,this);
22243 Roo.get(document).on('mouseout', this.leave, this);
22246 this.currentTip = new Roo.bootstrap.Tooltip();
22249 enter : function(ev)
22251 var dom = ev.getTarget();
22253 //Roo.log(['enter',dom]);
22254 var el = Roo.fly(dom);
22255 if (this.currentEl) {
22257 //Roo.log(this.currentEl);
22258 //Roo.log(this.currentEl.contains(dom));
22259 if (this.currentEl == el) {
22262 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22270 if (this.currentTip.el) {
22271 this.currentTip.el.hide(); // force hiding...
22276 // you can not look for children, as if el is the body.. then everythign is the child..
22277 if (!el.attr('tooltip')) { //
22278 if (!el.select("[tooltip]").elements.length) {
22281 // is the mouse over this child...?
22282 bindEl = el.select("[tooltip]").first();
22283 var xy = ev.getXY();
22284 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22285 //Roo.log("not in region.");
22288 //Roo.log("child element over..");
22291 this.currentEl = bindEl;
22292 this.currentTip.bind(bindEl);
22293 this.currentRegion = Roo.lib.Region.getRegion(dom);
22294 this.currentTip.enter();
22297 leave : function(ev)
22299 var dom = ev.getTarget();
22300 //Roo.log(['leave',dom]);
22301 if (!this.currentEl) {
22306 if (dom != this.currentEl.dom) {
22309 var xy = ev.getXY();
22310 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22313 // only activate leave if mouse cursor is outside... bounding box..
22318 if (this.currentTip) {
22319 this.currentTip.leave();
22321 //Roo.log('clear currentEl');
22322 this.currentEl = false;
22327 'left' : ['r-l', [-2,0], 'right'],
22328 'right' : ['l-r', [2,0], 'left'],
22329 'bottom' : ['t-b', [0,2], 'top'],
22330 'top' : [ 'b-t', [0,-2], 'bottom']
22336 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22341 delay : null, // can be { show : 300 , hide: 500}
22345 hoverState : null, //???
22347 placement : 'bottom',
22349 getAutoCreate : function(){
22356 cls : 'tooltip-arrow'
22359 cls : 'tooltip-inner'
22366 bind : function(el)
22372 enter : function () {
22374 if (this.timeout != null) {
22375 clearTimeout(this.timeout);
22378 this.hoverState = 'in';
22379 //Roo.log("enter - show");
22380 if (!this.delay || !this.delay.show) {
22385 this.timeout = setTimeout(function () {
22386 if (_t.hoverState == 'in') {
22389 }, this.delay.show);
22393 clearTimeout(this.timeout);
22395 this.hoverState = 'out';
22396 if (!this.delay || !this.delay.hide) {
22402 this.timeout = setTimeout(function () {
22403 //Roo.log("leave - timeout");
22405 if (_t.hoverState == 'out') {
22407 Roo.bootstrap.Tooltip.currentEl = false;
22415 this.render(document.body);
22418 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22420 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22422 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22424 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22426 var placement = typeof this.placement == 'function' ?
22427 this.placement.call(this, this.el, on_el) :
22430 var autoToken = /\s?auto?\s?/i;
22431 var autoPlace = autoToken.test(placement);
22433 placement = placement.replace(autoToken, '') || 'top';
22437 //this.el.setXY([0,0]);
22439 //this.el.dom.style.display='block';
22440 this.el.addClass(placement);
22442 //this.el.appendTo(on_el);
22444 var p = this.getPosition();
22445 var box = this.el.getBox();
22450 var align = Roo.bootstrap.Tooltip.alignment[placement];
22451 this.el.alignTo(this.bindEl, align[0],align[1]);
22452 //var arrow = this.el.select('.arrow',true).first();
22453 //arrow.set(align[2],
22455 this.el.addClass('in fade');
22456 this.hoverState = null;
22458 if (this.el.hasClass('fade')) {
22469 //this.el.setXY([0,0]);
22470 this.el.removeClass('in');
22486 * @class Roo.bootstrap.LocationPicker
22487 * @extends Roo.bootstrap.Component
22488 * Bootstrap LocationPicker class
22489 * @cfg {Number} latitude Position when init default 0
22490 * @cfg {Number} longitude Position when init default 0
22491 * @cfg {Number} zoom default 15
22492 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22493 * @cfg {Boolean} mapTypeControl default false
22494 * @cfg {Boolean} disableDoubleClickZoom default false
22495 * @cfg {Boolean} scrollwheel default true
22496 * @cfg {Boolean} streetViewControl default false
22497 * @cfg {Number} radius default 0
22498 * @cfg {String} locationName
22499 * @cfg {Boolean} draggable default true
22500 * @cfg {Boolean} enableAutocomplete default false
22501 * @cfg {Boolean} enableReverseGeocode default true
22502 * @cfg {String} markerTitle
22505 * Create a new LocationPicker
22506 * @param {Object} config The config object
22510 Roo.bootstrap.LocationPicker = function(config){
22512 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22517 * Fires when the picker initialized.
22518 * @param {Roo.bootstrap.LocationPicker} this
22519 * @param {Google Location} location
22523 * @event positionchanged
22524 * Fires when the picker position changed.
22525 * @param {Roo.bootstrap.LocationPicker} this
22526 * @param {Google Location} location
22528 positionchanged : true,
22531 * Fires when the map resize.
22532 * @param {Roo.bootstrap.LocationPicker} this
22537 * Fires when the map show.
22538 * @param {Roo.bootstrap.LocationPicker} this
22543 * Fires when the map hide.
22544 * @param {Roo.bootstrap.LocationPicker} this
22549 * Fires when click the map.
22550 * @param {Roo.bootstrap.LocationPicker} this
22551 * @param {Map event} e
22555 * @event mapRightClick
22556 * Fires when right click the map.
22557 * @param {Roo.bootstrap.LocationPicker} this
22558 * @param {Map event} e
22560 mapRightClick : true,
22562 * @event markerClick
22563 * Fires when click the marker.
22564 * @param {Roo.bootstrap.LocationPicker} this
22565 * @param {Map event} e
22567 markerClick : true,
22569 * @event markerRightClick
22570 * Fires when right click the marker.
22571 * @param {Roo.bootstrap.LocationPicker} this
22572 * @param {Map event} e
22574 markerRightClick : true,
22576 * @event OverlayViewDraw
22577 * Fires when OverlayView Draw
22578 * @param {Roo.bootstrap.LocationPicker} this
22580 OverlayViewDraw : true,
22582 * @event OverlayViewOnAdd
22583 * Fires when OverlayView Draw
22584 * @param {Roo.bootstrap.LocationPicker} this
22586 OverlayViewOnAdd : true,
22588 * @event OverlayViewOnRemove
22589 * Fires when OverlayView Draw
22590 * @param {Roo.bootstrap.LocationPicker} this
22592 OverlayViewOnRemove : true,
22594 * @event OverlayViewShow
22595 * Fires when OverlayView Draw
22596 * @param {Roo.bootstrap.LocationPicker} this
22597 * @param {Pixel} cpx
22599 OverlayViewShow : true,
22601 * @event OverlayViewHide
22602 * Fires when OverlayView Draw
22603 * @param {Roo.bootstrap.LocationPicker} this
22605 OverlayViewHide : true
22610 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22612 gMapContext: false,
22618 mapTypeControl: false,
22619 disableDoubleClickZoom: false,
22621 streetViewControl: false,
22625 enableAutocomplete: false,
22626 enableReverseGeocode: true,
22629 getAutoCreate: function()
22634 cls: 'roo-location-picker'
22640 initEvents: function(ct, position)
22642 if(!this.el.getWidth() || this.isApplied()){
22646 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22651 initial: function()
22653 if(!this.mapTypeId){
22654 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22657 this.gMapContext = this.GMapContext();
22659 this.initOverlayView();
22661 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22665 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22666 _this.setPosition(_this.gMapContext.marker.position);
22669 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22670 _this.fireEvent('mapClick', this, event);
22674 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22675 _this.fireEvent('mapRightClick', this, event);
22679 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22680 _this.fireEvent('markerClick', this, event);
22684 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22685 _this.fireEvent('markerRightClick', this, event);
22689 this.setPosition(this.gMapContext.location);
22691 this.fireEvent('initial', this, this.gMapContext.location);
22694 initOverlayView: function()
22698 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22702 _this.fireEvent('OverlayViewDraw', _this);
22707 _this.fireEvent('OverlayViewOnAdd', _this);
22710 onRemove: function()
22712 _this.fireEvent('OverlayViewOnRemove', _this);
22715 show: function(cpx)
22717 _this.fireEvent('OverlayViewShow', _this, cpx);
22722 _this.fireEvent('OverlayViewHide', _this);
22728 fromLatLngToContainerPixel: function(event)
22730 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22733 isApplied: function()
22735 return this.getGmapContext() == false ? false : true;
22738 getGmapContext: function()
22740 return this.gMapContext
22743 GMapContext: function()
22745 var position = new google.maps.LatLng(this.latitude, this.longitude);
22747 var _map = new google.maps.Map(this.el.dom, {
22750 mapTypeId: this.mapTypeId,
22751 mapTypeControl: this.mapTypeControl,
22752 disableDoubleClickZoom: this.disableDoubleClickZoom,
22753 scrollwheel: this.scrollwheel,
22754 streetViewControl: this.streetViewControl,
22755 locationName: this.locationName,
22756 draggable: this.draggable,
22757 enableAutocomplete: this.enableAutocomplete,
22758 enableReverseGeocode: this.enableReverseGeocode
22761 var _marker = new google.maps.Marker({
22762 position: position,
22764 title: this.markerTitle,
22765 draggable: this.draggable
22772 location: position,
22773 radius: this.radius,
22774 locationName: this.locationName,
22775 addressComponents: {
22776 formatted_address: null,
22777 addressLine1: null,
22778 addressLine2: null,
22780 streetNumber: null,
22784 stateOrProvince: null
22787 domContainer: this.el.dom,
22788 geodecoder: new google.maps.Geocoder()
22792 drawCircle: function(center, radius, options)
22794 if (this.gMapContext.circle != null) {
22795 this.gMapContext.circle.setMap(null);
22799 options = Roo.apply({}, options, {
22800 strokeColor: "#0000FF",
22801 strokeOpacity: .35,
22803 fillColor: "#0000FF",
22807 options.map = this.gMapContext.map;
22808 options.radius = radius;
22809 options.center = center;
22810 this.gMapContext.circle = new google.maps.Circle(options);
22811 return this.gMapContext.circle;
22817 setPosition: function(location)
22819 this.gMapContext.location = location;
22820 this.gMapContext.marker.setPosition(location);
22821 this.gMapContext.map.panTo(location);
22822 this.drawCircle(location, this.gMapContext.radius, {});
22826 if (this.gMapContext.settings.enableReverseGeocode) {
22827 this.gMapContext.geodecoder.geocode({
22828 latLng: this.gMapContext.location
22829 }, function(results, status) {
22831 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22832 _this.gMapContext.locationName = results[0].formatted_address;
22833 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22835 _this.fireEvent('positionchanged', this, location);
22842 this.fireEvent('positionchanged', this, location);
22847 google.maps.event.trigger(this.gMapContext.map, "resize");
22849 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22851 this.fireEvent('resize', this);
22854 setPositionByLatLng: function(latitude, longitude)
22856 this.setPosition(new google.maps.LatLng(latitude, longitude));
22859 getCurrentPosition: function()
22862 latitude: this.gMapContext.location.lat(),
22863 longitude: this.gMapContext.location.lng()
22867 getAddressName: function()
22869 return this.gMapContext.locationName;
22872 getAddressComponents: function()
22874 return this.gMapContext.addressComponents;
22877 address_component_from_google_geocode: function(address_components)
22881 for (var i = 0; i < address_components.length; i++) {
22882 var component = address_components[i];
22883 if (component.types.indexOf("postal_code") >= 0) {
22884 result.postalCode = component.short_name;
22885 } else if (component.types.indexOf("street_number") >= 0) {
22886 result.streetNumber = component.short_name;
22887 } else if (component.types.indexOf("route") >= 0) {
22888 result.streetName = component.short_name;
22889 } else if (component.types.indexOf("neighborhood") >= 0) {
22890 result.city = component.short_name;
22891 } else if (component.types.indexOf("locality") >= 0) {
22892 result.city = component.short_name;
22893 } else if (component.types.indexOf("sublocality") >= 0) {
22894 result.district = component.short_name;
22895 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22896 result.stateOrProvince = component.short_name;
22897 } else if (component.types.indexOf("country") >= 0) {
22898 result.country = component.short_name;
22902 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22903 result.addressLine2 = "";
22907 setZoomLevel: function(zoom)
22909 this.gMapContext.map.setZoom(zoom);
22922 this.fireEvent('show', this);
22933 this.fireEvent('hide', this);
22938 Roo.apply(Roo.bootstrap.LocationPicker, {
22940 OverlayView : function(map, options)
22942 options = options || {};
22956 * @class Roo.bootstrap.Alert
22957 * @extends Roo.bootstrap.Component
22958 * Bootstrap Alert class
22959 * @cfg {String} title The title of alert
22960 * @cfg {String} html The content of alert
22961 * @cfg {String} weight ( success | info | warning | danger )
22962 * @cfg {String} faicon font-awesomeicon
22965 * Create a new alert
22966 * @param {Object} config The config object
22970 Roo.bootstrap.Alert = function(config){
22971 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22975 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22982 getAutoCreate : function()
22991 cls : 'roo-alert-icon'
22996 cls : 'roo-alert-title',
23001 cls : 'roo-alert-text',
23008 cfg.cn[0].cls += ' fa ' + this.faicon;
23012 cfg.cls += ' alert-' + this.weight;
23018 initEvents: function()
23020 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23023 setTitle : function(str)
23025 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23028 setText : function(str)
23030 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23033 setWeight : function(weight)
23036 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23039 this.weight = weight;
23041 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23044 setIcon : function(icon)
23047 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23052 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);