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')){
1634 function onBeforeCheck(mi, state){
1636 var g = groups[mi.group];
1637 for(var i = 0, l = g.length; i < l; i++){
1639 g[i].setChecked(false);
1648 * Hides all menus that are currently visible
1650 hideAll : function(){
1655 register : function(menu){
1659 menus[menu.id] = menu;
1660 menu.on("beforehide", onBeforeHide);
1661 menu.on("hide", onHide);
1662 menu.on("beforeshow", onBeforeShow);
1663 menu.on("show", onShow);
1665 if(g && menu.events["checkchange"]){
1669 groups[g].push(menu);
1670 menu.on("checkchange", onCheck);
1675 * Returns a {@link Roo.menu.Menu} object
1676 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1677 * be used to generate and return a new Menu instance.
1679 get : function(menu){
1680 if(typeof menu == "string"){ // menu id
1682 }else if(menu.events){ // menu instance
1685 /*else if(typeof menu.length == 'number'){ // array of menu items?
1686 return new Roo.bootstrap.Menu({items:menu});
1687 }else{ // otherwise, must be a config
1688 return new Roo.bootstrap.Menu(menu);
1695 unregister : function(menu){
1696 delete menus[menu.id];
1697 menu.un("beforehide", onBeforeHide);
1698 menu.un("hide", onHide);
1699 menu.un("beforeshow", onBeforeShow);
1700 menu.un("show", onShow);
1702 if(g && menu.events["checkchange"]){
1703 groups[g].remove(menu);
1704 menu.un("checkchange", onCheck);
1709 registerCheckable : function(menuItem){
1710 var g = menuItem.group;
1715 groups[g].push(menuItem);
1716 menuItem.on("beforecheckchange", onBeforeCheck);
1721 unregisterCheckable : function(menuItem){
1722 var g = menuItem.group;
1724 groups[g].remove(menuItem);
1725 menuItem.un("beforecheckchange", onBeforeCheck);
1737 * @class Roo.bootstrap.Menu
1738 * @extends Roo.bootstrap.Component
1739 * Bootstrap Menu class - container for MenuItems
1740 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1744 * @param {Object} config The config object
1748 Roo.bootstrap.Menu = function(config){
1749 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1750 if (this.registerMenu) {
1751 Roo.bootstrap.MenuMgr.register(this);
1756 * Fires before this menu is displayed
1757 * @param {Roo.menu.Menu} this
1762 * Fires before this menu is hidden
1763 * @param {Roo.menu.Menu} this
1768 * Fires after this menu is displayed
1769 * @param {Roo.menu.Menu} this
1774 * Fires after this menu is hidden
1775 * @param {Roo.menu.Menu} this
1780 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1781 * @param {Roo.menu.Menu} this
1782 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1783 * @param {Roo.EventObject} e
1788 * Fires when the mouse is hovering over this menu
1789 * @param {Roo.menu.Menu} this
1790 * @param {Roo.EventObject} e
1791 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1796 * Fires when the mouse exits this menu
1797 * @param {Roo.menu.Menu} this
1798 * @param {Roo.EventObject} e
1799 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1804 * Fires when a menu item contained in this menu is clicked
1805 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1806 * @param {Roo.EventObject} e
1810 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1813 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1817 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1820 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1822 registerMenu : true,
1824 menuItems :false, // stores the menu items..
1830 getChildContainer : function() {
1834 getAutoCreate : function(){
1836 //if (['right'].indexOf(this.align)!==-1) {
1837 // cfg.cn[1].cls += ' pull-right'
1843 cls : 'dropdown-menu' ,
1844 style : 'z-index:1000'
1848 if (this.type === 'submenu') {
1849 cfg.cls = 'submenu active';
1851 if (this.type === 'treeview') {
1852 cfg.cls = 'treeview-menu';
1857 initEvents : function() {
1859 // Roo.log("ADD event");
1860 // Roo.log(this.triggerEl.dom);
1861 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
1863 this.triggerEl.addClass('dropdown-toggle');
1864 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1866 this.el.on("mouseover", this.onMouseOver, this);
1867 this.el.on("mouseout", this.onMouseOut, this);
1871 findTargetItem : function(e){
1872 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1876 //Roo.log(t); Roo.log(t.id);
1878 //Roo.log(this.menuitems);
1879 return this.menuitems.get(t.id);
1881 //return this.items.get(t.menuItemId);
1886 onClick : function(e){
1887 Roo.log("menu.onClick");
1888 var t = this.findTargetItem(e);
1889 if(!t || t.isContainer){
1894 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1895 if(t == this.activeItem && t.shouldDeactivate(e)){
1896 this.activeItem.deactivate();
1897 delete this.activeItem;
1901 this.setActiveItem(t, true);
1909 Roo.log('pass click event');
1913 this.fireEvent("click", this, t, e);
1917 onMouseOver : function(e){
1918 var t = this.findTargetItem(e);
1921 // if(t.canActivate && !t.disabled){
1922 // this.setActiveItem(t, true);
1926 this.fireEvent("mouseover", this, e, t);
1928 isVisible : function(){
1929 return !this.hidden;
1931 onMouseOut : function(e){
1932 var t = this.findTargetItem(e);
1935 // if(t == this.activeItem && t.shouldDeactivate(e)){
1936 // this.activeItem.deactivate();
1937 // delete this.activeItem;
1940 this.fireEvent("mouseout", this, e, t);
1945 * Displays this menu relative to another element
1946 * @param {String/HTMLElement/Roo.Element} element The element to align to
1947 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1948 * the element (defaults to this.defaultAlign)
1949 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1951 show : function(el, pos, parentMenu){
1952 this.parentMenu = parentMenu;
1956 this.fireEvent("beforeshow", this);
1957 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1960 * Displays this menu at a specific xy position
1961 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1962 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1964 showAt : function(xy, parentMenu, /* private: */_e){
1965 this.parentMenu = parentMenu;
1970 this.fireEvent("beforeshow", this);
1971 //xy = this.el.adjustForConstraints(xy);
1975 this.hideMenuItems();
1976 this.hidden = false;
1977 this.triggerEl.addClass('open');
1979 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
1980 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
1985 this.fireEvent("show", this);
1991 this.doFocus.defer(50, this);
1995 doFocus : function(){
1997 this.focusEl.focus();
2002 * Hides this menu and optionally all parent menus
2003 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2005 hide : function(deep){
2007 this.hideMenuItems();
2008 if(this.el && this.isVisible()){
2009 this.fireEvent("beforehide", this);
2010 if(this.activeItem){
2011 this.activeItem.deactivate();
2012 this.activeItem = null;
2014 this.triggerEl.removeClass('open');;
2016 this.fireEvent("hide", this);
2018 if(deep === true && this.parentMenu){
2019 this.parentMenu.hide(true);
2023 onTriggerPress : function(e)
2026 Roo.log('trigger press');
2027 //Roo.log(e.getTarget());
2028 // Roo.log(this.triggerEl.dom);
2029 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
2033 if (this.isVisible()) {
2038 this.show(this.triggerEl, false, false);
2047 hideMenuItems : function()
2049 //$(backdrop).remove()
2050 Roo.select('.open',true).each(function(aa) {
2052 aa.removeClass('open');
2053 //var parent = getParent($(this))
2054 //var relatedTarget = { relatedTarget: this }
2056 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2057 //if (e.isDefaultPrevented()) return
2058 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2061 addxtypeChild : function (tree, cntr) {
2062 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2064 this.menuitems.add(comp);
2085 * @class Roo.bootstrap.MenuItem
2086 * @extends Roo.bootstrap.Component
2087 * Bootstrap MenuItem class
2088 * @cfg {String} html the menu label
2089 * @cfg {String} href the link
2090 * @cfg {Boolean} preventDefault (true | false) default true
2091 * @cfg {Boolean} isContainer (true | false) default false
2095 * Create a new MenuItem
2096 * @param {Object} config The config object
2100 Roo.bootstrap.MenuItem = function(config){
2101 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2106 * The raw click event for the entire grid.
2107 * @param {Roo.bootstrap.MenuItem} this
2108 * @param {Roo.EventObject} e
2114 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2118 preventDefault: true,
2119 isContainer : false,
2121 getAutoCreate : function(){
2123 if(this.isContainer){
2126 cls: 'dropdown-menu-item'
2132 cls: 'dropdown-menu-item',
2141 if (this.parent().type == 'treeview') {
2142 cfg.cls = 'treeview-menu';
2145 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2146 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2150 initEvents: function() {
2152 //this.el.select('a').on('click', this.onClick, this);
2155 onClick : function(e)
2157 Roo.log('item on click ');
2158 //if(this.preventDefault){
2159 // e.preventDefault();
2161 //this.parent().hideMenuItems();
2163 this.fireEvent('click', this, e);
2182 * @class Roo.bootstrap.MenuSeparator
2183 * @extends Roo.bootstrap.Component
2184 * Bootstrap MenuSeparator class
2187 * Create a new MenuItem
2188 * @param {Object} config The config object
2192 Roo.bootstrap.MenuSeparator = function(config){
2193 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2196 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2198 getAutoCreate : function(){
2217 * @class Roo.bootstrap.Modal
2218 * @extends Roo.bootstrap.Component
2219 * Bootstrap Modal class
2220 * @cfg {String} title Title of dialog
2221 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2222 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2223 * @cfg {Boolean} specificTitle default false
2224 * @cfg {Array} buttons Array of buttons or standard button set..
2225 * @cfg {String} buttonPosition (left|right|center) default right
2226 * @cfg {Boolean} animate default true
2227 * @cfg {Boolean} allow_close default true
2230 * Create a new Modal Dialog
2231 * @param {Object} config The config object
2234 Roo.bootstrap.Modal = function(config){
2235 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2240 * The raw btnclick event for the button
2241 * @param {Roo.EventObject} e
2245 this.buttons = this.buttons || [];
2248 this.tmpl = Roo.factory(this.tmpl);
2253 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2255 title : 'test dialog',
2265 specificTitle: false,
2267 buttonPosition: 'right',
2281 onRender : function(ct, position)
2283 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2286 var cfg = Roo.apply({}, this.getAutoCreate());
2289 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2291 //if (!cfg.name.length) {
2295 cfg.cls += ' ' + this.cls;
2298 cfg.style = this.style;
2300 this.el = Roo.get(document.body).createChild(cfg, position);
2302 //var type = this.el.dom.type;
2307 if(this.tabIndex !== undefined){
2308 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2312 this.bodyEl = this.el.select('.modal-body',true).first();
2313 this.closeEl = this.el.select('.modal-header .close', true).first();
2314 this.footerEl = this.el.select('.modal-footer',true).first();
2315 this.titleEl = this.el.select('.modal-title',true).first();
2319 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2320 this.maskEl.enableDisplayMode("block");
2322 //this.el.addClass("x-dlg-modal");
2324 if (this.buttons.length) {
2325 Roo.each(this.buttons, function(bb) {
2326 b = Roo.apply({}, bb);
2327 b.xns = b.xns || Roo.bootstrap;
2328 b.xtype = b.xtype || 'Button';
2329 if (typeof(b.listeners) == 'undefined') {
2330 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2333 var btn = Roo.factory(b);
2335 btn.onRender(this.el.select('.modal-footer div').first());
2339 // render the children.
2342 if(typeof(this.items) != 'undefined'){
2343 var items = this.items;
2346 for(var i =0;i < items.length;i++) {
2347 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2351 this.items = nitems;
2353 // where are these used - they used to be body/close/footer
2357 //this.el.addClass([this.fieldClass, this.cls]);
2360 getAutoCreate : function(){
2365 html : this.html || ''
2370 cls : 'modal-title',
2374 if(this.specificTitle){
2380 if (this.allow_close) {
2391 style : 'display: none',
2394 cls: "modal-dialog",
2397 cls : "modal-content",
2400 cls : 'modal-header',
2405 cls : 'modal-footer',
2409 cls: 'btn-' + this.buttonPosition
2426 modal.cls += ' fade';
2432 getChildContainer : function() {
2437 getButtonContainer : function() {
2438 return this.el.select('.modal-footer div',true).first();
2441 initEvents : function()
2443 if (this.allow_close) {
2444 this.closeEl.on('click', this.hide, this);
2450 if (!this.rendered) {
2454 this.el.setStyle('display', 'block');
2458 (function(){ _this.el.addClass('in'); }).defer(50);
2460 this.el.addClass('in');
2463 // not sure how we can show data in here..
2465 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2468 Roo.get(document.body).addClass("x-body-masked");
2469 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2471 this.el.setStyle('zIndex', '10001');
2473 this.fireEvent('show', this);
2480 Roo.get(document.body).removeClass("x-body-masked");
2481 this.el.removeClass('in');
2485 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2487 this.el.setStyle('display', 'none');
2490 this.fireEvent('hide', this);
2493 addButton : function(str, cb)
2497 var b = Roo.apply({}, { html : str } );
2498 b.xns = b.xns || Roo.bootstrap;
2499 b.xtype = b.xtype || 'Button';
2500 if (typeof(b.listeners) == 'undefined') {
2501 b.listeners = { click : cb.createDelegate(this) };
2504 var btn = Roo.factory(b);
2506 btn.onRender(this.el.select('.modal-footer div').first());
2512 setDefaultButton : function(btn)
2514 //this.el.select('.modal-footer').()
2516 resizeTo: function(w,h)
2520 setContentSize : function(w, h)
2524 onButtonClick: function(btn,e)
2527 this.fireEvent('btnclick', btn.name, e);
2530 * Set the title of the Dialog
2531 * @param {String} str new Title
2533 setTitle: function(str) {
2534 this.titleEl.dom.innerHTML = str;
2537 * Set the body of the Dialog
2538 * @param {String} str new Title
2540 setBody: function(str) {
2541 this.bodyEl.dom.innerHTML = str;
2544 * Set the body of the Dialog using the template
2545 * @param {Obj} data - apply this data to the template and replace the body contents.
2547 applyBody: function(obj)
2550 Roo.log("Error - using apply Body without a template");
2553 this.tmpl.overwrite(this.bodyEl, obj);
2559 Roo.apply(Roo.bootstrap.Modal, {
2561 * Button config that displays a single OK button
2570 * Button config that displays Yes and No buttons
2586 * Button config that displays OK and Cancel buttons
2601 * Button config that displays Yes, No and Cancel buttons
2624 * messagebox - can be used as a replace
2628 * @class Roo.MessageBox
2629 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2633 Roo.Msg.alert('Status', 'Changes saved successfully.');
2635 // Prompt for user data:
2636 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2638 // process text value...
2642 // Show a dialog using config options:
2644 title:'Save Changes?',
2645 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2646 buttons: Roo.Msg.YESNOCANCEL,
2653 Roo.bootstrap.MessageBox = function(){
2654 var dlg, opt, mask, waitTimer;
2655 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2656 var buttons, activeTextEl, bwidth;
2660 var handleButton = function(button){
2662 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2666 var handleHide = function(){
2668 dlg.el.removeClass(opt.cls);
2671 // Roo.TaskMgr.stop(waitTimer);
2672 // waitTimer = null;
2677 var updateButtons = function(b){
2680 buttons["ok"].hide();
2681 buttons["cancel"].hide();
2682 buttons["yes"].hide();
2683 buttons["no"].hide();
2684 //dlg.footer.dom.style.display = 'none';
2687 dlg.footerEl.dom.style.display = '';
2688 for(var k in buttons){
2689 if(typeof buttons[k] != "function"){
2692 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2693 width += buttons[k].el.getWidth()+15;
2703 var handleEsc = function(d, k, e){
2704 if(opt && opt.closable !== false){
2714 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2715 * @return {Roo.BasicDialog} The BasicDialog element
2717 getDialog : function(){
2719 dlg = new Roo.bootstrap.Modal( {
2722 //constraintoviewport:false,
2724 //collapsible : false,
2729 //buttonAlign:"center",
2730 closeClick : function(){
2731 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2734 handleButton("cancel");
2739 dlg.on("hide", handleHide);
2741 //dlg.addKeyListener(27, handleEsc);
2743 this.buttons = buttons;
2744 var bt = this.buttonText;
2745 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2746 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2747 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2748 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2750 bodyEl = dlg.bodyEl.createChild({
2752 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2753 '<textarea class="roo-mb-textarea"></textarea>' +
2754 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2756 msgEl = bodyEl.dom.firstChild;
2757 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2758 textboxEl.enableDisplayMode();
2759 textboxEl.addKeyListener([10,13], function(){
2760 if(dlg.isVisible() && opt && opt.buttons){
2763 }else if(opt.buttons.yes){
2764 handleButton("yes");
2768 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2769 textareaEl.enableDisplayMode();
2770 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2771 progressEl.enableDisplayMode();
2772 var pf = progressEl.dom.firstChild;
2774 pp = Roo.get(pf.firstChild);
2775 pp.setHeight(pf.offsetHeight);
2783 * Updates the message box body text
2784 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2785 * the XHTML-compliant non-breaking space character '&#160;')
2786 * @return {Roo.MessageBox} This message box
2788 updateText : function(text){
2789 if(!dlg.isVisible() && !opt.width){
2790 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2792 msgEl.innerHTML = text || ' ';
2794 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2795 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2797 Math.min(opt.width || cw , this.maxWidth),
2798 Math.max(opt.minWidth || this.minWidth, bwidth)
2801 activeTextEl.setWidth(w);
2803 if(dlg.isVisible()){
2804 dlg.fixedcenter = false;
2806 // to big, make it scroll. = But as usual stupid IE does not support
2809 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2810 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2811 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2813 bodyEl.dom.style.height = '';
2814 bodyEl.dom.style.overflowY = '';
2817 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2819 bodyEl.dom.style.overflowX = '';
2822 dlg.setContentSize(w, bodyEl.getHeight());
2823 if(dlg.isVisible()){
2824 dlg.fixedcenter = true;
2830 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2831 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2832 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2833 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2834 * @return {Roo.MessageBox} This message box
2836 updateProgress : function(value, text){
2838 this.updateText(text);
2840 if (pp) { // weird bug on my firefox - for some reason this is not defined
2841 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2847 * Returns true if the message box is currently displayed
2848 * @return {Boolean} True if the message box is visible, else false
2850 isVisible : function(){
2851 return dlg && dlg.isVisible();
2855 * Hides the message box if it is displayed
2858 if(this.isVisible()){
2864 * Displays a new message box, or reinitializes an existing message box, based on the config options
2865 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2866 * The following config object properties are supported:
2868 Property Type Description
2869 ---------- --------------- ------------------------------------------------------------------------------------
2870 animEl String/Element An id or Element from which the message box should animate as it opens and
2871 closes (defaults to undefined)
2872 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2873 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2874 closable Boolean False to hide the top-right close button (defaults to true). Note that
2875 progress and wait dialogs will ignore this property and always hide the
2876 close button as they can only be closed programmatically.
2877 cls String A custom CSS class to apply to the message box element
2878 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2879 displayed (defaults to 75)
2880 fn Function A callback function to execute after closing the dialog. The arguments to the
2881 function will be btn (the name of the button that was clicked, if applicable,
2882 e.g. "ok"), and text (the value of the active text field, if applicable).
2883 Progress and wait dialogs will ignore this option since they do not respond to
2884 user actions and can only be closed programmatically, so any required function
2885 should be called by the same code after it closes the dialog.
2886 icon String A CSS class that provides a background image to be used as an icon for
2887 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2888 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2889 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2890 modal Boolean False to allow user interaction with the page while the message box is
2891 displayed (defaults to true)
2892 msg String A string that will replace the existing message box body text (defaults
2893 to the XHTML-compliant non-breaking space character ' ')
2894 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2895 progress Boolean True to display a progress bar (defaults to false)
2896 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2897 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2898 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2899 title String The title text
2900 value String The string value to set into the active textbox element if displayed
2901 wait Boolean True to display a progress bar (defaults to false)
2902 width Number The width of the dialog in pixels
2909 msg: 'Please enter your address:',
2911 buttons: Roo.MessageBox.OKCANCEL,
2914 animEl: 'addAddressBtn'
2917 * @param {Object} config Configuration options
2918 * @return {Roo.MessageBox} This message box
2920 show : function(options)
2923 // this causes nightmares if you show one dialog after another
2924 // especially on callbacks..
2926 if(this.isVisible()){
2929 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2930 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2931 Roo.log("New Dialog Message:" + options.msg )
2932 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2933 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2936 var d = this.getDialog();
2938 d.setTitle(opt.title || " ");
2939 d.closeEl.setDisplayed(opt.closable !== false);
2940 activeTextEl = textboxEl;
2941 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2946 textareaEl.setHeight(typeof opt.multiline == "number" ?
2947 opt.multiline : this.defaultTextHeight);
2948 activeTextEl = textareaEl;
2957 progressEl.setDisplayed(opt.progress === true);
2958 this.updateProgress(0);
2959 activeTextEl.dom.value = opt.value || "";
2961 dlg.setDefaultButton(activeTextEl);
2963 var bs = opt.buttons;
2967 }else if(bs && bs.yes){
2968 db = buttons["yes"];
2970 dlg.setDefaultButton(db);
2972 bwidth = updateButtons(opt.buttons);
2973 this.updateText(opt.msg);
2975 d.el.addClass(opt.cls);
2977 d.proxyDrag = opt.proxyDrag === true;
2978 d.modal = opt.modal !== false;
2979 d.mask = opt.modal !== false ? mask : false;
2981 // force it to the end of the z-index stack so it gets a cursor in FF
2982 document.body.appendChild(dlg.el.dom);
2983 d.animateTarget = null;
2984 d.show(options.animEl);
2990 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2991 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2992 * and closing the message box when the process is complete.
2993 * @param {String} title The title bar text
2994 * @param {String} msg The message box body text
2995 * @return {Roo.MessageBox} This message box
2997 progress : function(title, msg){
3004 minWidth: this.minProgressWidth,
3011 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3012 * If a callback function is passed it will be called after the user clicks the button, and the
3013 * id of the button that was clicked will be passed as the only parameter to the callback
3014 * (could also be the top-right close button).
3015 * @param {String} title The title bar text
3016 * @param {String} msg The message box body text
3017 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3018 * @param {Object} scope (optional) The scope of the callback function
3019 * @return {Roo.MessageBox} This message box
3021 alert : function(title, msg, fn, scope){
3034 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3035 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3036 * You are responsible for closing the message box when the process is complete.
3037 * @param {String} msg The message box body text
3038 * @param {String} title (optional) The title bar text
3039 * @return {Roo.MessageBox} This message box
3041 wait : function(msg, title){
3052 waitTimer = Roo.TaskMgr.start({
3054 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3062 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3063 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3064 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3065 * @param {String} title The title bar text
3066 * @param {String} msg The message box body text
3067 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3068 * @param {Object} scope (optional) The scope of the callback function
3069 * @return {Roo.MessageBox} This message box
3071 confirm : function(title, msg, fn, scope){
3075 buttons: this.YESNO,
3084 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3085 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3086 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3087 * (could also be the top-right close button) and the text that was entered will be passed as the two
3088 * parameters to the callback.
3089 * @param {String} title The title bar text
3090 * @param {String} msg The message box body text
3091 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3092 * @param {Object} scope (optional) The scope of the callback function
3093 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3094 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3095 * @return {Roo.MessageBox} This message box
3097 prompt : function(title, msg, fn, scope, multiline){
3101 buttons: this.OKCANCEL,
3106 multiline: multiline,
3113 * Button config that displays a single OK button
3118 * Button config that displays Yes and No buttons
3121 YESNO : {yes:true, no:true},
3123 * Button config that displays OK and Cancel buttons
3126 OKCANCEL : {ok:true, cancel:true},
3128 * Button config that displays Yes, No and Cancel buttons
3131 YESNOCANCEL : {yes:true, no:true, cancel:true},
3134 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3137 defaultTextHeight : 75,
3139 * The maximum width in pixels of the message box (defaults to 600)
3144 * The minimum width in pixels of the message box (defaults to 100)
3149 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3150 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3153 minProgressWidth : 250,
3155 * An object containing the default button text strings that can be overriden for localized language support.
3156 * Supported properties are: ok, cancel, yes and no.
3157 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3170 * Shorthand for {@link Roo.MessageBox}
3172 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3173 Roo.Msg = Roo.Msg || Roo.MessageBox;
3182 * @class Roo.bootstrap.Navbar
3183 * @extends Roo.bootstrap.Component
3184 * Bootstrap Navbar class
3187 * Create a new Navbar
3188 * @param {Object} config The config object
3192 Roo.bootstrap.Navbar = function(config){
3193 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3197 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3206 getAutoCreate : function(){
3209 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3213 initEvents :function ()
3215 //Roo.log(this.el.select('.navbar-toggle',true));
3216 this.el.select('.navbar-toggle',true).on('click', function() {
3217 // Roo.log('click');
3218 this.el.select('.navbar-collapse',true).toggleClass('in');
3226 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3228 var size = this.el.getSize();
3229 this.maskEl.setSize(size.width, size.height);
3230 this.maskEl.enableDisplayMode("block");
3239 getChildContainer : function()
3241 if (this.el.select('.collapse').getCount()) {
3242 return this.el.select('.collapse',true).first();
3275 * @class Roo.bootstrap.NavSimplebar
3276 * @extends Roo.bootstrap.Navbar
3277 * Bootstrap Sidebar class
3279 * @cfg {Boolean} inverse is inverted color
3281 * @cfg {String} type (nav | pills | tabs)
3282 * @cfg {Boolean} arrangement stacked | justified
3283 * @cfg {String} align (left | right) alignment
3285 * @cfg {Boolean} main (true|false) main nav bar? default false
3286 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3288 * @cfg {String} tag (header|footer|nav|div) default is nav
3294 * Create a new Sidebar
3295 * @param {Object} config The config object
3299 Roo.bootstrap.NavSimplebar = function(config){
3300 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3303 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3319 getAutoCreate : function(){
3323 tag : this.tag || 'div',
3336 this.type = this.type || 'nav';
3337 if (['tabs','pills'].indexOf(this.type)!==-1) {
3338 cfg.cn[0].cls += ' nav-' + this.type
3342 if (this.type!=='nav') {
3343 Roo.log('nav type must be nav/tabs/pills')
3345 cfg.cn[0].cls += ' navbar-nav'
3351 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3352 cfg.cn[0].cls += ' nav-' + this.arrangement;
3356 if (this.align === 'right') {
3357 cfg.cn[0].cls += ' navbar-right';
3361 cfg.cls += ' navbar-inverse';
3388 * @class Roo.bootstrap.NavHeaderbar
3389 * @extends Roo.bootstrap.NavSimplebar
3390 * Bootstrap Sidebar class
3392 * @cfg {String} brand what is brand
3393 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3394 * @cfg {String} brand_href href of the brand
3395 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3396 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3397 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3398 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3401 * Create a new Sidebar
3402 * @param {Object} config The config object
3406 Roo.bootstrap.NavHeaderbar = function(config){
3407 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3411 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3418 desktopCenter : false,
3421 getAutoCreate : function(){
3424 tag: this.nav || 'nav',
3431 if (this.desktopCenter) {
3432 cn.push({cls : 'container', cn : []});
3439 cls: 'navbar-header',
3444 cls: 'navbar-toggle',
3445 'data-toggle': 'collapse',
3450 html: 'Toggle navigation'
3472 cls: 'collapse navbar-collapse',
3476 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3478 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3479 cfg.cls += ' navbar-' + this.position;
3481 // tag can override this..
3483 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3486 if (this.brand !== '') {
3489 href: this.brand_href ? this.brand_href : '#',
3490 cls: 'navbar-brand',
3498 cfg.cls += ' main-nav';
3506 getHeaderChildContainer : function()
3508 if (this.el.select('.navbar-header').getCount()) {
3509 return this.el.select('.navbar-header',true).first();
3512 return this.getChildContainer();
3516 initEvents : function()
3518 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3520 if (this.autohide) {
3525 Roo.get(document).on('scroll',function(e) {
3526 var ns = Roo.get(document).getScroll().top;
3527 var os = prevScroll;
3531 ft.removeClass('slideDown');
3532 ft.addClass('slideUp');
3535 ft.removeClass('slideUp');
3536 ft.addClass('slideDown');
3557 * @class Roo.bootstrap.NavSidebar
3558 * @extends Roo.bootstrap.Navbar
3559 * Bootstrap Sidebar class
3562 * Create a new Sidebar
3563 * @param {Object} config The config object
3567 Roo.bootstrap.NavSidebar = function(config){
3568 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3571 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3573 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3575 getAutoCreate : function(){
3580 cls: 'sidebar sidebar-nav'
3602 * @class Roo.bootstrap.NavGroup
3603 * @extends Roo.bootstrap.Component
3604 * Bootstrap NavGroup class
3605 * @cfg {String} align left | right
3606 * @cfg {Boolean} inverse false | true
3607 * @cfg {String} type (nav|pills|tab) default nav
3608 * @cfg {String} navId - reference Id for navbar.
3612 * Create a new nav group
3613 * @param {Object} config The config object
3616 Roo.bootstrap.NavGroup = function(config){
3617 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3620 Roo.bootstrap.NavGroup.register(this);
3624 * Fires when the active item changes
3625 * @param {Roo.bootstrap.NavGroup} this
3626 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3627 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3634 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3645 getAutoCreate : function()
3647 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3654 if (['tabs','pills'].indexOf(this.type)!==-1) {
3655 cfg.cls += ' nav-' + this.type
3657 if (this.type!=='nav') {
3658 Roo.log('nav type must be nav/tabs/pills')
3660 cfg.cls += ' navbar-nav'
3663 if (this.parent().sidebar) {
3666 cls: 'dashboard-menu sidebar-menu'
3672 if (this.form === true) {
3678 if (this.align === 'right') {
3679 cfg.cls += ' navbar-right';
3681 cfg.cls += ' navbar-left';
3685 if (this.align === 'right') {
3686 cfg.cls += ' navbar-right';
3690 cfg.cls += ' navbar-inverse';
3698 * sets the active Navigation item
3699 * @param {Roo.bootstrap.NavItem} the new current navitem
3701 setActiveItem : function(item)
3704 Roo.each(this.navItems, function(v){
3709 v.setActive(false, true);
3716 item.setActive(true, true);
3717 this.fireEvent('changed', this, item, prev);
3722 * gets the active Navigation item
3723 * @return {Roo.bootstrap.NavItem} the current navitem
3725 getActive : function()
3729 Roo.each(this.navItems, function(v){
3740 indexOfNav : function()
3744 Roo.each(this.navItems, function(v,i){
3755 * adds a Navigation item
3756 * @param {Roo.bootstrap.NavItem} the navitem to add
3758 addItem : function(cfg)
3760 var cn = new Roo.bootstrap.NavItem(cfg);
3762 cn.parentId = this.id;
3763 cn.onRender(this.el, null);
3767 * register a Navigation item
3768 * @param {Roo.bootstrap.NavItem} the navitem to add
3770 register : function(item)
3772 this.navItems.push( item);
3773 item.navId = this.navId;
3778 * clear all the Navigation item
3781 clearAll : function()
3784 this.el.dom.innerHTML = '';
3787 getNavItem: function(tabId)
3790 Roo.each(this.navItems, function(e) {
3791 if (e.tabId == tabId) {
3801 setActiveNext : function()
3803 var i = this.indexOfNav(this.getActive());
3804 if (i > this.navItems.length) {
3807 this.setActiveItem(this.navItems[i+1]);
3809 setActivePrev : function()
3811 var i = this.indexOfNav(this.getActive());
3815 this.setActiveItem(this.navItems[i-1]);
3817 clearWasActive : function(except) {
3818 Roo.each(this.navItems, function(e) {
3819 if (e.tabId != except.tabId && e.was_active) {
3820 e.was_active = false;
3827 getWasActive : function ()
3830 Roo.each(this.navItems, function(e) {
3845 Roo.apply(Roo.bootstrap.NavGroup, {
3849 * register a Navigation Group
3850 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3852 register : function(navgrp)
3854 this.groups[navgrp.navId] = navgrp;
3858 * fetch a Navigation Group based on the navigation ID
3859 * @param {string} the navgroup to add
3860 * @returns {Roo.bootstrap.NavGroup} the navgroup
3862 get: function(navId) {
3863 if (typeof(this.groups[navId]) == 'undefined') {
3865 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3867 return this.groups[navId] ;
3882 * @class Roo.bootstrap.NavItem
3883 * @extends Roo.bootstrap.Component
3884 * Bootstrap Navbar.NavItem class
3885 * @cfg {String} href link to
3886 * @cfg {String} html content of button
3887 * @cfg {String} badge text inside badge
3888 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3889 * @cfg {String} glyphicon name of glyphicon
3890 * @cfg {String} icon name of font awesome icon
3891 * @cfg {Boolean} active Is item active
3892 * @cfg {Boolean} disabled Is item disabled
3894 * @cfg {Boolean} preventDefault (true | false) default false
3895 * @cfg {String} tabId the tab that this item activates.
3896 * @cfg {String} tagtype (a|span) render as a href or span?
3897 * @cfg {Boolean} animateRef (true|false) link to element default false
3900 * Create a new Navbar Item
3901 * @param {Object} config The config object
3903 Roo.bootstrap.NavItem = function(config){
3904 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3909 * The raw click event for the entire grid.
3910 * @param {Roo.EventObject} e
3915 * Fires when the active item active state changes
3916 * @param {Roo.bootstrap.NavItem} this
3917 * @param {boolean} state the new state
3923 * Fires when scroll to element
3924 * @param {Roo.bootstrap.NavItem} this
3925 * @param {Object} options
3926 * @param {Roo.EventObject} e
3934 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3942 preventDefault : false,
3949 getAutoCreate : function(){
3957 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3959 if (this.disabled) {
3960 cfg.cls += ' disabled';
3963 if (this.href || this.html || this.glyphicon || this.icon) {
3967 href : this.href || "#",
3968 html: this.html || ''
3973 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3976 if(this.glyphicon) {
3977 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3982 cfg.cn[0].html += " <span class='caret'></span>";
3986 if (this.badge !== '') {
3988 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3996 initEvents: function()
3998 if (typeof (this.menu) != 'undefined') {
3999 this.menu.parentType = this.xtype;
4000 this.menu.triggerEl = this.el;
4001 this.menu = this.addxtype(Roo.apply({}, this.menu));
4004 this.el.select('a',true).on('click', this.onClick, this);
4006 if(this.tagtype == 'span'){
4007 this.el.select('span',true).on('click', this.onClick, this);
4010 // at this point parent should be available..
4011 this.parent().register(this);
4014 onClick : function(e)
4017 this.preventDefault ||
4024 if (this.disabled) {
4028 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4029 if (tg && tg.transition) {
4030 Roo.log("waiting for the transitionend");
4036 //Roo.log("fire event clicked");
4037 if(this.fireEvent('click', this, e) === false){
4041 if(this.tagtype == 'span'){
4045 //Roo.log(this.href);
4046 var ael = this.el.select('a',true).first();
4049 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4050 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4051 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4052 return; // ignore... - it's a 'hash' to another page.
4056 this.scrollToElement(e);
4060 var p = this.parent();
4062 if (['tabs','pills'].indexOf(p.type)!==-1) {
4063 if (typeof(p.setActiveItem) !== 'undefined') {
4064 p.setActiveItem(this);
4068 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4069 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4070 // remove the collapsed menu expand...
4071 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4075 isActive: function () {
4078 setActive : function(state, fire, is_was_active)
4080 if (this.active && !state & this.navId) {
4081 this.was_active = true;
4082 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4084 nv.clearWasActive(this);
4088 this.active = state;
4091 this.el.removeClass('active');
4092 } else if (!this.el.hasClass('active')) {
4093 this.el.addClass('active');
4096 this.fireEvent('changed', this, state);
4099 // show a panel if it's registered and related..
4101 if (!this.navId || !this.tabId || !state || is_was_active) {
4105 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4109 var pan = tg.getPanelByName(this.tabId);
4113 // if we can not flip to new panel - go back to old nav highlight..
4114 if (false == tg.showPanel(pan)) {
4115 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4117 var onav = nv.getWasActive();
4119 onav.setActive(true, false, true);
4128 // this should not be here...
4129 setDisabled : function(state)
4131 this.disabled = state;
4133 this.el.removeClass('disabled');
4134 } else if (!this.el.hasClass('disabled')) {
4135 this.el.addClass('disabled');
4141 * Fetch the element to display the tooltip on.
4142 * @return {Roo.Element} defaults to this.el
4144 tooltipEl : function()
4146 return this.el.select('' + this.tagtype + '', true).first();
4149 scrollToElement : function(e)
4151 var c = document.body;
4154 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4156 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4157 c = document.documentElement;
4160 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4166 var o = target.calcOffsetsTo(c);
4173 this.fireEvent('scrollto', this, options, e);
4175 Roo.get(c).scrollTo('top', options.value, true);
4188 * <span> icon </span>
4189 * <span> text </span>
4190 * <span>badge </span>
4194 * @class Roo.bootstrap.NavSidebarItem
4195 * @extends Roo.bootstrap.NavItem
4196 * Bootstrap Navbar.NavSidebarItem class
4198 * Create a new Navbar Button
4199 * @param {Object} config The config object
4201 Roo.bootstrap.NavSidebarItem = function(config){
4202 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4207 * The raw click event for the entire grid.
4208 * @param {Roo.EventObject} e
4213 * Fires when the active item active state changes
4214 * @param {Roo.bootstrap.NavSidebarItem} this
4215 * @param {boolean} state the new state
4223 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4226 getAutoCreate : function(){
4231 href : this.href || '#',
4243 html : this.html || ''
4248 cfg.cls += ' active';
4252 if (this.glyphicon || this.icon) {
4253 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4254 a.cn.push({ tag : 'i', cls : c }) ;
4259 if (this.badge !== '') {
4260 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4264 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4265 a.cls += 'dropdown-toggle treeview' ;
4289 * @class Roo.bootstrap.Row
4290 * @extends Roo.bootstrap.Component
4291 * Bootstrap Row class (contains columns...)
4295 * @param {Object} config The config object
4298 Roo.bootstrap.Row = function(config){
4299 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4302 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4304 getAutoCreate : function(){
4323 * @class Roo.bootstrap.Element
4324 * @extends Roo.bootstrap.Component
4325 * Bootstrap Element class
4326 * @cfg {String} html contents of the element
4327 * @cfg {String} tag tag of the element
4328 * @cfg {String} cls class of the element
4329 * @cfg {Boolean} preventDefault (true|false) default false
4330 * @cfg {Boolean} clickable (true|false) default false
4333 * Create a new Element
4334 * @param {Object} config The config object
4337 Roo.bootstrap.Element = function(config){
4338 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4344 * When a element is chick
4345 * @param {Roo.bootstrap.Element} this
4346 * @param {Roo.EventObject} e
4352 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4357 preventDefault: false,
4360 getAutoCreate : function(){
4371 initEvents: function()
4373 Roo.bootstrap.Element.superclass.initEvents.call(this);
4376 this.el.on('click', this.onClick, this);
4381 onClick : function(e)
4383 if(this.preventDefault){
4387 this.fireEvent('click', this, e);
4390 getValue : function()
4392 return this.el.dom.innerHTML;
4395 setValue : function(value)
4397 this.el.dom.innerHTML = value;
4412 * @class Roo.bootstrap.Pagination
4413 * @extends Roo.bootstrap.Component
4414 * Bootstrap Pagination class
4415 * @cfg {String} size xs | sm | md | lg
4416 * @cfg {Boolean} inverse false | true
4419 * Create a new Pagination
4420 * @param {Object} config The config object
4423 Roo.bootstrap.Pagination = function(config){
4424 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4427 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4433 getAutoCreate : function(){
4439 cfg.cls += ' inverse';
4445 cfg.cls += " " + this.cls;
4463 * @class Roo.bootstrap.PaginationItem
4464 * @extends Roo.bootstrap.Component
4465 * Bootstrap PaginationItem class
4466 * @cfg {String} html text
4467 * @cfg {String} href the link
4468 * @cfg {Boolean} preventDefault (true | false) default true
4469 * @cfg {Boolean} active (true | false) default false
4470 * @cfg {Boolean} disabled default false
4474 * Create a new PaginationItem
4475 * @param {Object} config The config object
4479 Roo.bootstrap.PaginationItem = function(config){
4480 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4485 * The raw click event for the entire grid.
4486 * @param {Roo.EventObject} e
4492 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4496 preventDefault: true,
4501 getAutoCreate : function(){
4507 href : this.href ? this.href : '#',
4508 html : this.html ? this.html : ''
4518 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4522 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4528 initEvents: function() {
4530 this.el.on('click', this.onClick, this);
4533 onClick : function(e)
4535 Roo.log('PaginationItem on click ');
4536 if(this.preventDefault){
4544 this.fireEvent('click', this, e);
4560 * @class Roo.bootstrap.Slider
4561 * @extends Roo.bootstrap.Component
4562 * Bootstrap Slider class
4565 * Create a new Slider
4566 * @param {Object} config The config object
4569 Roo.bootstrap.Slider = function(config){
4570 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4573 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4575 getAutoCreate : function(){
4579 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4583 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4595 * Ext JS Library 1.1.1
4596 * Copyright(c) 2006-2007, Ext JS, LLC.
4598 * Originally Released Under LGPL - original licence link has changed is not relivant.
4601 * <script type="text/javascript">
4606 * @class Roo.grid.ColumnModel
4607 * @extends Roo.util.Observable
4608 * This is the default implementation of a ColumnModel used by the Grid. It defines
4609 * the columns in the grid.
4612 var colModel = new Roo.grid.ColumnModel([
4613 {header: "Ticker", width: 60, sortable: true, locked: true},
4614 {header: "Company Name", width: 150, sortable: true},
4615 {header: "Market Cap.", width: 100, sortable: true},
4616 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4617 {header: "Employees", width: 100, sortable: true, resizable: false}
4622 * The config options listed for this class are options which may appear in each
4623 * individual column definition.
4624 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4626 * @param {Object} config An Array of column config objects. See this class's
4627 * config objects for details.
4629 Roo.grid.ColumnModel = function(config){
4631 * The config passed into the constructor
4633 this.config = config;
4636 // if no id, create one
4637 // if the column does not have a dataIndex mapping,
4638 // map it to the order it is in the config
4639 for(var i = 0, len = config.length; i < len; i++){
4641 if(typeof c.dataIndex == "undefined"){
4644 if(typeof c.renderer == "string"){
4645 c.renderer = Roo.util.Format[c.renderer];
4647 if(typeof c.id == "undefined"){
4650 if(c.editor && c.editor.xtype){
4651 c.editor = Roo.factory(c.editor, Roo.grid);
4653 if(c.editor && c.editor.isFormField){
4654 c.editor = new Roo.grid.GridEditor(c.editor);
4656 this.lookup[c.id] = c;
4660 * The width of columns which have no width specified (defaults to 100)
4663 this.defaultWidth = 100;
4666 * Default sortable of columns which have no sortable specified (defaults to false)
4669 this.defaultSortable = false;
4673 * @event widthchange
4674 * Fires when the width of a column changes.
4675 * @param {ColumnModel} this
4676 * @param {Number} columnIndex The column index
4677 * @param {Number} newWidth The new width
4679 "widthchange": true,
4681 * @event headerchange
4682 * Fires when the text of a header changes.
4683 * @param {ColumnModel} this
4684 * @param {Number} columnIndex The column index
4685 * @param {Number} newText The new header text
4687 "headerchange": true,
4689 * @event hiddenchange
4690 * Fires when a column is hidden or "unhidden".
4691 * @param {ColumnModel} this
4692 * @param {Number} columnIndex The column index
4693 * @param {Boolean} hidden true if hidden, false otherwise
4695 "hiddenchange": true,
4697 * @event columnmoved
4698 * Fires when a column is moved.
4699 * @param {ColumnModel} this
4700 * @param {Number} oldIndex
4701 * @param {Number} newIndex
4703 "columnmoved" : true,
4705 * @event columlockchange
4706 * Fires when a column's locked state is changed
4707 * @param {ColumnModel} this
4708 * @param {Number} colIndex
4709 * @param {Boolean} locked true if locked
4711 "columnlockchange" : true
4713 Roo.grid.ColumnModel.superclass.constructor.call(this);
4715 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4717 * @cfg {String} header The header text to display in the Grid view.
4720 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4721 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4722 * specified, the column's index is used as an index into the Record's data Array.
4725 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4726 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4729 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4730 * Defaults to the value of the {@link #defaultSortable} property.
4731 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4734 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4737 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4740 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4743 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4746 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4747 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4748 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4749 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4752 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4755 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4758 * @cfg {String} cursor (Optional)
4761 * @cfg {String} tooltip (Optional)
4764 * Returns the id of the column at the specified index.
4765 * @param {Number} index The column index
4766 * @return {String} the id
4768 getColumnId : function(index){
4769 return this.config[index].id;
4773 * Returns the column for a specified id.
4774 * @param {String} id The column id
4775 * @return {Object} the column
4777 getColumnById : function(id){
4778 return this.lookup[id];
4783 * Returns the column for a specified dataIndex.
4784 * @param {String} dataIndex The column dataIndex
4785 * @return {Object|Boolean} the column or false if not found
4787 getColumnByDataIndex: function(dataIndex){
4788 var index = this.findColumnIndex(dataIndex);
4789 return index > -1 ? this.config[index] : false;
4793 * Returns the index for a specified column id.
4794 * @param {String} id The column id
4795 * @return {Number} the index, or -1 if not found
4797 getIndexById : function(id){
4798 for(var i = 0, len = this.config.length; i < len; i++){
4799 if(this.config[i].id == id){
4807 * Returns the index for a specified column dataIndex.
4808 * @param {String} dataIndex The column dataIndex
4809 * @return {Number} the index, or -1 if not found
4812 findColumnIndex : function(dataIndex){
4813 for(var i = 0, len = this.config.length; i < len; i++){
4814 if(this.config[i].dataIndex == dataIndex){
4822 moveColumn : function(oldIndex, newIndex){
4823 var c = this.config[oldIndex];
4824 this.config.splice(oldIndex, 1);
4825 this.config.splice(newIndex, 0, c);
4826 this.dataMap = null;
4827 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4830 isLocked : function(colIndex){
4831 return this.config[colIndex].locked === true;
4834 setLocked : function(colIndex, value, suppressEvent){
4835 if(this.isLocked(colIndex) == value){
4838 this.config[colIndex].locked = value;
4840 this.fireEvent("columnlockchange", this, colIndex, value);
4844 getTotalLockedWidth : function(){
4846 for(var i = 0; i < this.config.length; i++){
4847 if(this.isLocked(i) && !this.isHidden(i)){
4848 this.totalWidth += this.getColumnWidth(i);
4854 getLockedCount : function(){
4855 for(var i = 0, len = this.config.length; i < len; i++){
4856 if(!this.isLocked(i)){
4863 * Returns the number of columns.
4866 getColumnCount : function(visibleOnly){
4867 if(visibleOnly === true){
4869 for(var i = 0, len = this.config.length; i < len; i++){
4870 if(!this.isHidden(i)){
4876 return this.config.length;
4880 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4881 * @param {Function} fn
4882 * @param {Object} scope (optional)
4883 * @return {Array} result
4885 getColumnsBy : function(fn, scope){
4887 for(var i = 0, len = this.config.length; i < len; i++){
4888 var c = this.config[i];
4889 if(fn.call(scope||this, c, i) === true){
4897 * Returns true if the specified column is sortable.
4898 * @param {Number} col The column index
4901 isSortable : function(col){
4902 if(typeof this.config[col].sortable == "undefined"){
4903 return this.defaultSortable;
4905 return this.config[col].sortable;
4909 * Returns the rendering (formatting) function defined for the column.
4910 * @param {Number} col The column index.
4911 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4913 getRenderer : function(col){
4914 if(!this.config[col].renderer){
4915 return Roo.grid.ColumnModel.defaultRenderer;
4917 return this.config[col].renderer;
4921 * Sets the rendering (formatting) function for a column.
4922 * @param {Number} col The column index
4923 * @param {Function} fn The function to use to process the cell's raw data
4924 * to return HTML markup for the grid view. The render function is called with
4925 * the following parameters:<ul>
4926 * <li>Data value.</li>
4927 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4928 * <li>css A CSS style string to apply to the table cell.</li>
4929 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4930 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4931 * <li>Row index</li>
4932 * <li>Column index</li>
4933 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4935 setRenderer : function(col, fn){
4936 this.config[col].renderer = fn;
4940 * Returns the width for the specified column.
4941 * @param {Number} col The column index
4944 getColumnWidth : function(col){
4945 return this.config[col].width * 1 || this.defaultWidth;
4949 * Sets the width for a column.
4950 * @param {Number} col The column index
4951 * @param {Number} width The new width
4953 setColumnWidth : function(col, width, suppressEvent){
4954 this.config[col].width = width;
4955 this.totalWidth = null;
4957 this.fireEvent("widthchange", this, col, width);
4962 * Returns the total width of all columns.
4963 * @param {Boolean} includeHidden True to include hidden column widths
4966 getTotalWidth : function(includeHidden){
4967 if(!this.totalWidth){
4968 this.totalWidth = 0;
4969 for(var i = 0, len = this.config.length; i < len; i++){
4970 if(includeHidden || !this.isHidden(i)){
4971 this.totalWidth += this.getColumnWidth(i);
4975 return this.totalWidth;
4979 * Returns the header for the specified column.
4980 * @param {Number} col The column index
4983 getColumnHeader : function(col){
4984 return this.config[col].header;
4988 * Sets the header for a column.
4989 * @param {Number} col The column index
4990 * @param {String} header The new header
4992 setColumnHeader : function(col, header){
4993 this.config[col].header = header;
4994 this.fireEvent("headerchange", this, col, header);
4998 * Returns the tooltip for the specified column.
4999 * @param {Number} col The column index
5002 getColumnTooltip : function(col){
5003 return this.config[col].tooltip;
5006 * Sets the tooltip for a column.
5007 * @param {Number} col The column index
5008 * @param {String} tooltip The new tooltip
5010 setColumnTooltip : function(col, tooltip){
5011 this.config[col].tooltip = tooltip;
5015 * Returns the dataIndex for the specified column.
5016 * @param {Number} col The column index
5019 getDataIndex : function(col){
5020 return this.config[col].dataIndex;
5024 * Sets the dataIndex for a column.
5025 * @param {Number} col The column index
5026 * @param {Number} dataIndex The new dataIndex
5028 setDataIndex : function(col, dataIndex){
5029 this.config[col].dataIndex = dataIndex;
5035 * Returns true if the cell is editable.
5036 * @param {Number} colIndex The column index
5037 * @param {Number} rowIndex The row index
5040 isCellEditable : function(colIndex, rowIndex){
5041 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5045 * Returns the editor defined for the cell/column.
5046 * return false or null to disable editing.
5047 * @param {Number} colIndex The column index
5048 * @param {Number} rowIndex The row index
5051 getCellEditor : function(colIndex, rowIndex){
5052 return this.config[colIndex].editor;
5056 * Sets if a column is editable.
5057 * @param {Number} col The column index
5058 * @param {Boolean} editable True if the column is editable
5060 setEditable : function(col, editable){
5061 this.config[col].editable = editable;
5066 * Returns true if the column is hidden.
5067 * @param {Number} colIndex The column index
5070 isHidden : function(colIndex){
5071 return this.config[colIndex].hidden;
5076 * Returns true if the column width cannot be changed
5078 isFixed : function(colIndex){
5079 return this.config[colIndex].fixed;
5083 * Returns true if the column can be resized
5086 isResizable : function(colIndex){
5087 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5090 * Sets if a column is hidden.
5091 * @param {Number} colIndex The column index
5092 * @param {Boolean} hidden True if the column is hidden
5094 setHidden : function(colIndex, hidden){
5095 this.config[colIndex].hidden = hidden;
5096 this.totalWidth = null;
5097 this.fireEvent("hiddenchange", this, colIndex, hidden);
5101 * Sets the editor for a column.
5102 * @param {Number} col The column index
5103 * @param {Object} editor The editor object
5105 setEditor : function(col, editor){
5106 this.config[col].editor = editor;
5110 Roo.grid.ColumnModel.defaultRenderer = function(value){
5111 if(typeof value == "string" && value.length < 1){
5117 // Alias for backwards compatibility
5118 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5121 * Ext JS Library 1.1.1
5122 * Copyright(c) 2006-2007, Ext JS, LLC.
5124 * Originally Released Under LGPL - original licence link has changed is not relivant.
5127 * <script type="text/javascript">
5131 * @class Roo.LoadMask
5132 * A simple utility class for generically masking elements while loading data. If the element being masked has
5133 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5134 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5135 * element's UpdateManager load indicator and will be destroyed after the initial load.
5137 * Create a new LoadMask
5138 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5139 * @param {Object} config The config object
5141 Roo.LoadMask = function(el, config){
5142 this.el = Roo.get(el);
5143 Roo.apply(this, config);
5145 this.store.on('beforeload', this.onBeforeLoad, this);
5146 this.store.on('load', this.onLoad, this);
5147 this.store.on('loadexception', this.onLoadException, this);
5148 this.removeMask = false;
5150 var um = this.el.getUpdateManager();
5151 um.showLoadIndicator = false; // disable the default indicator
5152 um.on('beforeupdate', this.onBeforeLoad, this);
5153 um.on('update', this.onLoad, this);
5154 um.on('failure', this.onLoad, this);
5155 this.removeMask = true;
5159 Roo.LoadMask.prototype = {
5161 * @cfg {Boolean} removeMask
5162 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5163 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5167 * The text to display in a centered loading message box (defaults to 'Loading...')
5171 * @cfg {String} msgCls
5172 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5174 msgCls : 'x-mask-loading',
5177 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5183 * Disables the mask to prevent it from being displayed
5185 disable : function(){
5186 this.disabled = true;
5190 * Enables the mask so that it can be displayed
5192 enable : function(){
5193 this.disabled = false;
5196 onLoadException : function()
5200 if (typeof(arguments[3]) != 'undefined') {
5201 Roo.MessageBox.alert("Error loading",arguments[3]);
5205 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5206 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5215 this.el.unmask(this.removeMask);
5220 this.el.unmask(this.removeMask);
5224 onBeforeLoad : function(){
5226 this.el.mask(this.msg, this.msgCls);
5231 destroy : function(){
5233 this.store.un('beforeload', this.onBeforeLoad, this);
5234 this.store.un('load', this.onLoad, this);
5235 this.store.un('loadexception', this.onLoadException, this);
5237 var um = this.el.getUpdateManager();
5238 um.un('beforeupdate', this.onBeforeLoad, this);
5239 um.un('update', this.onLoad, this);
5240 um.un('failure', this.onLoad, this);
5251 * @class Roo.bootstrap.Table
5252 * @extends Roo.bootstrap.Component
5253 * Bootstrap Table class
5254 * @cfg {String} cls table class
5255 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5256 * @cfg {String} bgcolor Specifies the background color for a table
5257 * @cfg {Number} border Specifies whether the table cells should have borders or not
5258 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5259 * @cfg {Number} cellspacing Specifies the space between cells
5260 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5261 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5262 * @cfg {String} sortable Specifies that the table should be sortable
5263 * @cfg {String} summary Specifies a summary of the content of a table
5264 * @cfg {Number} width Specifies the width of a table
5265 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5267 * @cfg {boolean} striped Should the rows be alternative striped
5268 * @cfg {boolean} bordered Add borders to the table
5269 * @cfg {boolean} hover Add hover highlighting
5270 * @cfg {boolean} condensed Format condensed
5271 * @cfg {boolean} responsive Format condensed
5272 * @cfg {Boolean} loadMask (true|false) default false
5273 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5274 * @cfg {Boolean} thead (true|false) generate thead, default true
5275 * @cfg {Boolean} RowSelection (true|false) default false
5276 * @cfg {Boolean} CellSelection (true|false) default false
5277 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5281 * Create a new Table
5282 * @param {Object} config The config object
5285 Roo.bootstrap.Table = function(config){
5286 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5289 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5290 this.sm = this.selModel;
5291 this.sm.xmodule = this.xmodule || false;
5293 if (this.cm && typeof(this.cm.config) == 'undefined') {
5294 this.colModel = new Roo.grid.ColumnModel(this.cm);
5295 this.cm = this.colModel;
5296 this.cm.xmodule = this.xmodule || false;
5299 this.store= Roo.factory(this.store, Roo.data);
5300 this.ds = this.store;
5301 this.ds.xmodule = this.xmodule || false;
5304 if (this.footer && this.store) {
5305 this.footer.dataSource = this.ds;
5306 this.footer = Roo.factory(this.footer);
5313 * Fires when a cell is clicked
5314 * @param {Roo.bootstrap.Table} this
5315 * @param {Roo.Element} el
5316 * @param {Number} rowIndex
5317 * @param {Number} columnIndex
5318 * @param {Roo.EventObject} e
5322 * @event celldblclick
5323 * Fires when a cell is double clicked
5324 * @param {Roo.bootstrap.Table} this
5325 * @param {Roo.Element} el
5326 * @param {Number} rowIndex
5327 * @param {Number} columnIndex
5328 * @param {Roo.EventObject} e
5330 "celldblclick" : true,
5333 * Fires when a row is clicked
5334 * @param {Roo.bootstrap.Table} this
5335 * @param {Roo.Element} el
5336 * @param {Number} rowIndex
5337 * @param {Roo.EventObject} e
5341 * @event rowdblclick
5342 * Fires when a row is double clicked
5343 * @param {Roo.bootstrap.Table} this
5344 * @param {Roo.Element} el
5345 * @param {Number} rowIndex
5346 * @param {Roo.EventObject} e
5348 "rowdblclick" : true,
5351 * Fires when a mouseover occur
5352 * @param {Roo.bootstrap.Table} this
5353 * @param {Roo.Element} el
5354 * @param {Number} rowIndex
5355 * @param {Number} columnIndex
5356 * @param {Roo.EventObject} e
5361 * Fires when a mouseout occur
5362 * @param {Roo.bootstrap.Table} this
5363 * @param {Roo.Element} el
5364 * @param {Number} rowIndex
5365 * @param {Number} columnIndex
5366 * @param {Roo.EventObject} e
5371 * Fires when a row is rendered, so you can change add a style to it.
5372 * @param {Roo.bootstrap.Table} this
5373 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5377 * @event rowsrendered
5378 * Fires when all the rows have been rendered
5379 * @param {Roo.bootstrap.Table} this
5381 'rowsrendered' : true
5386 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5410 RowSelection : false,
5411 CellSelection : false,
5414 // Roo.Element - the tbody
5417 getAutoCreate : function(){
5418 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5427 cfg.cls += ' table-striped';
5431 cfg.cls += ' table-hover';
5433 if (this.bordered) {
5434 cfg.cls += ' table-bordered';
5436 if (this.condensed) {
5437 cfg.cls += ' table-condensed';
5439 if (this.responsive) {
5440 cfg.cls += ' table-responsive';
5444 cfg.cls+= ' ' +this.cls;
5447 // this lot should be simplifed...
5450 cfg.align=this.align;
5453 cfg.bgcolor=this.bgcolor;
5456 cfg.border=this.border;
5458 if (this.cellpadding) {
5459 cfg.cellpadding=this.cellpadding;
5461 if (this.cellspacing) {
5462 cfg.cellspacing=this.cellspacing;
5465 cfg.frame=this.frame;
5468 cfg.rules=this.rules;
5470 if (this.sortable) {
5471 cfg.sortable=this.sortable;
5474 cfg.summary=this.summary;
5477 cfg.width=this.width;
5480 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5483 if(this.store || this.cm){
5485 cfg.cn.push(this.renderHeader());
5488 cfg.cn.push(this.renderBody());
5491 cfg.cn.push(this.renderFooter());
5494 cfg.cls+= ' TableGrid';
5497 return { cn : [ cfg ] };
5500 initEvents : function()
5502 if(!this.store || !this.cm){
5506 //Roo.log('initEvents with ds!!!!');
5508 this.mainBody = this.el.select('tbody', true).first();
5513 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5514 e.on('click', _this.sort, _this);
5517 this.el.on("click", this.onClick, this);
5518 this.el.on("dblclick", this.onDblClick, this);
5520 // why is this done????? = it breaks dialogs??
5521 //this.parent().el.setStyle('position', 'relative');
5525 this.footer.parentId = this.id;
5526 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5529 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5531 this.store.on('load', this.onLoad, this);
5532 this.store.on('beforeload', this.onBeforeLoad, this);
5533 this.store.on('update', this.onUpdate, this);
5534 this.store.on('add', this.onAdd, this);
5538 onMouseover : function(e, el)
5540 var cell = Roo.get(el);
5546 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5547 cell = cell.findParent('td', false, true);
5550 var row = cell.findParent('tr', false, true);
5551 var cellIndex = cell.dom.cellIndex;
5552 var rowIndex = row.dom.rowIndex - 1; // start from 0
5554 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
5558 onMouseout : function(e, el)
5560 var cell = Roo.get(el);
5566 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5567 cell = cell.findParent('td', false, true);
5570 var row = cell.findParent('tr', false, true);
5571 var cellIndex = cell.dom.cellIndex;
5572 var rowIndex = row.dom.rowIndex - 1; // start from 0
5574 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5578 onClick : function(e, el)
5580 var cell = Roo.get(el);
5582 if(!cell || (!this.CellSelection && !this.RowSelection)){
5586 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5587 cell = cell.findParent('td', false, true);
5590 if(!cell || typeof(cell) == 'undefined'){
5594 var row = cell.findParent('tr', false, true);
5596 if(!row || typeof(row) == 'undefined'){
5600 var cellIndex = cell.dom.cellIndex;
5601 var rowIndex = this.getRowIndex(row);
5603 if(this.CellSelection){
5604 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5607 if(this.RowSelection){
5608 this.fireEvent('rowclick', this, row, rowIndex, e);
5614 onDblClick : function(e,el)
5616 var cell = Roo.get(el);
5618 if(!cell || (!this.CellSelection && !this.RowSelection)){
5622 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5623 cell = cell.findParent('td', false, true);
5626 if(!cell || typeof(cell) == 'undefined'){
5630 var row = cell.findParent('tr', false, true);
5632 if(!row || typeof(row) == 'undefined'){
5636 var cellIndex = cell.dom.cellIndex;
5637 var rowIndex = this.getRowIndex(row);
5639 if(this.CellSelection){
5640 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5643 if(this.RowSelection){
5644 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5648 sort : function(e,el)
5650 var col = Roo.get(el);
5652 if(!col.hasClass('sortable')){
5656 var sort = col.attr('sort');
5659 if(col.hasClass('glyphicon-arrow-up')){
5663 this.store.sortInfo = {field : sort, direction : dir};
5666 Roo.log("calling footer first");
5667 this.footer.onClick('first');
5670 this.store.load({ params : { start : 0 } });
5674 renderHeader : function()
5683 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5685 var config = cm.config[i];
5690 html: cm.getColumnHeader(i)
5693 if(typeof(config.tooltip) != 'undefined'){
5694 c.tooltip = config.tooltip;
5697 if(typeof(config.colspan) != 'undefined'){
5698 c.colspan = config.colspan;
5701 if(typeof(config.hidden) != 'undefined' && config.hidden){
5702 c.style += ' display:none;';
5705 if(typeof(config.dataIndex) != 'undefined'){
5706 c.sort = config.dataIndex;
5709 if(typeof(config.sortable) != 'undefined' && config.sortable){
5713 if(typeof(config.align) != 'undefined' && config.align.length){
5714 c.style += ' text-align:' + config.align + ';';
5717 if(typeof(config.width) != 'undefined'){
5718 c.style += ' width:' + config.width + 'px;';
5721 if(typeof(config.cls) != 'undefined'){
5722 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5731 renderBody : function()
5741 colspan : this.cm.getColumnCount()
5751 renderFooter : function()
5761 colspan : this.cm.getColumnCount()
5775 Roo.log('ds onload');
5780 var ds = this.store;
5782 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5783 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5785 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5786 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5789 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5790 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5794 var tbody = this.mainBody;
5796 if(ds.getCount() > 0){
5797 ds.data.each(function(d,rowIndex){
5798 var row = this.renderRow(cm, ds, rowIndex);
5800 tbody.createChild(row);
5804 if(row.cellObjects.length){
5805 Roo.each(row.cellObjects, function(r){
5806 _this.renderCellObject(r);
5813 Roo.each(this.el.select('tbody td', true).elements, function(e){
5814 e.on('mouseover', _this.onMouseover, _this);
5817 Roo.each(this.el.select('tbody td', true).elements, function(e){
5818 e.on('mouseout', _this.onMouseout, _this);
5820 this.fireEvent('rowsrendered', this);
5821 //if(this.loadMask){
5822 // this.maskEl.hide();
5827 onUpdate : function(ds,record)
5829 this.refreshRow(record);
5832 onRemove : function(ds, record, index, isUpdate){
5833 if(isUpdate !== true){
5834 this.fireEvent("beforerowremoved", this, index, record);
5836 var bt = this.mainBody.dom;
5838 var rows = this.el.select('tbody > tr', true).elements;
5840 if(typeof(rows[index]) != 'undefined'){
5841 bt.removeChild(rows[index].dom);
5844 // if(bt.rows[index]){
5845 // bt.removeChild(bt.rows[index]);
5848 if(isUpdate !== true){
5849 //this.stripeRows(index);
5850 //this.syncRowHeights(index, index);
5852 this.fireEvent("rowremoved", this, index, record);
5856 onAdd : function(ds, records, rowIndex)
5858 //Roo.log('on Add called');
5859 // - note this does not handle multiple adding very well..
5860 var bt = this.mainBody.dom;
5861 for (var i =0 ; i < records.length;i++) {
5862 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5863 //Roo.log(records[i]);
5864 //Roo.log(this.store.getAt(rowIndex+i));
5865 this.insertRow(this.store, rowIndex + i, false);
5872 refreshRow : function(record){
5873 var ds = this.store, index;
5874 if(typeof record == 'number'){
5876 record = ds.getAt(index);
5878 index = ds.indexOf(record);
5880 this.insertRow(ds, index, true);
5881 this.onRemove(ds, record, index+1, true);
5882 //this.syncRowHeights(index, index);
5884 this.fireEvent("rowupdated", this, index, record);
5887 insertRow : function(dm, rowIndex, isUpdate){
5890 this.fireEvent("beforerowsinserted", this, rowIndex);
5892 //var s = this.getScrollState();
5893 var row = this.renderRow(this.cm, this.store, rowIndex);
5894 // insert before rowIndex..
5895 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5899 if(row.cellObjects.length){
5900 Roo.each(row.cellObjects, function(r){
5901 _this.renderCellObject(r);
5906 this.fireEvent("rowsinserted", this, rowIndex);
5907 //this.syncRowHeights(firstRow, lastRow);
5908 //this.stripeRows(firstRow);
5915 getRowDom : function(rowIndex)
5917 var rows = this.el.select('tbody > tr', true).elements;
5919 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5922 // returns the object tree for a tr..
5925 renderRow : function(cm, ds, rowIndex)
5928 var d = ds.getAt(rowIndex);
5935 var cellObjects = [];
5937 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5938 var config = cm.config[i];
5940 var renderer = cm.getRenderer(i);
5944 if(typeof(renderer) !== 'undefined'){
5945 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5947 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5948 // and are rendered into the cells after the row is rendered - using the id for the element.
5950 if(typeof(value) === 'object'){
5960 rowIndex : rowIndex,
5965 this.fireEvent('rowclass', this, rowcfg);
5969 cls : rowcfg.rowClass,
5971 html: (typeof(value) === 'object') ? '' : value
5978 if(typeof(config.colspan) != 'undefined'){
5979 td.colspan = config.colspan;
5982 if(typeof(config.hidden) != 'undefined' && config.hidden){
5983 td.style += ' display:none;';
5986 if(typeof(config.align) != 'undefined' && config.align.length){
5987 td.style += ' text-align:' + config.align + ';';
5990 if(typeof(config.width) != 'undefined'){
5991 td.style += ' width:' + config.width + 'px;';
5994 if(typeof(config.cursor) != 'undefined'){
5995 td.style += ' cursor:' + config.cursor + ';';
5998 if(typeof(config.cls) != 'undefined'){
5999 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6006 row.cellObjects = cellObjects;
6014 onBeforeLoad : function()
6016 //Roo.log('ds onBeforeLoad');
6020 //if(this.loadMask){
6021 // this.maskEl.show();
6029 this.el.select('tbody', true).first().dom.innerHTML = '';
6032 * Show or hide a row.
6033 * @param {Number} rowIndex to show or hide
6034 * @param {Boolean} state hide
6036 setRowVisibility : function(rowIndex, state)
6038 var bt = this.mainBody.dom;
6040 var rows = this.el.select('tbody > tr', true).elements;
6042 if(typeof(rows[rowIndex]) == 'undefined'){
6045 rows[rowIndex].dom.style.display = state ? '' : 'none';
6049 getSelectionModel : function(){
6051 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6053 return this.selModel;
6056 * Render the Roo.bootstrap object from renderder
6058 renderCellObject : function(r)
6062 var t = r.cfg.render(r.container);
6065 Roo.each(r.cfg.cn, function(c){
6067 container: t.getChildContainer(),
6070 _this.renderCellObject(child);
6075 getRowIndex : function(row)
6079 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6102 * @class Roo.bootstrap.TableCell
6103 * @extends Roo.bootstrap.Component
6104 * Bootstrap TableCell class
6105 * @cfg {String} html cell contain text
6106 * @cfg {String} cls cell class
6107 * @cfg {String} tag cell tag (td|th) default td
6108 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6109 * @cfg {String} align Aligns the content in a cell
6110 * @cfg {String} axis Categorizes cells
6111 * @cfg {String} bgcolor Specifies the background color of a cell
6112 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6113 * @cfg {Number} colspan Specifies the number of columns a cell should span
6114 * @cfg {String} headers Specifies one or more header cells a cell is related to
6115 * @cfg {Number} height Sets the height of a cell
6116 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6117 * @cfg {Number} rowspan Sets the number of rows a cell should span
6118 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6119 * @cfg {String} valign Vertical aligns the content in a cell
6120 * @cfg {Number} width Specifies the width of a cell
6123 * Create a new TableCell
6124 * @param {Object} config The config object
6127 Roo.bootstrap.TableCell = function(config){
6128 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6131 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6151 getAutoCreate : function(){
6152 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6172 cfg.align=this.align
6178 cfg.bgcolor=this.bgcolor
6181 cfg.charoff=this.charoff
6184 cfg.colspan=this.colspan
6187 cfg.headers=this.headers
6190 cfg.height=this.height
6193 cfg.nowrap=this.nowrap
6196 cfg.rowspan=this.rowspan
6199 cfg.scope=this.scope
6202 cfg.valign=this.valign
6205 cfg.width=this.width
6224 * @class Roo.bootstrap.TableRow
6225 * @extends Roo.bootstrap.Component
6226 * Bootstrap TableRow class
6227 * @cfg {String} cls row class
6228 * @cfg {String} align Aligns the content in a table row
6229 * @cfg {String} bgcolor Specifies a background color for a table row
6230 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6231 * @cfg {String} valign Vertical aligns the content in a table row
6234 * Create a new TableRow
6235 * @param {Object} config The config object
6238 Roo.bootstrap.TableRow = function(config){
6239 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6242 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6250 getAutoCreate : function(){
6251 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6261 cfg.align = this.align;
6264 cfg.bgcolor = this.bgcolor;
6267 cfg.charoff = this.charoff;
6270 cfg.valign = this.valign;
6288 * @class Roo.bootstrap.TableBody
6289 * @extends Roo.bootstrap.Component
6290 * Bootstrap TableBody class
6291 * @cfg {String} cls element class
6292 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6293 * @cfg {String} align Aligns the content inside the element
6294 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6295 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6298 * Create a new TableBody
6299 * @param {Object} config The config object
6302 Roo.bootstrap.TableBody = function(config){
6303 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6306 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6314 getAutoCreate : function(){
6315 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6329 cfg.align = this.align;
6332 cfg.charoff = this.charoff;
6335 cfg.valign = this.valign;
6342 // initEvents : function()
6349 // this.store = Roo.factory(this.store, Roo.data);
6350 // this.store.on('load', this.onLoad, this);
6352 // this.store.load();
6356 // onLoad: function ()
6358 // this.fireEvent('load', this);
6368 * Ext JS Library 1.1.1
6369 * Copyright(c) 2006-2007, Ext JS, LLC.
6371 * Originally Released Under LGPL - original licence link has changed is not relivant.
6374 * <script type="text/javascript">
6377 // as we use this in bootstrap.
6378 Roo.namespace('Roo.form');
6380 * @class Roo.form.Action
6381 * Internal Class used to handle form actions
6383 * @param {Roo.form.BasicForm} el The form element or its id
6384 * @param {Object} config Configuration options
6389 // define the action interface
6390 Roo.form.Action = function(form, options){
6392 this.options = options || {};
6395 * Client Validation Failed
6398 Roo.form.Action.CLIENT_INVALID = 'client';
6400 * Server Validation Failed
6403 Roo.form.Action.SERVER_INVALID = 'server';
6405 * Connect to Server Failed
6408 Roo.form.Action.CONNECT_FAILURE = 'connect';
6410 * Reading Data from Server Failed
6413 Roo.form.Action.LOAD_FAILURE = 'load';
6415 Roo.form.Action.prototype = {
6417 failureType : undefined,
6418 response : undefined,
6422 run : function(options){
6427 success : function(response){
6432 handleResponse : function(response){
6436 // default connection failure
6437 failure : function(response){
6439 this.response = response;
6440 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6441 this.form.afterAction(this, false);
6444 processResponse : function(response){
6445 this.response = response;
6446 if(!response.responseText){
6449 this.result = this.handleResponse(response);
6453 // utility functions used internally
6454 getUrl : function(appendParams){
6455 var url = this.options.url || this.form.url || this.form.el.dom.action;
6457 var p = this.getParams();
6459 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6465 getMethod : function(){
6466 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6469 getParams : function(){
6470 var bp = this.form.baseParams;
6471 var p = this.options.params;
6473 if(typeof p == "object"){
6474 p = Roo.urlEncode(Roo.applyIf(p, bp));
6475 }else if(typeof p == 'string' && bp){
6476 p += '&' + Roo.urlEncode(bp);
6479 p = Roo.urlEncode(bp);
6484 createCallback : function(){
6486 success: this.success,
6487 failure: this.failure,
6489 timeout: (this.form.timeout*1000),
6490 upload: this.form.fileUpload ? this.success : undefined
6495 Roo.form.Action.Submit = function(form, options){
6496 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6499 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6502 haveProgress : false,
6503 uploadComplete : false,
6505 // uploadProgress indicator.
6506 uploadProgress : function()
6508 if (!this.form.progressUrl) {
6512 if (!this.haveProgress) {
6513 Roo.MessageBox.progress("Uploading", "Uploading");
6515 if (this.uploadComplete) {
6516 Roo.MessageBox.hide();
6520 this.haveProgress = true;
6522 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6524 var c = new Roo.data.Connection();
6526 url : this.form.progressUrl,
6531 success : function(req){
6532 //console.log(data);
6536 rdata = Roo.decode(req.responseText)
6538 Roo.log("Invalid data from server..");
6542 if (!rdata || !rdata.success) {
6544 Roo.MessageBox.alert(Roo.encode(rdata));
6547 var data = rdata.data;
6549 if (this.uploadComplete) {
6550 Roo.MessageBox.hide();
6555 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6556 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6559 this.uploadProgress.defer(2000,this);
6562 failure: function(data) {
6563 Roo.log('progress url failed ');
6574 // run get Values on the form, so it syncs any secondary forms.
6575 this.form.getValues();
6577 var o = this.options;
6578 var method = this.getMethod();
6579 var isPost = method == 'POST';
6580 if(o.clientValidation === false || this.form.isValid()){
6582 if (this.form.progressUrl) {
6583 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6584 (new Date() * 1) + '' + Math.random());
6589 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6590 form:this.form.el.dom,
6591 url:this.getUrl(!isPost),
6593 params:isPost ? this.getParams() : null,
6594 isUpload: this.form.fileUpload
6597 this.uploadProgress();
6599 }else if (o.clientValidation !== false){ // client validation failed
6600 this.failureType = Roo.form.Action.CLIENT_INVALID;
6601 this.form.afterAction(this, false);
6605 success : function(response)
6607 this.uploadComplete= true;
6608 if (this.haveProgress) {
6609 Roo.MessageBox.hide();
6613 var result = this.processResponse(response);
6614 if(result === true || result.success){
6615 this.form.afterAction(this, true);
6619 this.form.markInvalid(result.errors);
6620 this.failureType = Roo.form.Action.SERVER_INVALID;
6622 this.form.afterAction(this, false);
6624 failure : function(response)
6626 this.uploadComplete= true;
6627 if (this.haveProgress) {
6628 Roo.MessageBox.hide();
6631 this.response = response;
6632 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6633 this.form.afterAction(this, false);
6636 handleResponse : function(response){
6637 if(this.form.errorReader){
6638 var rs = this.form.errorReader.read(response);
6641 for(var i = 0, len = rs.records.length; i < len; i++) {
6642 var r = rs.records[i];
6646 if(errors.length < 1){
6650 success : rs.success,
6656 ret = Roo.decode(response.responseText);
6660 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6670 Roo.form.Action.Load = function(form, options){
6671 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6672 this.reader = this.form.reader;
6675 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6680 Roo.Ajax.request(Roo.apply(
6681 this.createCallback(), {
6682 method:this.getMethod(),
6683 url:this.getUrl(false),
6684 params:this.getParams()
6688 success : function(response){
6690 var result = this.processResponse(response);
6691 if(result === true || !result.success || !result.data){
6692 this.failureType = Roo.form.Action.LOAD_FAILURE;
6693 this.form.afterAction(this, false);
6696 this.form.clearInvalid();
6697 this.form.setValues(result.data);
6698 this.form.afterAction(this, true);
6701 handleResponse : function(response){
6702 if(this.form.reader){
6703 var rs = this.form.reader.read(response);
6704 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6706 success : rs.success,
6710 return Roo.decode(response.responseText);
6714 Roo.form.Action.ACTION_TYPES = {
6715 'load' : Roo.form.Action.Load,
6716 'submit' : Roo.form.Action.Submit
6725 * @class Roo.bootstrap.Form
6726 * @extends Roo.bootstrap.Component
6727 * Bootstrap Form class
6728 * @cfg {String} method GET | POST (default POST)
6729 * @cfg {String} labelAlign top | left (default top)
6730 * @cfg {String} align left | right - for navbars
6731 * @cfg {Boolean} loadMask load mask when submit (default true)
6736 * @param {Object} config The config object
6740 Roo.bootstrap.Form = function(config){
6741 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6744 * @event clientvalidation
6745 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6746 * @param {Form} this
6747 * @param {Boolean} valid true if the form has passed client-side validation
6749 clientvalidation: true,
6751 * @event beforeaction
6752 * Fires before any action is performed. Return false to cancel the action.
6753 * @param {Form} this
6754 * @param {Action} action The action to be performed
6758 * @event actionfailed
6759 * Fires when an action fails.
6760 * @param {Form} this
6761 * @param {Action} action The action that failed
6763 actionfailed : true,
6765 * @event actioncomplete
6766 * Fires when an action is completed.
6767 * @param {Form} this
6768 * @param {Action} action The action that completed
6770 actioncomplete : true
6775 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6778 * @cfg {String} method
6779 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6784 * The URL to use for form actions if one isn't supplied in the action options.
6787 * @cfg {Boolean} fileUpload
6788 * Set to true if this form is a file upload.
6792 * @cfg {Object} baseParams
6793 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6797 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6801 * @cfg {Sting} align (left|right) for navbar forms
6806 activeAction : null,
6809 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6810 * element by passing it or its id or mask the form itself by passing in true.
6813 waitMsgTarget : false,
6817 getAutoCreate : function(){
6821 method : this.method || 'POST',
6822 id : this.id || Roo.id(),
6825 if (this.parent().xtype.match(/^Nav/)) {
6826 cfg.cls = 'navbar-form navbar-' + this.align;
6830 if (this.labelAlign == 'left' ) {
6831 cfg.cls += ' form-horizontal';
6837 initEvents : function()
6839 this.el.on('submit', this.onSubmit, this);
6840 // this was added as random key presses on the form where triggering form submit.
6841 this.el.on('keypress', function(e) {
6842 if (e.getCharCode() != 13) {
6845 // we might need to allow it for textareas.. and some other items.
6846 // check e.getTarget().
6848 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6852 Roo.log("keypress blocked");
6860 onSubmit : function(e){
6865 * Returns true if client-side validation on the form is successful.
6868 isValid : function(){
6869 var items = this.getItems();
6871 items.each(function(f){
6880 * Returns true if any fields in this form have changed since their original load.
6883 isDirty : function(){
6885 var items = this.getItems();
6886 items.each(function(f){
6896 * Performs a predefined action (submit or load) or custom actions you define on this form.
6897 * @param {String} actionName The name of the action type
6898 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6899 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6900 * accept other config options):
6902 Property Type Description
6903 ---------------- --------------- ----------------------------------------------------------------------------------
6904 url String The url for the action (defaults to the form's url)
6905 method String The form method to use (defaults to the form's method, or POST if not defined)
6906 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6907 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6908 validate the form on the client (defaults to false)
6910 * @return {BasicForm} this
6912 doAction : function(action, options){
6913 if(typeof action == 'string'){
6914 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6916 if(this.fireEvent('beforeaction', this, action) !== false){
6917 this.beforeAction(action);
6918 action.run.defer(100, action);
6924 beforeAction : function(action){
6925 var o = action.options;
6928 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6930 // not really supported yet.. ??
6932 //if(this.waitMsgTarget === true){
6933 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6934 //}else if(this.waitMsgTarget){
6935 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6936 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6938 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6944 afterAction : function(action, success){
6945 this.activeAction = null;
6946 var o = action.options;
6948 //if(this.waitMsgTarget === true){
6950 //}else if(this.waitMsgTarget){
6951 // this.waitMsgTarget.unmask();
6953 // Roo.MessageBox.updateProgress(1);
6954 // Roo.MessageBox.hide();
6961 Roo.callback(o.success, o.scope, [this, action]);
6962 this.fireEvent('actioncomplete', this, action);
6966 // failure condition..
6967 // we have a scenario where updates need confirming.
6968 // eg. if a locking scenario exists..
6969 // we look for { errors : { needs_confirm : true }} in the response.
6971 (typeof(action.result) != 'undefined') &&
6972 (typeof(action.result.errors) != 'undefined') &&
6973 (typeof(action.result.errors.needs_confirm) != 'undefined')
6976 Roo.log("not supported yet");
6979 Roo.MessageBox.confirm(
6980 "Change requires confirmation",
6981 action.result.errorMsg,
6986 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
6996 Roo.callback(o.failure, o.scope, [this, action]);
6997 // show an error message if no failed handler is set..
6998 if (!this.hasListener('actionfailed')) {
6999 Roo.log("need to add dialog support");
7001 Roo.MessageBox.alert("Error",
7002 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7003 action.result.errorMsg :
7004 "Saving Failed, please check your entries or try again"
7009 this.fireEvent('actionfailed', this, action);
7014 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7015 * @param {String} id The value to search for
7018 findField : function(id){
7019 var items = this.getItems();
7020 var field = items.get(id);
7022 items.each(function(f){
7023 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7030 return field || null;
7033 * Mark fields in this form invalid in bulk.
7034 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7035 * @return {BasicForm} this
7037 markInvalid : function(errors){
7038 if(errors instanceof Array){
7039 for(var i = 0, len = errors.length; i < len; i++){
7040 var fieldError = errors[i];
7041 var f = this.findField(fieldError.id);
7043 f.markInvalid(fieldError.msg);
7049 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7050 field.markInvalid(errors[id]);
7054 //Roo.each(this.childForms || [], function (f) {
7055 // f.markInvalid(errors);
7062 * Set values for fields in this form in bulk.
7063 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7064 * @return {BasicForm} this
7066 setValues : function(values){
7067 if(values instanceof Array){ // array of objects
7068 for(var i = 0, len = values.length; i < len; i++){
7070 var f = this.findField(v.id);
7072 f.setValue(v.value);
7073 if(this.trackResetOnLoad){
7074 f.originalValue = f.getValue();
7078 }else{ // object hash
7081 if(typeof values[id] != 'function' && (field = this.findField(id))){
7083 if (field.setFromData &&
7085 field.displayField &&
7086 // combos' with local stores can
7087 // be queried via setValue()
7088 // to set their value..
7089 (field.store && !field.store.isLocal)
7093 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7094 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7095 field.setFromData(sd);
7098 field.setValue(values[id]);
7102 if(this.trackResetOnLoad){
7103 field.originalValue = field.getValue();
7109 //Roo.each(this.childForms || [], function (f) {
7110 // f.setValues(values);
7117 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7118 * they are returned as an array.
7119 * @param {Boolean} asString
7122 getValues : function(asString){
7123 //if (this.childForms) {
7124 // copy values from the child forms
7125 // Roo.each(this.childForms, function (f) {
7126 // this.setValues(f.getValues());
7132 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7133 if(asString === true){
7136 return Roo.urlDecode(fs);
7140 * Returns the fields in this form as an object with key/value pairs.
7141 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7144 getFieldValues : function(with_hidden)
7146 var items = this.getItems();
7148 items.each(function(f){
7152 var v = f.getValue();
7153 if (f.inputType =='radio') {
7154 if (typeof(ret[f.getName()]) == 'undefined') {
7155 ret[f.getName()] = ''; // empty..
7158 if (!f.el.dom.checked) {
7166 // not sure if this supported any more..
7167 if ((typeof(v) == 'object') && f.getRawValue) {
7168 v = f.getRawValue() ; // dates..
7170 // combo boxes where name != hiddenName...
7171 if (f.name != f.getName()) {
7172 ret[f.name] = f.getRawValue();
7174 ret[f.getName()] = v;
7181 * Clears all invalid messages in this form.
7182 * @return {BasicForm} this
7184 clearInvalid : function(){
7185 var items = this.getItems();
7187 items.each(function(f){
7198 * @return {BasicForm} this
7201 var items = this.getItems();
7202 items.each(function(f){
7206 Roo.each(this.childForms || [], function (f) {
7213 getItems : function()
7215 var r=new Roo.util.MixedCollection(false, function(o){
7216 return o.id || (o.id = Roo.id());
7218 var iter = function(el) {
7225 Roo.each(el.items,function(e) {
7245 * Ext JS Library 1.1.1
7246 * Copyright(c) 2006-2007, Ext JS, LLC.
7248 * Originally Released Under LGPL - original licence link has changed is not relivant.
7251 * <script type="text/javascript">
7254 * @class Roo.form.VTypes
7255 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7258 Roo.form.VTypes = function(){
7259 // closure these in so they are only created once.
7260 var alpha = /^[a-zA-Z_]+$/;
7261 var alphanum = /^[a-zA-Z0-9_]+$/;
7262 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7263 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7265 // All these messages and functions are configurable
7268 * The function used to validate email addresses
7269 * @param {String} value The email address
7271 'email' : function(v){
7272 return email.test(v);
7275 * The error text to display when the email validation function returns false
7278 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7280 * The keystroke filter mask to be applied on email input
7283 'emailMask' : /[a-z0-9_\.\-@]/i,
7286 * The function used to validate URLs
7287 * @param {String} value The URL
7289 'url' : function(v){
7293 * The error text to display when the url validation function returns false
7296 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7299 * The function used to validate alpha values
7300 * @param {String} value The value
7302 'alpha' : function(v){
7303 return alpha.test(v);
7306 * The error text to display when the alpha validation function returns false
7309 'alphaText' : 'This field should only contain letters and _',
7311 * The keystroke filter mask to be applied on alpha input
7314 'alphaMask' : /[a-z_]/i,
7317 * The function used to validate alphanumeric values
7318 * @param {String} value The value
7320 'alphanum' : function(v){
7321 return alphanum.test(v);
7324 * The error text to display when the alphanumeric validation function returns false
7327 'alphanumText' : 'This field should only contain letters, numbers and _',
7329 * The keystroke filter mask to be applied on alphanumeric input
7332 'alphanumMask' : /[a-z0-9_]/i
7342 * @class Roo.bootstrap.Input
7343 * @extends Roo.bootstrap.Component
7344 * Bootstrap Input class
7345 * @cfg {Boolean} disabled is it disabled
7346 * @cfg {String} fieldLabel - the label associated
7347 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7348 * @cfg {String} name name of the input
7349 * @cfg {string} fieldLabel - the label associated
7350 * @cfg {string} inputType - input / file submit ...
7351 * @cfg {string} placeholder - placeholder to put in text.
7352 * @cfg {string} before - input group add on before
7353 * @cfg {string} after - input group add on after
7354 * @cfg {string} size - (lg|sm) or leave empty..
7355 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7356 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7357 * @cfg {Number} md colspan out of 12 for computer-sized screens
7358 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7359 * @cfg {string} value default value of the input
7360 * @cfg {Number} labelWidth set the width of label (0-12)
7361 * @cfg {String} labelAlign (top|left)
7362 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7363 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7365 * @cfg {String} align (left|center|right) Default left
7370 * Create a new Input
7371 * @param {Object} config The config object
7374 Roo.bootstrap.Input = function(config){
7375 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7380 * Fires when this field receives input focus.
7381 * @param {Roo.form.Field} this
7386 * Fires when this field loses input focus.
7387 * @param {Roo.form.Field} this
7392 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7393 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7394 * @param {Roo.form.Field} this
7395 * @param {Roo.EventObject} e The event object
7400 * Fires just before the field blurs if the field value has changed.
7401 * @param {Roo.form.Field} this
7402 * @param {Mixed} newValue The new value
7403 * @param {Mixed} oldValue The original value
7408 * Fires after the field has been marked as invalid.
7409 * @param {Roo.form.Field} this
7410 * @param {String} msg The validation message
7415 * Fires after the field has been validated with no errors.
7416 * @param {Roo.form.Field} this
7421 * Fires after the key up
7422 * @param {Roo.form.Field} this
7423 * @param {Roo.EventObject} e The event Object
7429 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7431 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7432 automatic validation (defaults to "keyup").
7434 validationEvent : "keyup",
7436 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7438 validateOnBlur : true,
7440 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7442 validationDelay : 250,
7444 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7446 focusClass : "x-form-focus", // not needed???
7450 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7452 invalidClass : "has-warning",
7455 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7457 validClass : "has-success",
7460 * @cfg {Boolean} hasFeedback (true|false) default true
7465 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7467 invalidFeedbackClass : "glyphicon-warning-sign",
7470 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7472 validFeedbackClass : "glyphicon-ok",
7475 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7477 selectOnFocus : false,
7480 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7484 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7489 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7491 disableKeyFilter : false,
7494 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7498 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7502 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7504 blankText : "This field is required",
7507 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7511 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7513 maxLength : Number.MAX_VALUE,
7515 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7517 minLengthText : "The minimum length for this field is {0}",
7519 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7521 maxLengthText : "The maximum length for this field is {0}",
7525 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7526 * If available, this function will be called only after the basic validators all return true, and will be passed the
7527 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7531 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7532 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7533 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7537 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7541 autocomplete: false,
7560 formatedValue : false,
7562 parentLabelAlign : function()
7565 while (parent.parent()) {
7566 parent = parent.parent();
7567 if (typeof(parent.labelAlign) !='undefined') {
7568 return parent.labelAlign;
7575 getAutoCreate : function(){
7577 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7583 if(this.inputType != 'hidden'){
7584 cfg.cls = 'form-group' //input-group
7590 type : this.inputType,
7592 cls : 'form-control',
7593 placeholder : this.placeholder || '',
7594 autocomplete : this.autocomplete || 'new-password'
7599 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7602 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7603 input.maxLength = this.maxLength;
7606 if (this.disabled) {
7607 input.disabled=true;
7610 if (this.readOnly) {
7611 input.readonly=true;
7615 input.name = this.name;
7618 input.cls += ' input-' + this.size;
7621 ['xs','sm','md','lg'].map(function(size){
7622 if (settings[size]) {
7623 cfg.cls += ' col-' + size + '-' + settings[size];
7627 var inputblock = input;
7631 cls: 'glyphicon form-control-feedback'
7634 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7637 cls : 'has-feedback',
7645 if (this.before || this.after) {
7648 cls : 'input-group',
7652 if (this.before && typeof(this.before) == 'string') {
7654 inputblock.cn.push({
7656 cls : 'roo-input-before input-group-addon',
7660 if (this.before && typeof(this.before) == 'object') {
7661 this.before = Roo.factory(this.before);
7662 Roo.log(this.before);
7663 inputblock.cn.push({
7665 cls : 'roo-input-before input-group-' +
7666 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7670 inputblock.cn.push(input);
7672 if (this.after && typeof(this.after) == 'string') {
7673 inputblock.cn.push({
7675 cls : 'roo-input-after input-group-addon',
7679 if (this.after && typeof(this.after) == 'object') {
7680 this.after = Roo.factory(this.after);
7681 Roo.log(this.after);
7682 inputblock.cn.push({
7684 cls : 'roo-input-after input-group-' +
7685 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7689 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7690 inputblock.cls += ' has-feedback';
7691 inputblock.cn.push(feedback);
7695 if (align ==='left' && this.fieldLabel.length) {
7696 Roo.log("left and has label");
7702 cls : 'control-label col-sm-' + this.labelWidth,
7703 html : this.fieldLabel
7707 cls : "col-sm-" + (12 - this.labelWidth),
7714 } else if ( this.fieldLabel.length) {
7720 //cls : 'input-group-addon',
7721 html : this.fieldLabel
7731 Roo.log(" no label && no align");
7740 Roo.log('input-parentType: ' + this.parentType);
7742 if (this.parentType === 'Navbar' && this.parent().bar) {
7743 cfg.cls += ' navbar-form';
7751 * return the real input element.
7753 inputEl: function ()
7755 return this.el.select('input.form-control',true).first();
7758 tooltipEl : function()
7760 return this.inputEl();
7763 setDisabled : function(v)
7765 var i = this.inputEl().dom;
7767 i.removeAttribute('disabled');
7771 i.setAttribute('disabled','true');
7773 initEvents : function()
7776 this.inputEl().on("keydown" , this.fireKey, this);
7777 this.inputEl().on("focus", this.onFocus, this);
7778 this.inputEl().on("blur", this.onBlur, this);
7780 this.inputEl().relayEvent('keyup', this);
7782 // reference to original value for reset
7783 this.originalValue = this.getValue();
7784 //Roo.form.TextField.superclass.initEvents.call(this);
7785 if(this.validationEvent == 'keyup'){
7786 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7787 this.inputEl().on('keyup', this.filterValidation, this);
7789 else if(this.validationEvent !== false){
7790 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7793 if(this.selectOnFocus){
7794 this.on("focus", this.preFocus, this);
7797 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7798 this.inputEl().on("keypress", this.filterKeys, this);
7801 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7802 this.el.on("click", this.autoSize, this);
7805 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7806 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7809 if (typeof(this.before) == 'object') {
7810 this.before.render(this.el.select('.roo-input-before',true).first());
7812 if (typeof(this.after) == 'object') {
7813 this.after.render(this.el.select('.roo-input-after',true).first());
7818 filterValidation : function(e){
7819 if(!e.isNavKeyPress()){
7820 this.validationTask.delay(this.validationDelay);
7824 * Validates the field value
7825 * @return {Boolean} True if the value is valid, else false
7827 validate : function(){
7828 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7829 if(this.disabled || this.validateValue(this.getRawValue())){
7840 * Validates a value according to the field's validation rules and marks the field as invalid
7841 * if the validation fails
7842 * @param {Mixed} value The value to validate
7843 * @return {Boolean} True if the value is valid, else false
7845 validateValue : function(value){
7846 if(value.length < 1) { // if it's blank
7847 if(this.allowBlank){
7853 if(value.length < this.minLength){
7856 if(value.length > this.maxLength){
7860 var vt = Roo.form.VTypes;
7861 if(!vt[this.vtype](value, this)){
7865 if(typeof this.validator == "function"){
7866 var msg = this.validator(value);
7872 if(this.regex && !this.regex.test(value)){
7882 fireKey : function(e){
7883 //Roo.log('field ' + e.getKey());
7884 if(e.isNavKeyPress()){
7885 this.fireEvent("specialkey", this, e);
7888 focus : function (selectText){
7890 this.inputEl().focus();
7891 if(selectText === true){
7892 this.inputEl().dom.select();
7898 onFocus : function(){
7899 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7900 // this.el.addClass(this.focusClass);
7903 this.hasFocus = true;
7904 this.startValue = this.getValue();
7905 this.fireEvent("focus", this);
7909 beforeBlur : Roo.emptyFn,
7913 onBlur : function(){
7915 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7916 //this.el.removeClass(this.focusClass);
7918 this.hasFocus = false;
7919 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7922 var v = this.getValue();
7923 if(String(v) !== String(this.startValue)){
7924 this.fireEvent('change', this, v, this.startValue);
7926 this.fireEvent("blur", this);
7930 * Resets the current field value to the originally loaded value and clears any validation messages
7933 this.setValue(this.originalValue);
7937 * Returns the name of the field
7938 * @return {Mixed} name The name field
7940 getName: function(){
7944 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7945 * @return {Mixed} value The field value
7947 getValue : function(){
7949 var v = this.inputEl().getValue();
7954 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7955 * @return {Mixed} value The field value
7957 getRawValue : function(){
7958 var v = this.inputEl().getValue();
7964 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7965 * @param {Mixed} value The value to set
7967 setRawValue : function(v){
7968 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7971 selectText : function(start, end){
7972 var v = this.getRawValue();
7974 start = start === undefined ? 0 : start;
7975 end = end === undefined ? v.length : end;
7976 var d = this.inputEl().dom;
7977 if(d.setSelectionRange){
7978 d.setSelectionRange(start, end);
7979 }else if(d.createTextRange){
7980 var range = d.createTextRange();
7981 range.moveStart("character", start);
7982 range.moveEnd("character", v.length-end);
7989 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
7990 * @param {Mixed} value The value to set
7992 setValue : function(v){
7995 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8001 processValue : function(value){
8002 if(this.stripCharsRe){
8003 var newValue = value.replace(this.stripCharsRe, '');
8004 if(newValue !== value){
8005 this.setRawValue(newValue);
8012 preFocus : function(){
8014 if(this.selectOnFocus){
8015 this.inputEl().dom.select();
8018 filterKeys : function(e){
8020 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8023 var c = e.getCharCode(), cc = String.fromCharCode(c);
8024 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8027 if(!this.maskRe.test(cc)){
8032 * Clear any invalid styles/messages for this field
8034 clearInvalid : function(){
8036 if(!this.el || this.preventMark){ // not rendered
8039 this.el.removeClass(this.invalidClass);
8041 this.fireEvent('valid', this);
8045 * Mark this field as valid
8047 markValid : function(){
8048 if(!this.el || this.preventMark){ // not rendered
8052 this.el.removeClass([this.invalidClass, this.validClass]);
8054 if(this.disabled || this.allowBlank){
8058 this.el.addClass(this.validClass);
8060 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8062 var feedback = this.el.select('.form-control-feedback', true).first();
8065 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8066 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8071 this.fireEvent('valid', this);
8075 * Mark this field as invalid
8076 * @param {String} msg The validation message
8078 markInvalid : function(msg){
8079 if(!this.el || this.preventMark){ // not rendered
8083 this.el.removeClass([this.invalidClass, this.validClass]);
8085 if(this.disabled || this.allowBlank){
8089 this.el.addClass(this.invalidClass);
8091 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8093 var feedback = this.el.select('.form-control-feedback', true).first();
8096 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8098 if(this.getValue().length){
8099 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8106 this.fireEvent('invalid', this, msg);
8109 SafariOnKeyDown : function(event)
8111 // this is a workaround for a password hang bug on chrome/ webkit.
8113 var isSelectAll = false;
8115 if(this.inputEl().dom.selectionEnd > 0){
8116 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8118 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8119 event.preventDefault();
8124 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8126 event.preventDefault();
8127 // this is very hacky as keydown always get's upper case.
8129 var cc = String.fromCharCode(event.getCharCode());
8130 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8134 adjustWidth : function(tag, w){
8135 tag = tag.toLowerCase();
8136 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8137 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8141 if(tag == 'textarea'){
8144 }else if(Roo.isOpera){
8148 if(tag == 'textarea'){
8167 * @class Roo.bootstrap.TextArea
8168 * @extends Roo.bootstrap.Input
8169 * Bootstrap TextArea class
8170 * @cfg {Number} cols Specifies the visible width of a text area
8171 * @cfg {Number} rows Specifies the visible number of lines in a text area
8172 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8173 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8174 * @cfg {string} html text
8177 * Create a new TextArea
8178 * @param {Object} config The config object
8181 Roo.bootstrap.TextArea = function(config){
8182 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8186 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8196 getAutoCreate : function(){
8198 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8209 value : this.value || '',
8210 html: this.html || '',
8211 cls : 'form-control',
8212 placeholder : this.placeholder || ''
8216 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8217 input.maxLength = this.maxLength;
8221 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8225 input.cols = this.cols;
8228 if (this.readOnly) {
8229 input.readonly = true;
8233 input.name = this.name;
8237 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8241 ['xs','sm','md','lg'].map(function(size){
8242 if (settings[size]) {
8243 cfg.cls += ' col-' + size + '-' + settings[size];
8247 var inputblock = input;
8249 if(this.hasFeedback && !this.allowBlank){
8253 cls: 'glyphicon form-control-feedback'
8257 cls : 'has-feedback',
8266 if (this.before || this.after) {
8269 cls : 'input-group',
8273 inputblock.cn.push({
8275 cls : 'input-group-addon',
8280 inputblock.cn.push(input);
8282 if(this.hasFeedback && !this.allowBlank){
8283 inputblock.cls += ' has-feedback';
8284 inputblock.cn.push(feedback);
8288 inputblock.cn.push({
8290 cls : 'input-group-addon',
8297 if (align ==='left' && this.fieldLabel.length) {
8298 Roo.log("left and has label");
8304 cls : 'control-label col-sm-' + this.labelWidth,
8305 html : this.fieldLabel
8309 cls : "col-sm-" + (12 - this.labelWidth),
8316 } else if ( this.fieldLabel.length) {
8322 //cls : 'input-group-addon',
8323 html : this.fieldLabel
8333 Roo.log(" no label && no align");
8343 if (this.disabled) {
8344 input.disabled=true;
8351 * return the real textarea element.
8353 inputEl: function ()
8355 return this.el.select('textarea.form-control',true).first();
8363 * trigger field - base class for combo..
8368 * @class Roo.bootstrap.TriggerField
8369 * @extends Roo.bootstrap.Input
8370 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8371 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8372 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8373 * for which you can provide a custom implementation. For example:
8375 var trigger = new Roo.bootstrap.TriggerField();
8376 trigger.onTriggerClick = myTriggerFn;
8377 trigger.applyTo('my-field');
8380 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8381 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8382 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8383 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8384 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8387 * Create a new TriggerField.
8388 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8389 * to the base TextField)
8391 Roo.bootstrap.TriggerField = function(config){
8392 this.mimicing = false;
8393 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8396 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8398 * @cfg {String} triggerClass A CSS class to apply to the trigger
8401 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8405 /** @cfg {Boolean} grow @hide */
8406 /** @cfg {Number} growMin @hide */
8407 /** @cfg {Number} growMax @hide */
8413 autoSize: Roo.emptyFn,
8420 actionMode : 'wrap',
8425 getAutoCreate : function(){
8427 var align = this.labelAlign || this.parentLabelAlign();
8432 cls: 'form-group' //input-group
8439 type : this.inputType,
8440 cls : 'form-control',
8441 autocomplete: 'new-password',
8442 placeholder : this.placeholder || ''
8446 input.name = this.name;
8449 input.cls += ' input-' + this.size;
8452 if (this.disabled) {
8453 input.disabled=true;
8456 var inputblock = input;
8458 if(this.hasFeedback && !this.allowBlank){
8462 cls: 'glyphicon form-control-feedback'
8466 cls : 'has-feedback',
8474 if (this.before || this.after) {
8477 cls : 'input-group',
8481 inputblock.cn.push({
8483 cls : 'input-group-addon',
8488 inputblock.cn.push(input);
8490 if(this.hasFeedback && !this.allowBlank){
8491 inputblock.cls += ' has-feedback';
8492 inputblock.cn.push(feedback);
8496 inputblock.cn.push({
8498 cls : 'input-group-addon',
8511 cls: 'form-hidden-field'
8519 Roo.log('multiple');
8527 cls: 'form-hidden-field'
8531 cls: 'select2-choices',
8535 cls: 'select2-search-field',
8548 cls: 'select2-container input-group',
8553 // cls: 'typeahead typeahead-long dropdown-menu',
8554 // style: 'display:none'
8559 if(!this.multiple && this.showToggleBtn){
8565 if (this.caret != false) {
8568 cls: 'fa fa-' + this.caret
8575 cls : 'input-group-addon btn dropdown-toggle',
8580 cls: 'combobox-clear',
8594 combobox.cls += ' select2-container-multi';
8597 if (align ==='left' && this.fieldLabel.length) {
8599 Roo.log("left and has label");
8605 cls : 'control-label col-sm-' + this.labelWidth,
8606 html : this.fieldLabel
8610 cls : "col-sm-" + (12 - this.labelWidth),
8617 } else if ( this.fieldLabel.length) {
8623 //cls : 'input-group-addon',
8624 html : this.fieldLabel
8634 Roo.log(" no label && no align");
8641 ['xs','sm','md','lg'].map(function(size){
8642 if (settings[size]) {
8643 cfg.cls += ' col-' + size + '-' + settings[size];
8654 onResize : function(w, h){
8655 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8656 // if(typeof w == 'number'){
8657 // var x = w - this.trigger.getWidth();
8658 // this.inputEl().setWidth(this.adjustWidth('input', x));
8659 // this.trigger.setStyle('left', x+'px');
8664 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8667 getResizeEl : function(){
8668 return this.inputEl();
8672 getPositionEl : function(){
8673 return this.inputEl();
8677 alignErrorIcon : function(){
8678 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8682 initEvents : function(){
8686 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8687 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8688 if(!this.multiple && this.showToggleBtn){
8689 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8690 if(this.hideTrigger){
8691 this.trigger.setDisplayed(false);
8693 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8697 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8700 //this.trigger.addClassOnOver('x-form-trigger-over');
8701 //this.trigger.addClassOnClick('x-form-trigger-click');
8704 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8708 createList : function()
8710 this.list = Roo.get(document.body).createChild({
8712 cls: 'typeahead typeahead-long dropdown-menu',
8713 style: 'display:none'
8716 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8721 initTrigger : function(){
8726 onDestroy : function(){
8728 this.trigger.removeAllListeners();
8729 // this.trigger.remove();
8732 // this.wrap.remove();
8734 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8738 onFocus : function(){
8739 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8742 this.wrap.addClass('x-trigger-wrap-focus');
8743 this.mimicing = true;
8744 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8745 if(this.monitorTab){
8746 this.el.on("keydown", this.checkTab, this);
8753 checkTab : function(e){
8754 if(e.getKey() == e.TAB){
8760 onBlur : function(){
8765 mimicBlur : function(e, t){
8767 if(!this.wrap.contains(t) && this.validateBlur()){
8774 triggerBlur : function(){
8775 this.mimicing = false;
8776 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8777 if(this.monitorTab){
8778 this.el.un("keydown", this.checkTab, this);
8780 //this.wrap.removeClass('x-trigger-wrap-focus');
8781 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8785 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8786 validateBlur : function(e, t){
8791 onDisable : function(){
8792 this.inputEl().dom.disabled = true;
8793 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8795 // this.wrap.addClass('x-item-disabled');
8800 onEnable : function(){
8801 this.inputEl().dom.disabled = false;
8802 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8804 // this.el.removeClass('x-item-disabled');
8809 onShow : function(){
8810 var ae = this.getActionEl();
8813 ae.dom.style.display = '';
8814 ae.dom.style.visibility = 'visible';
8820 onHide : function(){
8821 var ae = this.getActionEl();
8822 ae.dom.style.display = 'none';
8826 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8827 * by an implementing function.
8829 * @param {EventObject} e
8831 onTriggerClick : Roo.emptyFn
8835 * Ext JS Library 1.1.1
8836 * Copyright(c) 2006-2007, Ext JS, LLC.
8838 * Originally Released Under LGPL - original licence link has changed is not relivant.
8841 * <script type="text/javascript">
8846 * @class Roo.data.SortTypes
8848 * Defines the default sorting (casting?) comparison functions used when sorting data.
8850 Roo.data.SortTypes = {
8852 * Default sort that does nothing
8853 * @param {Mixed} s The value being converted
8854 * @return {Mixed} The comparison value
8861 * The regular expression used to strip tags
8865 stripTagsRE : /<\/?[^>]+>/gi,
8868 * Strips all HTML tags to sort on text only
8869 * @param {Mixed} s The value being converted
8870 * @return {String} The comparison value
8872 asText : function(s){
8873 return String(s).replace(this.stripTagsRE, "");
8877 * Strips all HTML tags to sort on text only - Case insensitive
8878 * @param {Mixed} s The value being converted
8879 * @return {String} The comparison value
8881 asUCText : function(s){
8882 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8886 * Case insensitive string
8887 * @param {Mixed} s The value being converted
8888 * @return {String} The comparison value
8890 asUCString : function(s) {
8891 return String(s).toUpperCase();
8896 * @param {Mixed} s The value being converted
8897 * @return {Number} The comparison value
8899 asDate : function(s) {
8903 if(s instanceof Date){
8906 return Date.parse(String(s));
8911 * @param {Mixed} s The value being converted
8912 * @return {Float} The comparison value
8914 asFloat : function(s) {
8915 var val = parseFloat(String(s).replace(/,/g, ""));
8916 if(isNaN(val)) val = 0;
8922 * @param {Mixed} s The value being converted
8923 * @return {Number} The comparison value
8925 asInt : function(s) {
8926 var val = parseInt(String(s).replace(/,/g, ""));
8927 if(isNaN(val)) val = 0;
8932 * Ext JS Library 1.1.1
8933 * Copyright(c) 2006-2007, Ext JS, LLC.
8935 * Originally Released Under LGPL - original licence link has changed is not relivant.
8938 * <script type="text/javascript">
8942 * @class Roo.data.Record
8943 * Instances of this class encapsulate both record <em>definition</em> information, and record
8944 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8945 * to access Records cached in an {@link Roo.data.Store} object.<br>
8947 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8948 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8951 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8953 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8954 * {@link #create}. The parameters are the same.
8955 * @param {Array} data An associative Array of data values keyed by the field name.
8956 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8957 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8958 * not specified an integer id is generated.
8960 Roo.data.Record = function(data, id){
8961 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8966 * Generate a constructor for a specific record layout.
8967 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8968 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8969 * Each field definition object may contain the following properties: <ul>
8970 * <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,
8971 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8972 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8973 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8974 * is being used, then this is a string containing the javascript expression to reference the data relative to
8975 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8976 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8977 * this may be omitted.</p></li>
8978 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8979 * <ul><li>auto (Default, implies no conversion)</li>
8984 * <li>date</li></ul></p></li>
8985 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
8986 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
8987 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
8988 * by the Reader into an object that will be stored in the Record. It is passed the
8989 * following parameters:<ul>
8990 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
8992 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
8994 * <br>usage:<br><pre><code>
8995 var TopicRecord = Roo.data.Record.create(
8996 {name: 'title', mapping: 'topic_title'},
8997 {name: 'author', mapping: 'username'},
8998 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
8999 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9000 {name: 'lastPoster', mapping: 'user2'},
9001 {name: 'excerpt', mapping: 'post_text'}
9004 var myNewRecord = new TopicRecord({
9005 title: 'Do my job please',
9008 lastPost: new Date(),
9009 lastPoster: 'Animal',
9010 excerpt: 'No way dude!'
9012 myStore.add(myNewRecord);
9017 Roo.data.Record.create = function(o){
9019 f.superclass.constructor.apply(this, arguments);
9021 Roo.extend(f, Roo.data.Record);
9022 var p = f.prototype;
9023 p.fields = new Roo.util.MixedCollection(false, function(field){
9026 for(var i = 0, len = o.length; i < len; i++){
9027 p.fields.add(new Roo.data.Field(o[i]));
9029 f.getField = function(name){
9030 return p.fields.get(name);
9035 Roo.data.Record.AUTO_ID = 1000;
9036 Roo.data.Record.EDIT = 'edit';
9037 Roo.data.Record.REJECT = 'reject';
9038 Roo.data.Record.COMMIT = 'commit';
9040 Roo.data.Record.prototype = {
9042 * Readonly flag - true if this record has been modified.
9051 join : function(store){
9056 * Set the named field to the specified value.
9057 * @param {String} name The name of the field to set.
9058 * @param {Object} value The value to set the field to.
9060 set : function(name, value){
9061 if(this.data[name] == value){
9068 if(typeof this.modified[name] == 'undefined'){
9069 this.modified[name] = this.data[name];
9071 this.data[name] = value;
9072 if(!this.editing && this.store){
9073 this.store.afterEdit(this);
9078 * Get the value of the named field.
9079 * @param {String} name The name of the field to get the value of.
9080 * @return {Object} The value of the field.
9082 get : function(name){
9083 return this.data[name];
9087 beginEdit : function(){
9088 this.editing = true;
9093 cancelEdit : function(){
9094 this.editing = false;
9095 delete this.modified;
9099 endEdit : function(){
9100 this.editing = false;
9101 if(this.dirty && this.store){
9102 this.store.afterEdit(this);
9107 * Usually called by the {@link Roo.data.Store} which owns the Record.
9108 * Rejects all changes made to the Record since either creation, or the last commit operation.
9109 * Modified fields are reverted to their original values.
9111 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9112 * of reject operations.
9114 reject : function(){
9115 var m = this.modified;
9117 if(typeof m[n] != "function"){
9118 this.data[n] = m[n];
9122 delete this.modified;
9123 this.editing = false;
9125 this.store.afterReject(this);
9130 * Usually called by the {@link Roo.data.Store} which owns the Record.
9131 * Commits all changes made to the Record since either creation, or the last commit operation.
9133 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9134 * of commit operations.
9136 commit : function(){
9138 delete this.modified;
9139 this.editing = false;
9141 this.store.afterCommit(this);
9146 hasError : function(){
9147 return this.error != null;
9151 clearError : function(){
9156 * Creates a copy of this record.
9157 * @param {String} id (optional) A new record id if you don't want to use this record's id
9160 copy : function(newId) {
9161 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9165 * Ext JS Library 1.1.1
9166 * Copyright(c) 2006-2007, Ext JS, LLC.
9168 * Originally Released Under LGPL - original licence link has changed is not relivant.
9171 * <script type="text/javascript">
9177 * @class Roo.data.Store
9178 * @extends Roo.util.Observable
9179 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9180 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9182 * 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
9183 * has no knowledge of the format of the data returned by the Proxy.<br>
9185 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9186 * instances from the data object. These records are cached and made available through accessor functions.
9188 * Creates a new Store.
9189 * @param {Object} config A config object containing the objects needed for the Store to access data,
9190 * and read the data into Records.
9192 Roo.data.Store = function(config){
9193 this.data = new Roo.util.MixedCollection(false);
9194 this.data.getKey = function(o){
9197 this.baseParams = {};
9204 "multisort" : "_multisort"
9207 if(config && config.data){
9208 this.inlineData = config.data;
9212 Roo.apply(this, config);
9214 if(this.reader){ // reader passed
9215 this.reader = Roo.factory(this.reader, Roo.data);
9216 this.reader.xmodule = this.xmodule || false;
9217 if(!this.recordType){
9218 this.recordType = this.reader.recordType;
9220 if(this.reader.onMetaChange){
9221 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9225 if(this.recordType){
9226 this.fields = this.recordType.prototype.fields;
9232 * @event datachanged
9233 * Fires when the data cache has changed, and a widget which is using this Store
9234 * as a Record cache should refresh its view.
9235 * @param {Store} this
9240 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9241 * @param {Store} this
9242 * @param {Object} meta The JSON metadata
9247 * Fires when Records have been added to the Store
9248 * @param {Store} this
9249 * @param {Roo.data.Record[]} records The array of Records added
9250 * @param {Number} index The index at which the record(s) were added
9255 * Fires when a Record has been removed from the Store
9256 * @param {Store} this
9257 * @param {Roo.data.Record} record The Record that was removed
9258 * @param {Number} index The index at which the record was removed
9263 * Fires when a Record has been updated
9264 * @param {Store} this
9265 * @param {Roo.data.Record} record The Record that was updated
9266 * @param {String} operation The update operation being performed. Value may be one of:
9268 Roo.data.Record.EDIT
9269 Roo.data.Record.REJECT
9270 Roo.data.Record.COMMIT
9276 * Fires when the data cache has been cleared.
9277 * @param {Store} this
9282 * Fires before a request is made for a new data object. If the beforeload handler returns false
9283 * the load action will be canceled.
9284 * @param {Store} this
9285 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9289 * @event beforeloadadd
9290 * Fires after a new set of Records has been loaded.
9291 * @param {Store} this
9292 * @param {Roo.data.Record[]} records The Records that were loaded
9293 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9295 beforeloadadd : true,
9298 * Fires after a new set of Records has been loaded, before they are added to the store.
9299 * @param {Store} this
9300 * @param {Roo.data.Record[]} records The Records that were loaded
9301 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9302 * @params {Object} return from reader
9306 * @event loadexception
9307 * Fires if an exception occurs in the Proxy during loading.
9308 * Called with the signature of the Proxy's "loadexception" event.
9309 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9312 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9313 * @param {Object} load options
9314 * @param {Object} jsonData from your request (normally this contains the Exception)
9316 loadexception : true
9320 this.proxy = Roo.factory(this.proxy, Roo.data);
9321 this.proxy.xmodule = this.xmodule || false;
9322 this.relayEvents(this.proxy, ["loadexception"]);
9324 this.sortToggle = {};
9325 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9327 Roo.data.Store.superclass.constructor.call(this);
9329 if(this.inlineData){
9330 this.loadData(this.inlineData);
9331 delete this.inlineData;
9335 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9337 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9338 * without a remote query - used by combo/forms at present.
9342 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9345 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9348 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9349 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9352 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9353 * on any HTTP request
9356 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9359 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9363 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9364 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9369 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9370 * loaded or when a record is removed. (defaults to false).
9372 pruneModifiedRecords : false,
9378 * Add Records to the Store and fires the add event.
9379 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9381 add : function(records){
9382 records = [].concat(records);
9383 for(var i = 0, len = records.length; i < len; i++){
9384 records[i].join(this);
9386 var index = this.data.length;
9387 this.data.addAll(records);
9388 this.fireEvent("add", this, records, index);
9392 * Remove a Record from the Store and fires the remove event.
9393 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9395 remove : function(record){
9396 var index = this.data.indexOf(record);
9397 this.data.removeAt(index);
9398 if(this.pruneModifiedRecords){
9399 this.modified.remove(record);
9401 this.fireEvent("remove", this, record, index);
9405 * Remove all Records from the Store and fires the clear event.
9407 removeAll : function(){
9409 if(this.pruneModifiedRecords){
9412 this.fireEvent("clear", this);
9416 * Inserts Records to the Store at the given index and fires the add event.
9417 * @param {Number} index The start index at which to insert the passed Records.
9418 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9420 insert : function(index, records){
9421 records = [].concat(records);
9422 for(var i = 0, len = records.length; i < len; i++){
9423 this.data.insert(index, records[i]);
9424 records[i].join(this);
9426 this.fireEvent("add", this, records, index);
9430 * Get the index within the cache of the passed Record.
9431 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9432 * @return {Number} The index of the passed Record. Returns -1 if not found.
9434 indexOf : function(record){
9435 return this.data.indexOf(record);
9439 * Get the index within the cache of the Record with the passed id.
9440 * @param {String} id The id of the Record to find.
9441 * @return {Number} The index of the Record. Returns -1 if not found.
9443 indexOfId : function(id){
9444 return this.data.indexOfKey(id);
9448 * Get the Record with the specified id.
9449 * @param {String} id The id of the Record to find.
9450 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9452 getById : function(id){
9453 return this.data.key(id);
9457 * Get the Record at the specified index.
9458 * @param {Number} index The index of the Record to find.
9459 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9461 getAt : function(index){
9462 return this.data.itemAt(index);
9466 * Returns a range of Records between specified indices.
9467 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9468 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9469 * @return {Roo.data.Record[]} An array of Records
9471 getRange : function(start, end){
9472 return this.data.getRange(start, end);
9476 storeOptions : function(o){
9477 o = Roo.apply({}, o);
9480 this.lastOptions = o;
9484 * Loads the Record cache from the configured Proxy using the configured Reader.
9486 * If using remote paging, then the first load call must specify the <em>start</em>
9487 * and <em>limit</em> properties in the options.params property to establish the initial
9488 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9490 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9491 * and this call will return before the new data has been loaded. Perform any post-processing
9492 * in a callback function, or in a "load" event handler.</strong>
9494 * @param {Object} options An object containing properties which control loading options:<ul>
9495 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9496 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9497 * passed the following arguments:<ul>
9498 * <li>r : Roo.data.Record[]</li>
9499 * <li>options: Options object from the load call</li>
9500 * <li>success: Boolean success indicator</li></ul></li>
9501 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9502 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9505 load : function(options){
9506 options = options || {};
9507 if(this.fireEvent("beforeload", this, options) !== false){
9508 this.storeOptions(options);
9509 var p = Roo.apply(options.params || {}, this.baseParams);
9510 // if meta was not loaded from remote source.. try requesting it.
9511 if (!this.reader.metaFromRemote) {
9514 if(this.sortInfo && this.remoteSort){
9515 var pn = this.paramNames;
9516 p[pn["sort"]] = this.sortInfo.field;
9517 p[pn["dir"]] = this.sortInfo.direction;
9519 if (this.multiSort) {
9520 var pn = this.paramNames;
9521 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9524 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9529 * Reloads the Record cache from the configured Proxy using the configured Reader and
9530 * the options from the last load operation performed.
9531 * @param {Object} options (optional) An object containing properties which may override the options
9532 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9533 * the most recently used options are reused).
9535 reload : function(options){
9536 this.load(Roo.applyIf(options||{}, this.lastOptions));
9540 // Called as a callback by the Reader during a load operation.
9541 loadRecords : function(o, options, success){
9542 if(!o || success === false){
9543 if(success !== false){
9544 this.fireEvent("load", this, [], options, o);
9546 if(options.callback){
9547 options.callback.call(options.scope || this, [], options, false);
9551 // if data returned failure - throw an exception.
9552 if (o.success === false) {
9553 // show a message if no listener is registered.
9554 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9555 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9557 // loadmask wil be hooked into this..
9558 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9561 var r = o.records, t = o.totalRecords || r.length;
9563 this.fireEvent("beforeloadadd", this, r, options, o);
9565 if(!options || options.add !== true){
9566 if(this.pruneModifiedRecords){
9569 for(var i = 0, len = r.length; i < len; i++){
9573 this.data = this.snapshot;
9574 delete this.snapshot;
9577 this.data.addAll(r);
9578 this.totalLength = t;
9580 this.fireEvent("datachanged", this);
9582 this.totalLength = Math.max(t, this.data.length+r.length);
9585 this.fireEvent("load", this, r, options, o);
9586 if(options.callback){
9587 options.callback.call(options.scope || this, r, options, true);
9593 * Loads data from a passed data block. A Reader which understands the format of the data
9594 * must have been configured in the constructor.
9595 * @param {Object} data The data block from which to read the Records. The format of the data expected
9596 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9597 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9599 loadData : function(o, append){
9600 var r = this.reader.readRecords(o);
9601 this.loadRecords(r, {add: append}, true);
9605 * Gets the number of cached records.
9607 * <em>If using paging, this may not be the total size of the dataset. If the data object
9608 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9609 * the data set size</em>
9611 getCount : function(){
9612 return this.data.length || 0;
9616 * Gets the total number of records in the dataset as returned by the server.
9618 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9619 * the dataset size</em>
9621 getTotalCount : function(){
9622 return this.totalLength || 0;
9626 * Returns the sort state of the Store as an object with two properties:
9628 field {String} The name of the field by which the Records are sorted
9629 direction {String} The sort order, "ASC" or "DESC"
9632 getSortState : function(){
9633 return this.sortInfo;
9637 applySort : function(){
9638 if(this.sortInfo && !this.remoteSort){
9639 var s = this.sortInfo, f = s.field;
9640 var st = this.fields.get(f).sortType;
9641 var fn = function(r1, r2){
9642 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9643 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9645 this.data.sort(s.direction, fn);
9646 if(this.snapshot && this.snapshot != this.data){
9647 this.snapshot.sort(s.direction, fn);
9653 * Sets the default sort column and order to be used by the next load operation.
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 setDefaultSort : function(field, dir){
9658 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9663 * If remote sorting is used, the sort is performed on the server, and the cache is
9664 * reloaded. If local sorting is used, the cache is sorted internally.
9665 * @param {String} fieldName The name of the field to sort by.
9666 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9668 sort : function(fieldName, dir){
9669 var f = this.fields.get(fieldName);
9671 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9673 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9674 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9679 this.sortToggle[f.name] = dir;
9680 this.sortInfo = {field: f.name, direction: dir};
9681 if(!this.remoteSort){
9683 this.fireEvent("datachanged", this);
9685 this.load(this.lastOptions);
9690 * Calls the specified function for each of the Records in the cache.
9691 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9692 * Returning <em>false</em> aborts and exits the iteration.
9693 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9695 each : function(fn, scope){
9696 this.data.each(fn, scope);
9700 * Gets all records modified since the last commit. Modified records are persisted across load operations
9701 * (e.g., during paging).
9702 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9704 getModifiedRecords : function(){
9705 return this.modified;
9709 createFilterFn : function(property, value, anyMatch){
9710 if(!value.exec){ // not a regex
9711 value = String(value);
9712 if(value.length == 0){
9715 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9718 return value.test(r.data[property]);
9723 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9724 * @param {String} property A field on your records
9725 * @param {Number} start The record index to start at (defaults to 0)
9726 * @param {Number} end The last record index to include (defaults to length - 1)
9727 * @return {Number} The sum
9729 sum : function(property, start, end){
9730 var rs = this.data.items, v = 0;
9732 end = (end || end === 0) ? end : rs.length-1;
9734 for(var i = start; i <= end; i++){
9735 v += (rs[i].data[property] || 0);
9741 * Filter the records by a specified property.
9742 * @param {String} field A field on your records
9743 * @param {String/RegExp} value Either a string that the field
9744 * should start with or a RegExp to test against the field
9745 * @param {Boolean} anyMatch True to match any part not just the beginning
9747 filter : function(property, value, anyMatch){
9748 var fn = this.createFilterFn(property, value, anyMatch);
9749 return fn ? this.filterBy(fn) : this.clearFilter();
9753 * Filter by a function. The specified function will be called with each
9754 * record in this data source. If the function returns true the record is included,
9755 * otherwise it is filtered.
9756 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9757 * @param {Object} scope (optional) The scope of the function (defaults to this)
9759 filterBy : function(fn, scope){
9760 this.snapshot = this.snapshot || this.data;
9761 this.data = this.queryBy(fn, scope||this);
9762 this.fireEvent("datachanged", this);
9766 * Query the records by a specified property.
9767 * @param {String} field A field on your records
9768 * @param {String/RegExp} value Either a string that the field
9769 * should start with or a RegExp to test against the field
9770 * @param {Boolean} anyMatch True to match any part not just the beginning
9771 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9773 query : function(property, value, anyMatch){
9774 var fn = this.createFilterFn(property, value, anyMatch);
9775 return fn ? this.queryBy(fn) : this.data.clone();
9779 * Query by a function. The specified function will be called with each
9780 * record in this data source. If the function returns true the record is included
9782 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9783 * @param {Object} scope (optional) The scope of the function (defaults to this)
9784 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9786 queryBy : function(fn, scope){
9787 var data = this.snapshot || this.data;
9788 return data.filterBy(fn, scope||this);
9792 * Collects unique values for a particular dataIndex from this store.
9793 * @param {String} dataIndex The property to collect
9794 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9795 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9796 * @return {Array} An array of the unique values
9798 collect : function(dataIndex, allowNull, bypassFilter){
9799 var d = (bypassFilter === true && this.snapshot) ?
9800 this.snapshot.items : this.data.items;
9801 var v, sv, r = [], l = {};
9802 for(var i = 0, len = d.length; i < len; i++){
9803 v = d[i].data[dataIndex];
9805 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9814 * Revert to a view of the Record cache with no filtering applied.
9815 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9817 clearFilter : function(suppressEvent){
9818 if(this.snapshot && this.snapshot != this.data){
9819 this.data = this.snapshot;
9820 delete this.snapshot;
9821 if(suppressEvent !== true){
9822 this.fireEvent("datachanged", this);
9828 afterEdit : function(record){
9829 if(this.modified.indexOf(record) == -1){
9830 this.modified.push(record);
9832 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9836 afterReject : function(record){
9837 this.modified.remove(record);
9838 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9842 afterCommit : function(record){
9843 this.modified.remove(record);
9844 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9848 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9849 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9851 commitChanges : function(){
9852 var m = this.modified.slice(0);
9854 for(var i = 0, len = m.length; i < len; i++){
9860 * Cancel outstanding changes on all changed records.
9862 rejectChanges : function(){
9863 var m = this.modified.slice(0);
9865 for(var i = 0, len = m.length; i < len; i++){
9870 onMetaChange : function(meta, rtype, o){
9871 this.recordType = rtype;
9872 this.fields = rtype.prototype.fields;
9873 delete this.snapshot;
9874 this.sortInfo = meta.sortInfo || this.sortInfo;
9876 this.fireEvent('metachange', this, this.reader.meta);
9879 moveIndex : function(data, type)
9881 var index = this.indexOf(data);
9883 var newIndex = index + type;
9887 this.insert(newIndex, data);
9892 * Ext JS Library 1.1.1
9893 * Copyright(c) 2006-2007, Ext JS, LLC.
9895 * Originally Released Under LGPL - original licence link has changed is not relivant.
9898 * <script type="text/javascript">
9902 * @class Roo.data.SimpleStore
9903 * @extends Roo.data.Store
9904 * Small helper class to make creating Stores from Array data easier.
9905 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9906 * @cfg {Array} fields An array of field definition objects, or field name strings.
9907 * @cfg {Array} data The multi-dimensional array of data
9909 * @param {Object} config
9911 Roo.data.SimpleStore = function(config){
9912 Roo.data.SimpleStore.superclass.constructor.call(this, {
9914 reader: new Roo.data.ArrayReader({
9917 Roo.data.Record.create(config.fields)
9919 proxy : new Roo.data.MemoryProxy(config.data)
9923 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9925 * Ext JS Library 1.1.1
9926 * Copyright(c) 2006-2007, Ext JS, LLC.
9928 * Originally Released Under LGPL - original licence link has changed is not relivant.
9931 * <script type="text/javascript">
9936 * @extends Roo.data.Store
9937 * @class Roo.data.JsonStore
9938 * Small helper class to make creating Stores for JSON data easier. <br/>
9940 var store = new Roo.data.JsonStore({
9941 url: 'get-images.php',
9943 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9946 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9947 * JsonReader and HttpProxy (unless inline data is provided).</b>
9948 * @cfg {Array} fields An array of field definition objects, or field name strings.
9950 * @param {Object} config
9952 Roo.data.JsonStore = function(c){
9953 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9954 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9955 reader: new Roo.data.JsonReader(c, c.fields)
9958 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9960 * Ext JS Library 1.1.1
9961 * Copyright(c) 2006-2007, Ext JS, LLC.
9963 * Originally Released Under LGPL - original licence link has changed is not relivant.
9966 * <script type="text/javascript">
9970 Roo.data.Field = function(config){
9971 if(typeof config == "string"){
9972 config = {name: config};
9974 Roo.apply(this, config);
9980 var st = Roo.data.SortTypes;
9981 // named sortTypes are supported, here we look them up
9982 if(typeof this.sortType == "string"){
9983 this.sortType = st[this.sortType];
9986 // set default sortType for strings and dates
9990 this.sortType = st.asUCString;
9993 this.sortType = st.asDate;
9996 this.sortType = st.none;
10001 var stripRe = /[\$,%]/g;
10003 // prebuilt conversion function for this field, instead of
10004 // switching every time we're reading a value
10006 var cv, dateFormat = this.dateFormat;
10011 cv = function(v){ return v; };
10014 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10018 return v !== undefined && v !== null && v !== '' ?
10019 parseInt(String(v).replace(stripRe, ""), 10) : '';
10024 return v !== undefined && v !== null && v !== '' ?
10025 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10030 cv = function(v){ return v === true || v === "true" || v == 1; };
10037 if(v instanceof Date){
10041 if(dateFormat == "timestamp"){
10042 return new Date(v*1000);
10044 return Date.parseDate(v, dateFormat);
10046 var parsed = Date.parse(v);
10047 return parsed ? new Date(parsed) : null;
10056 Roo.data.Field.prototype = {
10064 * Ext JS Library 1.1.1
10065 * Copyright(c) 2006-2007, Ext JS, LLC.
10067 * Originally Released Under LGPL - original licence link has changed is not relivant.
10070 * <script type="text/javascript">
10073 // Base class for reading structured data from a data source. This class is intended to be
10074 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10077 * @class Roo.data.DataReader
10078 * Base class for reading structured data from a data source. This class is intended to be
10079 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10082 Roo.data.DataReader = function(meta, recordType){
10086 this.recordType = recordType instanceof Array ?
10087 Roo.data.Record.create(recordType) : recordType;
10090 Roo.data.DataReader.prototype = {
10092 * Create an empty record
10093 * @param {Object} data (optional) - overlay some values
10094 * @return {Roo.data.Record} record created.
10096 newRow : function(d) {
10098 this.recordType.prototype.fields.each(function(c) {
10100 case 'int' : da[c.name] = 0; break;
10101 case 'date' : da[c.name] = new Date(); break;
10102 case 'float' : da[c.name] = 0.0; break;
10103 case 'boolean' : da[c.name] = false; break;
10104 default : da[c.name] = ""; break;
10108 return new this.recordType(Roo.apply(da, d));
10113 * Ext JS Library 1.1.1
10114 * Copyright(c) 2006-2007, Ext JS, LLC.
10116 * Originally Released Under LGPL - original licence link has changed is not relivant.
10119 * <script type="text/javascript">
10123 * @class Roo.data.DataProxy
10124 * @extends Roo.data.Observable
10125 * This class is an abstract base class for implementations which provide retrieval of
10126 * unformatted data objects.<br>
10128 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10129 * (of the appropriate type which knows how to parse the data object) to provide a block of
10130 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10132 * Custom implementations must implement the load method as described in
10133 * {@link Roo.data.HttpProxy#load}.
10135 Roo.data.DataProxy = function(){
10138 * @event beforeload
10139 * Fires before a network request is made to retrieve a data object.
10140 * @param {Object} This DataProxy object.
10141 * @param {Object} params The params parameter to the load function.
10146 * Fires before the load method's callback is called.
10147 * @param {Object} This DataProxy object.
10148 * @param {Object} o The data object.
10149 * @param {Object} arg The callback argument object passed to the load function.
10153 * @event loadexception
10154 * Fires if an Exception occurs during data retrieval.
10155 * @param {Object} This DataProxy object.
10156 * @param {Object} o The data object.
10157 * @param {Object} arg The callback argument object passed to the load function.
10158 * @param {Object} e The Exception.
10160 loadexception : true
10162 Roo.data.DataProxy.superclass.constructor.call(this);
10165 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10168 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10172 * Ext JS Library 1.1.1
10173 * Copyright(c) 2006-2007, Ext JS, LLC.
10175 * Originally Released Under LGPL - original licence link has changed is not relivant.
10178 * <script type="text/javascript">
10181 * @class Roo.data.MemoryProxy
10182 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10183 * to the Reader when its load method is called.
10185 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10187 Roo.data.MemoryProxy = function(data){
10191 Roo.data.MemoryProxy.superclass.constructor.call(this);
10195 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10197 * Load data from the requested source (in this case an in-memory
10198 * data object passed to the constructor), read the data object into
10199 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10200 * process that block using the passed callback.
10201 * @param {Object} params This parameter is not used by the MemoryProxy class.
10202 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10203 * object into a block of Roo.data.Records.
10204 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10205 * The function must be passed <ul>
10206 * <li>The Record block object</li>
10207 * <li>The "arg" argument from the load function</li>
10208 * <li>A boolean success indicator</li>
10210 * @param {Object} scope The scope in which to call the callback
10211 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10213 load : function(params, reader, callback, scope, arg){
10214 params = params || {};
10217 result = reader.readRecords(this.data);
10219 this.fireEvent("loadexception", this, arg, null, e);
10220 callback.call(scope, null, arg, false);
10223 callback.call(scope, result, arg, true);
10227 update : function(params, records){
10232 * Ext JS Library 1.1.1
10233 * Copyright(c) 2006-2007, Ext JS, LLC.
10235 * Originally Released Under LGPL - original licence link has changed is not relivant.
10238 * <script type="text/javascript">
10241 * @class Roo.data.HttpProxy
10242 * @extends Roo.data.DataProxy
10243 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10244 * configured to reference a certain URL.<br><br>
10246 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10247 * from which the running page was served.<br><br>
10249 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10251 * Be aware that to enable the browser to parse an XML document, the server must set
10252 * the Content-Type header in the HTTP response to "text/xml".
10254 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10255 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10256 * will be used to make the request.
10258 Roo.data.HttpProxy = function(conn){
10259 Roo.data.HttpProxy.superclass.constructor.call(this);
10260 // is conn a conn config or a real conn?
10262 this.useAjax = !conn || !conn.events;
10266 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10267 // thse are take from connection...
10270 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10273 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10274 * extra parameters to each request made by this object. (defaults to undefined)
10277 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10278 * to each request made by this object. (defaults to undefined)
10281 * @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)
10284 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10287 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10293 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10297 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10298 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10299 * a finer-grained basis than the DataProxy events.
10301 getConnection : function(){
10302 return this.useAjax ? Roo.Ajax : this.conn;
10306 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10307 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10308 * process that block using the passed callback.
10309 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10310 * for the request to the remote server.
10311 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10312 * object into a block of Roo.data.Records.
10313 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10314 * The function must be passed <ul>
10315 * <li>The Record block object</li>
10316 * <li>The "arg" argument from the load function</li>
10317 * <li>A boolean success indicator</li>
10319 * @param {Object} scope The scope in which to call the callback
10320 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10322 load : function(params, reader, callback, scope, arg){
10323 if(this.fireEvent("beforeload", this, params) !== false){
10325 params : params || {},
10327 callback : callback,
10332 callback : this.loadResponse,
10336 Roo.applyIf(o, this.conn);
10337 if(this.activeRequest){
10338 Roo.Ajax.abort(this.activeRequest);
10340 this.activeRequest = Roo.Ajax.request(o);
10342 this.conn.request(o);
10345 callback.call(scope||this, null, arg, false);
10350 loadResponse : function(o, success, response){
10351 delete this.activeRequest;
10353 this.fireEvent("loadexception", this, o, response);
10354 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10359 result = o.reader.read(response);
10361 this.fireEvent("loadexception", this, o, response, e);
10362 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10366 this.fireEvent("load", this, o, o.request.arg);
10367 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10371 update : function(dataSet){
10376 updateResponse : function(dataSet){
10381 * Ext JS Library 1.1.1
10382 * Copyright(c) 2006-2007, Ext JS, LLC.
10384 * Originally Released Under LGPL - original licence link has changed is not relivant.
10387 * <script type="text/javascript">
10391 * @class Roo.data.ScriptTagProxy
10392 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10393 * other than the originating domain of the running page.<br><br>
10395 * <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
10396 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10398 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10399 * source code that is used as the source inside a <script> tag.<br><br>
10401 * In order for the browser to process the returned data, the server must wrap the data object
10402 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10403 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10404 * depending on whether the callback name was passed:
10407 boolean scriptTag = false;
10408 String cb = request.getParameter("callback");
10411 response.setContentType("text/javascript");
10413 response.setContentType("application/x-json");
10415 Writer out = response.getWriter();
10417 out.write(cb + "(");
10419 out.print(dataBlock.toJsonString());
10426 * @param {Object} config A configuration object.
10428 Roo.data.ScriptTagProxy = function(config){
10429 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10430 Roo.apply(this, config);
10431 this.head = document.getElementsByTagName("head")[0];
10434 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10436 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10438 * @cfg {String} url The URL from which to request the data object.
10441 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10445 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10446 * the server the name of the callback function set up by the load call to process the returned data object.
10447 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10448 * javascript output which calls this named function passing the data object as its only parameter.
10450 callbackParam : "callback",
10452 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10453 * name to the request.
10458 * Load data from the configured URL, read the data object into
10459 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10460 * process that block using the passed callback.
10461 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10462 * for the request to the remote server.
10463 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10464 * object into a block of Roo.data.Records.
10465 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10466 * The function must be passed <ul>
10467 * <li>The Record block object</li>
10468 * <li>The "arg" argument from the load function</li>
10469 * <li>A boolean success indicator</li>
10471 * @param {Object} scope The scope in which to call the callback
10472 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10474 load : function(params, reader, callback, scope, arg){
10475 if(this.fireEvent("beforeload", this, params) !== false){
10477 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10479 var url = this.url;
10480 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10482 url += "&_dc=" + (new Date().getTime());
10484 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10487 cb : "stcCallback"+transId,
10488 scriptId : "stcScript"+transId,
10492 callback : callback,
10498 window[trans.cb] = function(o){
10499 conn.handleResponse(o, trans);
10502 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10504 if(this.autoAbort !== false){
10508 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10510 var script = document.createElement("script");
10511 script.setAttribute("src", url);
10512 script.setAttribute("type", "text/javascript");
10513 script.setAttribute("id", trans.scriptId);
10514 this.head.appendChild(script);
10516 this.trans = trans;
10518 callback.call(scope||this, null, arg, false);
10523 isLoading : function(){
10524 return this.trans ? true : false;
10528 * Abort the current server request.
10530 abort : function(){
10531 if(this.isLoading()){
10532 this.destroyTrans(this.trans);
10537 destroyTrans : function(trans, isLoaded){
10538 this.head.removeChild(document.getElementById(trans.scriptId));
10539 clearTimeout(trans.timeoutId);
10541 window[trans.cb] = undefined;
10543 delete window[trans.cb];
10546 // if hasn't been loaded, wait for load to remove it to prevent script error
10547 window[trans.cb] = function(){
10548 window[trans.cb] = undefined;
10550 delete window[trans.cb];
10557 handleResponse : function(o, trans){
10558 this.trans = false;
10559 this.destroyTrans(trans, true);
10562 result = trans.reader.readRecords(o);
10564 this.fireEvent("loadexception", this, o, trans.arg, e);
10565 trans.callback.call(trans.scope||window, null, trans.arg, false);
10568 this.fireEvent("load", this, o, trans.arg);
10569 trans.callback.call(trans.scope||window, result, trans.arg, true);
10573 handleFailure : function(trans){
10574 this.trans = false;
10575 this.destroyTrans(trans, false);
10576 this.fireEvent("loadexception", this, null, trans.arg);
10577 trans.callback.call(trans.scope||window, null, trans.arg, false);
10581 * Ext JS Library 1.1.1
10582 * Copyright(c) 2006-2007, Ext JS, LLC.
10584 * Originally Released Under LGPL - original licence link has changed is not relivant.
10587 * <script type="text/javascript">
10591 * @class Roo.data.JsonReader
10592 * @extends Roo.data.DataReader
10593 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10594 * based on mappings in a provided Roo.data.Record constructor.
10596 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10597 * in the reply previously.
10602 var RecordDef = Roo.data.Record.create([
10603 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10604 {name: 'occupation'} // This field will use "occupation" as the mapping.
10606 var myReader = new Roo.data.JsonReader({
10607 totalProperty: "results", // The property which contains the total dataset size (optional)
10608 root: "rows", // The property which contains an Array of row objects
10609 id: "id" // The property within each row object that provides an ID for the record (optional)
10613 * This would consume a JSON file like this:
10615 { 'results': 2, 'rows': [
10616 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10617 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10620 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10621 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10622 * paged from the remote server.
10623 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10624 * @cfg {String} root name of the property which contains the Array of row objects.
10625 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10627 * Create a new JsonReader
10628 * @param {Object} meta Metadata configuration options
10629 * @param {Object} recordType Either an Array of field definition objects,
10630 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10632 Roo.data.JsonReader = function(meta, recordType){
10635 // set some defaults:
10636 Roo.applyIf(meta, {
10637 totalProperty: 'total',
10638 successProperty : 'success',
10643 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10645 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10648 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10649 * Used by Store query builder to append _requestMeta to params.
10652 metaFromRemote : false,
10654 * This method is only used by a DataProxy which has retrieved data from a remote server.
10655 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10656 * @return {Object} data A data block which is used by an Roo.data.Store object as
10657 * a cache of Roo.data.Records.
10659 read : function(response){
10660 var json = response.responseText;
10662 var o = /* eval:var:o */ eval("("+json+")");
10664 throw {message: "JsonReader.read: Json object not found"};
10670 this.metaFromRemote = true;
10671 this.meta = o.metaData;
10672 this.recordType = Roo.data.Record.create(o.metaData.fields);
10673 this.onMetaChange(this.meta, this.recordType, o);
10675 return this.readRecords(o);
10678 // private function a store will implement
10679 onMetaChange : function(meta, recordType, o){
10686 simpleAccess: function(obj, subsc) {
10693 getJsonAccessor: function(){
10695 return function(expr) {
10697 return(re.test(expr))
10698 ? new Function("obj", "return obj." + expr)
10703 return Roo.emptyFn;
10708 * Create a data block containing Roo.data.Records from an XML document.
10709 * @param {Object} o An object which contains an Array of row objects in the property specified
10710 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10711 * which contains the total size of the dataset.
10712 * @return {Object} data A data block which is used by an Roo.data.Store object as
10713 * a cache of Roo.data.Records.
10715 readRecords : function(o){
10717 * After any data loads, the raw JSON data is available for further custom processing.
10721 var s = this.meta, Record = this.recordType,
10722 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10724 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10726 if(s.totalProperty) {
10727 this.getTotal = this.getJsonAccessor(s.totalProperty);
10729 if(s.successProperty) {
10730 this.getSuccess = this.getJsonAccessor(s.successProperty);
10732 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10734 var g = this.getJsonAccessor(s.id);
10735 this.getId = function(rec) {
10737 return (r === undefined || r === "") ? null : r;
10740 this.getId = function(){return null;};
10743 for(var jj = 0; jj < fl; jj++){
10745 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10746 this.ef[jj] = this.getJsonAccessor(map);
10750 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10751 if(s.totalProperty){
10752 var vt = parseInt(this.getTotal(o), 10);
10757 if(s.successProperty){
10758 var vs = this.getSuccess(o);
10759 if(vs === false || vs === 'false'){
10764 for(var i = 0; i < c; i++){
10767 var id = this.getId(n);
10768 for(var j = 0; j < fl; j++){
10770 var v = this.ef[j](n);
10772 Roo.log('missing convert for ' + f.name);
10776 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10778 var record = new Record(values, id);
10780 records[i] = record;
10786 totalRecords : totalRecords
10791 * Ext JS Library 1.1.1
10792 * Copyright(c) 2006-2007, Ext JS, LLC.
10794 * Originally Released Under LGPL - original licence link has changed is not relivant.
10797 * <script type="text/javascript">
10801 * @class Roo.data.ArrayReader
10802 * @extends Roo.data.DataReader
10803 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10804 * Each element of that Array represents a row of data fields. The
10805 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10806 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10810 var RecordDef = Roo.data.Record.create([
10811 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10812 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10814 var myReader = new Roo.data.ArrayReader({
10815 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10819 * This would consume an Array like this:
10821 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10823 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10825 * Create a new JsonReader
10826 * @param {Object} meta Metadata configuration options.
10827 * @param {Object} recordType Either an Array of field definition objects
10828 * as specified to {@link Roo.data.Record#create},
10829 * or an {@link Roo.data.Record} object
10830 * created using {@link Roo.data.Record#create}.
10832 Roo.data.ArrayReader = function(meta, recordType){
10833 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10836 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10838 * Create a data block containing Roo.data.Records from an XML document.
10839 * @param {Object} o An Array of row objects which represents the dataset.
10840 * @return {Object} data A data block which is used by an Roo.data.Store object as
10841 * a cache of Roo.data.Records.
10843 readRecords : function(o){
10844 var sid = this.meta ? this.meta.id : null;
10845 var recordType = this.recordType, fields = recordType.prototype.fields;
10848 for(var i = 0; i < root.length; i++){
10851 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10852 for(var j = 0, jlen = fields.length; j < jlen; j++){
10853 var f = fields.items[j];
10854 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10855 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10857 values[f.name] = v;
10859 var record = new recordType(values, id);
10861 records[records.length] = record;
10865 totalRecords : records.length
10874 * @class Roo.bootstrap.ComboBox
10875 * @extends Roo.bootstrap.TriggerField
10876 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10877 * @cfg {Boolean} append (true|false) default false
10878 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10879 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10880 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10881 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10882 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10884 * Create a new ComboBox.
10885 * @param {Object} config Configuration options
10887 Roo.bootstrap.ComboBox = function(config){
10888 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10892 * Fires when the dropdown list is expanded
10893 * @param {Roo.bootstrap.ComboBox} combo This combo box
10898 * Fires when the dropdown list is collapsed
10899 * @param {Roo.bootstrap.ComboBox} combo This combo box
10903 * @event beforeselect
10904 * Fires before a list item is selected. Return false to cancel the selection.
10905 * @param {Roo.bootstrap.ComboBox} combo This combo box
10906 * @param {Roo.data.Record} record The data record returned from the underlying store
10907 * @param {Number} index The index of the selected item in the dropdown list
10909 'beforeselect' : true,
10912 * Fires when a list item is selected
10913 * @param {Roo.bootstrap.ComboBox} combo This combo box
10914 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10915 * @param {Number} index The index of the selected item in the dropdown list
10919 * @event beforequery
10920 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10921 * The event object passed has these properties:
10922 * @param {Roo.bootstrap.ComboBox} combo This combo box
10923 * @param {String} query The query
10924 * @param {Boolean} forceAll true to force "all" query
10925 * @param {Boolean} cancel true to cancel the query
10926 * @param {Object} e The query event object
10928 'beforequery': true,
10931 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10932 * @param {Roo.bootstrap.ComboBox} combo This combo box
10937 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10938 * @param {Roo.bootstrap.ComboBox} combo This combo box
10939 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10944 * Fires when the remove value from the combobox array
10945 * @param {Roo.bootstrap.ComboBox} combo This combo box
10949 * @event specialfilter
10950 * Fires when specialfilter
10951 * @param {Roo.bootstrap.ComboBox} combo This combo box
10953 'specialfilter' : true
10958 this.tickItems = [];
10960 this.selectedIndex = -1;
10961 if(this.mode == 'local'){
10962 if(config.queryDelay === undefined){
10963 this.queryDelay = 10;
10965 if(config.minChars === undefined){
10971 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10974 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10975 * rendering into an Roo.Editor, defaults to false)
10978 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10979 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
10982 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
10985 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
10986 * the dropdown list (defaults to undefined, with no header element)
10990 * @cfg {String/Roo.Template} tpl The template to use to render the output
10994 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
10996 listWidth: undefined,
10998 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
10999 * mode = 'remote' or 'text' if mode = 'local')
11001 displayField: undefined,
11004 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11005 * mode = 'remote' or 'value' if mode = 'local').
11006 * Note: use of a valueField requires the user make a selection
11007 * in order for a value to be mapped.
11009 valueField: undefined,
11013 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11014 * field's data value (defaults to the underlying DOM element's name)
11016 hiddenName: undefined,
11018 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11022 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11024 selectedClass: 'active',
11027 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11031 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11032 * anchor positions (defaults to 'tl-bl')
11034 listAlign: 'tl-bl?',
11036 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11040 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11041 * query specified by the allQuery config option (defaults to 'query')
11043 triggerAction: 'query',
11045 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11046 * (defaults to 4, does not apply if editable = false)
11050 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11051 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11055 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11056 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11060 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11061 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11065 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11066 * when editable = true (defaults to false)
11068 selectOnFocus:false,
11070 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11072 queryParam: 'query',
11074 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11075 * when mode = 'remote' (defaults to 'Loading...')
11077 loadingText: 'Loading...',
11079 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11083 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11087 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11088 * traditional select (defaults to true)
11092 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11096 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11100 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11101 * listWidth has a higher value)
11105 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11106 * allow the user to set arbitrary text into the field (defaults to false)
11108 forceSelection:false,
11110 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11111 * if typeAhead = true (defaults to 250)
11113 typeAheadDelay : 250,
11115 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11116 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11118 valueNotFoundText : undefined,
11120 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11122 blockFocus : false,
11125 * @cfg {Boolean} disableClear Disable showing of clear button.
11127 disableClear : false,
11129 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11131 alwaysQuery : false,
11134 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11139 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11141 invalidClass : "has-warning",
11144 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11146 validClass : "has-success",
11149 * @cfg {Boolean} specialFilter (true|false) special filter default false
11151 specialFilter : false,
11163 btnPosition : 'right',
11164 triggerList : true,
11165 showToggleBtn : true,
11166 // element that contains real text value.. (when hidden is used..)
11168 getAutoCreate : function()
11175 if(!this.tickable){
11176 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11181 * ComboBox with tickable selections
11184 var align = this.labelAlign || this.parentLabelAlign();
11187 cls : 'form-group roo-combobox-tickable' //input-group
11192 cls : 'tickable-buttons',
11197 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11204 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11211 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11218 buttons.cn.unshift({
11220 cls: 'select2-search-field-input'
11226 Roo.each(buttons.cn, function(c){
11228 c.cls += ' btn-' + _this.size;
11231 if (_this.disabled) {
11242 cls: 'form-hidden-field'
11246 cls: 'select2-choices',
11250 cls: 'select2-search-field',
11262 cls: 'select2-container input-group select2-container-multi',
11267 // cls: 'typeahead typeahead-long dropdown-menu',
11268 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11273 if(this.hasFeedback && !this.allowBlank){
11277 cls: 'glyphicon form-control-feedback'
11280 combobox.cn.push(feedback);
11283 if (align ==='left' && this.fieldLabel.length) {
11285 Roo.log("left and has label");
11291 cls : 'control-label col-sm-' + this.labelWidth,
11292 html : this.fieldLabel
11296 cls : "col-sm-" + (12 - this.labelWidth),
11303 } else if ( this.fieldLabel.length) {
11309 //cls : 'input-group-addon',
11310 html : this.fieldLabel
11320 Roo.log(" no label && no align");
11327 ['xs','sm','md','lg'].map(function(size){
11328 if (settings[size]) {
11329 cfg.cls += ' col-' + size + '-' + settings[size];
11338 initEvents: function()
11342 throw "can not find store for combo";
11344 this.store = Roo.factory(this.store, Roo.data);
11347 this.initTickableEvents();
11351 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11353 if(this.hiddenName){
11355 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11357 this.hiddenField.dom.value =
11358 this.hiddenValue !== undefined ? this.hiddenValue :
11359 this.value !== undefined ? this.value : '';
11361 // prevent input submission
11362 this.el.dom.removeAttribute('name');
11363 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11368 // this.el.dom.setAttribute('autocomplete', 'off');
11371 var cls = 'x-combo-list';
11373 //this.list = new Roo.Layer({
11374 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11380 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11381 _this.list.setWidth(lw);
11384 this.list.on('mouseover', this.onViewOver, this);
11385 this.list.on('mousemove', this.onViewMove, this);
11387 this.list.on('scroll', this.onViewScroll, this);
11390 this.list.swallowEvent('mousewheel');
11391 this.assetHeight = 0;
11394 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11395 this.assetHeight += this.header.getHeight();
11398 this.innerList = this.list.createChild({cls:cls+'-inner'});
11399 this.innerList.on('mouseover', this.onViewOver, this);
11400 this.innerList.on('mousemove', this.onViewMove, this);
11401 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11403 if(this.allowBlank && !this.pageSize && !this.disableClear){
11404 this.footer = this.list.createChild({cls:cls+'-ft'});
11405 this.pageTb = new Roo.Toolbar(this.footer);
11409 this.footer = this.list.createChild({cls:cls+'-ft'});
11410 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11411 {pageSize: this.pageSize});
11415 if (this.pageTb && this.allowBlank && !this.disableClear) {
11417 this.pageTb.add(new Roo.Toolbar.Fill(), {
11418 cls: 'x-btn-icon x-btn-clear',
11420 handler: function()
11423 _this.clearValue();
11424 _this.onSelect(false, -1);
11429 this.assetHeight += this.footer.getHeight();
11434 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11437 this.view = new Roo.View(this.list, this.tpl, {
11438 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11440 //this.view.wrapEl.setDisplayed(false);
11441 this.view.on('click', this.onViewClick, this);
11445 this.store.on('beforeload', this.onBeforeLoad, this);
11446 this.store.on('load', this.onLoad, this);
11447 this.store.on('loadexception', this.onLoadException, this);
11449 if(this.resizable){
11450 this.resizer = new Roo.Resizable(this.list, {
11451 pinned:true, handles:'se'
11453 this.resizer.on('resize', function(r, w, h){
11454 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11455 this.listWidth = w;
11456 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11457 this.restrictHeight();
11459 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11462 if(!this.editable){
11463 this.editable = true;
11464 this.setEditable(false);
11469 if (typeof(this.events.add.listeners) != 'undefined') {
11471 this.addicon = this.wrap.createChild(
11472 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11474 this.addicon.on('click', function(e) {
11475 this.fireEvent('add', this);
11478 if (typeof(this.events.edit.listeners) != 'undefined') {
11480 this.editicon = this.wrap.createChild(
11481 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11482 if (this.addicon) {
11483 this.editicon.setStyle('margin-left', '40px');
11485 this.editicon.on('click', function(e) {
11487 // we fire even if inothing is selected..
11488 this.fireEvent('edit', this, this.lastData );
11494 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11495 "up" : function(e){
11496 this.inKeyMode = true;
11500 "down" : function(e){
11501 if(!this.isExpanded()){
11502 this.onTriggerClick();
11504 this.inKeyMode = true;
11509 "enter" : function(e){
11510 // this.onViewClick();
11514 if(this.fireEvent("specialkey", this, e)){
11515 this.onViewClick(false);
11521 "esc" : function(e){
11525 "tab" : function(e){
11528 if(this.fireEvent("specialkey", this, e)){
11529 this.onViewClick(false);
11537 doRelay : function(foo, bar, hname){
11538 if(hname == 'down' || this.scope.isExpanded()){
11539 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11548 this.queryDelay = Math.max(this.queryDelay || 10,
11549 this.mode == 'local' ? 10 : 250);
11552 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11554 if(this.typeAhead){
11555 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11557 if(this.editable !== false){
11558 this.inputEl().on("keyup", this.onKeyUp, this);
11560 if(this.forceSelection){
11561 this.inputEl().on('blur', this.doForce, this);
11565 this.choices = this.el.select('ul.select2-choices', true).first();
11566 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11570 initTickableEvents: function()
11574 if(this.hiddenName){
11576 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11578 this.hiddenField.dom.value =
11579 this.hiddenValue !== undefined ? this.hiddenValue :
11580 this.value !== undefined ? this.value : '';
11582 // prevent input submission
11583 this.el.dom.removeAttribute('name');
11584 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11589 // this.list = this.el.select('ul.dropdown-menu',true).first();
11591 this.choices = this.el.select('ul.select2-choices', true).first();
11592 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11593 if(this.triggerList){
11594 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11597 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11598 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11600 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11601 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11603 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11604 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11606 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11607 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11608 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11611 this.cancelBtn.hide();
11616 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11617 _this.list.setWidth(lw);
11620 this.list.on('mouseover', this.onViewOver, this);
11621 this.list.on('mousemove', this.onViewMove, this);
11623 this.list.on('scroll', this.onViewScroll, this);
11626 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>';
11629 this.view = new Roo.View(this.list, this.tpl, {
11630 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11633 //this.view.wrapEl.setDisplayed(false);
11634 this.view.on('click', this.onViewClick, this);
11638 this.store.on('beforeload', this.onBeforeLoad, this);
11639 this.store.on('load', this.onLoad, this);
11640 this.store.on('loadexception', this.onLoadException, this);
11643 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11644 "up" : function(e){
11645 this.inKeyMode = true;
11649 "down" : function(e){
11650 this.inKeyMode = true;
11654 "enter" : function(e){
11655 if(this.fireEvent("specialkey", this, e)){
11656 this.onViewClick(false);
11662 "esc" : function(e){
11663 this.onTickableFooterButtonClick(e, false, false);
11666 "tab" : function(e){
11667 this.fireEvent("specialkey", this, e);
11669 this.onTickableFooterButtonClick(e, false, false);
11676 doRelay : function(e, fn, key){
11677 if(this.scope.isExpanded()){
11678 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11687 this.queryDelay = Math.max(this.queryDelay || 10,
11688 this.mode == 'local' ? 10 : 250);
11691 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11693 if(this.typeAhead){
11694 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11697 if(this.editable !== false){
11698 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11703 onDestroy : function(){
11705 this.view.setStore(null);
11706 this.view.el.removeAllListeners();
11707 this.view.el.remove();
11708 this.view.purgeListeners();
11711 this.list.dom.innerHTML = '';
11715 this.store.un('beforeload', this.onBeforeLoad, this);
11716 this.store.un('load', this.onLoad, this);
11717 this.store.un('loadexception', this.onLoadException, this);
11719 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11723 fireKey : function(e){
11724 if(e.isNavKeyPress() && !this.list.isVisible()){
11725 this.fireEvent("specialkey", this, e);
11730 onResize: function(w, h){
11731 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11733 // if(typeof w != 'number'){
11734 // // we do not handle it!?!?
11737 // var tw = this.trigger.getWidth();
11738 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11739 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11741 // this.inputEl().setWidth( this.adjustWidth('input', x));
11743 // //this.trigger.setStyle('left', x+'px');
11745 // if(this.list && this.listWidth === undefined){
11746 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11747 // this.list.setWidth(lw);
11748 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11756 * Allow or prevent the user from directly editing the field text. If false is passed,
11757 * the user will only be able to select from the items defined in the dropdown list. This method
11758 * is the runtime equivalent of setting the 'editable' config option at config time.
11759 * @param {Boolean} value True to allow the user to directly edit the field text
11761 setEditable : function(value){
11762 if(value == this.editable){
11765 this.editable = value;
11767 this.inputEl().dom.setAttribute('readOnly', true);
11768 this.inputEl().on('mousedown', this.onTriggerClick, this);
11769 this.inputEl().addClass('x-combo-noedit');
11771 this.inputEl().dom.setAttribute('readOnly', false);
11772 this.inputEl().un('mousedown', this.onTriggerClick, this);
11773 this.inputEl().removeClass('x-combo-noedit');
11779 onBeforeLoad : function(combo,opts){
11780 if(!this.hasFocus){
11784 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11786 this.restrictHeight();
11787 this.selectedIndex = -1;
11791 onLoad : function(){
11793 this.hasQuery = false;
11795 if(!this.hasFocus){
11799 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11800 this.loading.hide();
11803 if(this.store.getCount() > 0){
11805 this.restrictHeight();
11806 if(this.lastQuery == this.allQuery){
11807 if(this.editable && !this.tickable){
11808 this.inputEl().dom.select();
11812 !this.selectByValue(this.value, true) &&
11815 !this.store.lastOptions ||
11816 typeof(this.store.lastOptions.add) == 'undefined' ||
11817 this.store.lastOptions.add != true
11820 this.select(0, true);
11823 if(this.autoFocus){
11826 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11827 this.taTask.delay(this.typeAheadDelay);
11831 this.onEmptyResults();
11837 onLoadException : function()
11839 this.hasQuery = false;
11841 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11842 this.loading.hide();
11845 if(this.tickable && this.editable){
11851 Roo.log(this.store.reader.jsonData);
11852 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11854 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11860 onTypeAhead : function(){
11861 if(this.store.getCount() > 0){
11862 var r = this.store.getAt(0);
11863 var newValue = r.data[this.displayField];
11864 var len = newValue.length;
11865 var selStart = this.getRawValue().length;
11867 if(selStart != len){
11868 this.setRawValue(newValue);
11869 this.selectText(selStart, newValue.length);
11875 onSelect : function(record, index){
11877 if(this.fireEvent('beforeselect', this, record, index) !== false){
11879 this.setFromData(index > -1 ? record.data : false);
11882 this.fireEvent('select', this, record, index);
11887 * Returns the currently selected field value or empty string if no value is set.
11888 * @return {String} value The selected value
11890 getValue : function(){
11893 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11896 if(this.valueField){
11897 return typeof this.value != 'undefined' ? this.value : '';
11899 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11904 * Clears any text/value currently set in the field
11906 clearValue : function(){
11907 if(this.hiddenField){
11908 this.hiddenField.dom.value = '';
11911 this.setRawValue('');
11912 this.lastSelectionText = '';
11913 this.lastData = false;
11918 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11919 * will be displayed in the field. If the value does not match the data value of an existing item,
11920 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11921 * Otherwise the field will be blank (although the value will still be set).
11922 * @param {String} value The value to match
11924 setValue : function(v){
11931 if(this.valueField){
11932 var r = this.findRecord(this.valueField, v);
11934 text = r.data[this.displayField];
11935 }else if(this.valueNotFoundText !== undefined){
11936 text = this.valueNotFoundText;
11939 this.lastSelectionText = text;
11940 if(this.hiddenField){
11941 this.hiddenField.dom.value = v;
11943 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11947 * @property {Object} the last set data for the element
11952 * Sets the value of the field based on a object which is related to the record format for the store.
11953 * @param {Object} value the value to set as. or false on reset?
11955 setFromData : function(o){
11962 var dv = ''; // display value
11963 var vv = ''; // value value..
11965 if (this.displayField) {
11966 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11968 // this is an error condition!!!
11969 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11972 if(this.valueField){
11973 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11976 if(this.hiddenField){
11977 this.hiddenField.dom.value = vv;
11979 this.lastSelectionText = dv;
11980 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11984 // no hidden field.. - we store the value in 'value', but still display
11985 // display field!!!!
11986 this.lastSelectionText = dv;
11987 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
11993 reset : function(){
11994 // overridden so that last data is reset..
12001 this.setValue(this.originalValue);
12002 this.clearInvalid();
12003 this.lastData = false;
12005 this.view.clearSelections();
12009 findRecord : function(prop, value){
12011 if(this.store.getCount() > 0){
12012 this.store.each(function(r){
12013 if(r.data[prop] == value){
12023 getName: function()
12025 // returns hidden if it's set..
12026 if (!this.rendered) {return ''};
12027 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12031 onViewMove : function(e, t){
12032 this.inKeyMode = false;
12036 onViewOver : function(e, t){
12037 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12040 var item = this.view.findItemFromChild(t);
12043 var index = this.view.indexOf(item);
12044 this.select(index, false);
12049 onViewClick : function(view, doFocus, el, e)
12051 var index = this.view.getSelectedIndexes()[0];
12053 var r = this.store.getAt(index);
12057 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12064 Roo.each(this.tickItems, function(v,k){
12066 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12067 _this.tickItems.splice(k, 1);
12069 if(typeof(e) == 'undefined' && view == false){
12070 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12082 this.tickItems.push(r.data);
12084 if(typeof(e) == 'undefined' && view == false){
12085 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12092 this.onSelect(r, index);
12094 if(doFocus !== false && !this.blockFocus){
12095 this.inputEl().focus();
12100 restrictHeight : function(){
12101 //this.innerList.dom.style.height = '';
12102 //var inner = this.innerList.dom;
12103 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12104 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12105 //this.list.beginUpdate();
12106 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12107 this.list.alignTo(this.inputEl(), this.listAlign);
12108 this.list.alignTo(this.inputEl(), this.listAlign);
12109 //this.list.endUpdate();
12113 onEmptyResults : function(){
12115 if(this.tickable && this.editable){
12116 this.restrictHeight();
12124 * Returns true if the dropdown list is expanded, else false.
12126 isExpanded : function(){
12127 return this.list.isVisible();
12131 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12132 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12133 * @param {String} value The data value of the item to select
12134 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12135 * selected item if it is not currently in view (defaults to true)
12136 * @return {Boolean} True if the value matched an item in the list, else false
12138 selectByValue : function(v, scrollIntoView){
12139 if(v !== undefined && v !== null){
12140 var r = this.findRecord(this.valueField || this.displayField, v);
12142 this.select(this.store.indexOf(r), scrollIntoView);
12150 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12151 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12152 * @param {Number} index The zero-based index of the list item to select
12153 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12154 * selected item if it is not currently in view (defaults to true)
12156 select : function(index, scrollIntoView){
12157 this.selectedIndex = index;
12158 this.view.select(index);
12159 if(scrollIntoView !== false){
12160 var el = this.view.getNode(index);
12162 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12165 this.list.scrollChildIntoView(el, false);
12171 selectNext : function(){
12172 var ct = this.store.getCount();
12174 if(this.selectedIndex == -1){
12176 }else if(this.selectedIndex < ct-1){
12177 this.select(this.selectedIndex+1);
12183 selectPrev : function(){
12184 var ct = this.store.getCount();
12186 if(this.selectedIndex == -1){
12188 }else if(this.selectedIndex != 0){
12189 this.select(this.selectedIndex-1);
12195 onKeyUp : function(e){
12196 if(this.editable !== false && !e.isSpecialKey()){
12197 this.lastKey = e.getKey();
12198 this.dqTask.delay(this.queryDelay);
12203 validateBlur : function(){
12204 return !this.list || !this.list.isVisible();
12208 initQuery : function(){
12210 var v = this.getRawValue();
12212 if(this.tickable && this.editable){
12213 v = this.tickableInputEl().getValue();
12220 doForce : function(){
12221 if(this.inputEl().dom.value.length > 0){
12222 this.inputEl().dom.value =
12223 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12229 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12230 * query allowing the query action to be canceled if needed.
12231 * @param {String} query The SQL query to execute
12232 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12233 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12234 * saved in the current store (defaults to false)
12236 doQuery : function(q, forceAll){
12238 if(q === undefined || q === null){
12243 forceAll: forceAll,
12247 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12252 forceAll = qe.forceAll;
12253 if(forceAll === true || (q.length >= this.minChars)){
12255 this.hasQuery = true;
12257 if(this.lastQuery != q || this.alwaysQuery){
12258 this.lastQuery = q;
12259 if(this.mode == 'local'){
12260 this.selectedIndex = -1;
12262 this.store.clearFilter();
12265 if(this.specialFilter){
12266 this.fireEvent('specialfilter', this);
12271 this.store.filter(this.displayField, q);
12274 this.store.fireEvent("datachanged", this.store);
12281 this.store.baseParams[this.queryParam] = q;
12283 var options = {params : this.getParams(q)};
12286 options.add = true;
12287 options.params.start = this.page * this.pageSize;
12290 this.store.load(options);
12293 * this code will make the page width larger, at the beginning, the list not align correctly,
12294 * we should expand the list on onLoad
12295 * so command out it
12300 this.selectedIndex = -1;
12305 this.loadNext = false;
12309 getParams : function(q){
12311 //p[this.queryParam] = q;
12315 p.limit = this.pageSize;
12321 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12323 collapse : function(){
12324 if(!this.isExpanded()){
12331 this.hasFocus = false;
12333 this.cancelBtn.hide();
12334 this.trigger.show();
12337 this.tickableInputEl().dom.value = '';
12338 this.tickableInputEl().blur();
12343 Roo.get(document).un('mousedown', this.collapseIf, this);
12344 Roo.get(document).un('mousewheel', this.collapseIf, this);
12345 if (!this.editable) {
12346 Roo.get(document).un('keydown', this.listKeyPress, this);
12348 this.fireEvent('collapse', this);
12352 collapseIf : function(e){
12353 var in_combo = e.within(this.el);
12354 var in_list = e.within(this.list);
12355 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12357 if (in_combo || in_list || is_list) {
12358 //e.stopPropagation();
12363 this.onTickableFooterButtonClick(e, false, false);
12371 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12373 expand : function(){
12375 if(this.isExpanded() || !this.hasFocus){
12379 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12380 this.list.setWidth(lw);
12387 this.restrictHeight();
12391 this.tickItems = Roo.apply([], this.item);
12394 this.cancelBtn.show();
12395 this.trigger.hide();
12398 this.tickableInputEl().focus();
12403 Roo.get(document).on('mousedown', this.collapseIf, this);
12404 Roo.get(document).on('mousewheel', this.collapseIf, this);
12405 if (!this.editable) {
12406 Roo.get(document).on('keydown', this.listKeyPress, this);
12409 this.fireEvent('expand', this);
12413 // Implements the default empty TriggerField.onTriggerClick function
12414 onTriggerClick : function(e)
12416 Roo.log('trigger click');
12418 if(this.disabled || !this.triggerList){
12423 this.loadNext = false;
12425 if(this.isExpanded()){
12427 if (!this.blockFocus) {
12428 this.inputEl().focus();
12432 this.hasFocus = true;
12433 if(this.triggerAction == 'all') {
12434 this.doQuery(this.allQuery, true);
12436 this.doQuery(this.getRawValue());
12438 if (!this.blockFocus) {
12439 this.inputEl().focus();
12444 onTickableTriggerClick : function(e)
12451 this.loadNext = false;
12452 this.hasFocus = true;
12454 if(this.triggerAction == 'all') {
12455 this.doQuery(this.allQuery, true);
12457 this.doQuery(this.getRawValue());
12461 onSearchFieldClick : function(e)
12463 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12464 this.onTickableFooterButtonClick(e, false, false);
12468 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12473 this.loadNext = false;
12474 this.hasFocus = true;
12476 if(this.triggerAction == 'all') {
12477 this.doQuery(this.allQuery, true);
12479 this.doQuery(this.getRawValue());
12483 listKeyPress : function(e)
12485 //Roo.log('listkeypress');
12486 // scroll to first matching element based on key pres..
12487 if (e.isSpecialKey()) {
12490 var k = String.fromCharCode(e.getKey()).toUpperCase();
12493 var csel = this.view.getSelectedNodes();
12494 var cselitem = false;
12496 var ix = this.view.indexOf(csel[0]);
12497 cselitem = this.store.getAt(ix);
12498 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12504 this.store.each(function(v) {
12506 // start at existing selection.
12507 if (cselitem.id == v.id) {
12513 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12514 match = this.store.indexOf(v);
12520 if (match === false) {
12521 return true; // no more action?
12524 this.view.select(match);
12525 var sn = Roo.get(this.view.getSelectedNodes()[0])
12526 sn.scrollIntoView(sn.dom.parentNode, false);
12529 onViewScroll : function(e, t){
12531 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){
12535 this.hasQuery = true;
12537 this.loading = this.list.select('.loading', true).first();
12539 if(this.loading === null){
12540 this.list.createChild({
12542 cls: 'loading select2-more-results select2-active',
12543 html: 'Loading more results...'
12546 this.loading = this.list.select('.loading', true).first();
12548 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12550 this.loading.hide();
12553 this.loading.show();
12558 this.loadNext = true;
12560 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12565 addItem : function(o)
12567 var dv = ''; // display value
12569 if (this.displayField) {
12570 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12572 // this is an error condition!!!
12573 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12580 var choice = this.choices.createChild({
12582 cls: 'select2-search-choice',
12591 cls: 'select2-search-choice-close',
12596 }, this.searchField);
12598 var close = choice.select('a.select2-search-choice-close', true).first()
12600 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12608 this.inputEl().dom.value = '';
12613 onRemoveItem : function(e, _self, o)
12615 e.preventDefault();
12617 this.lastItem = Roo.apply([], this.item);
12619 var index = this.item.indexOf(o.data) * 1;
12622 Roo.log('not this item?!');
12626 this.item.splice(index, 1);
12631 this.fireEvent('remove', this, e);
12637 syncValue : function()
12639 if(!this.item.length){
12646 Roo.each(this.item, function(i){
12647 if(_this.valueField){
12648 value.push(i[_this.valueField]);
12655 this.value = value.join(',');
12657 if(this.hiddenField){
12658 this.hiddenField.dom.value = this.value;
12661 this.store.fireEvent("datachanged", this.store);
12664 clearItem : function()
12666 if(!this.multiple){
12672 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12681 inputEl: function ()
12684 return this.searchField;
12686 return this.el.select('input.form-control',true).first();
12690 onTickableFooterButtonClick : function(e, btn, el)
12692 e.preventDefault();
12694 this.lastItem = Roo.apply([], this.item);
12696 if(btn && btn.name == 'cancel'){
12697 this.tickItems = Roo.apply([], this.item);
12706 Roo.each(this.tickItems, function(o){
12714 validate : function()
12716 var v = this.getRawValue();
12719 v = this.getValue();
12722 if(this.disabled || this.allowBlank || v.length){
12727 this.markInvalid();
12731 tickableInputEl : function()
12733 if(!this.tickable || !this.editable){
12734 return this.inputEl();
12737 return this.inputEl().select('.select2-search-field-input', true).first();
12743 * @cfg {Boolean} grow
12747 * @cfg {Number} growMin
12751 * @cfg {Number} growMax
12761 * Ext JS Library 1.1.1
12762 * Copyright(c) 2006-2007, Ext JS, LLC.
12764 * Originally Released Under LGPL - original licence link has changed is not relivant.
12767 * <script type="text/javascript">
12772 * @extends Roo.util.Observable
12773 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12774 * This class also supports single and multi selection modes. <br>
12775 * Create a data model bound view:
12777 var store = new Roo.data.Store(...);
12779 var view = new Roo.View({
12781 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12783 singleSelect: true,
12784 selectedClass: "ydataview-selected",
12788 // listen for node click?
12789 view.on("click", function(vw, index, node, e){
12790 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12794 dataModel.load("foobar.xml");
12796 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12798 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12799 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12801 * Note: old style constructor is still suported (container, template, config)
12804 * Create a new View
12805 * @param {Object} config The config object
12808 Roo.View = function(config, depreciated_tpl, depreciated_config){
12810 this.parent = false;
12812 if (typeof(depreciated_tpl) == 'undefined') {
12813 // new way.. - universal constructor.
12814 Roo.apply(this, config);
12815 this.el = Roo.get(this.el);
12818 this.el = Roo.get(config);
12819 this.tpl = depreciated_tpl;
12820 Roo.apply(this, depreciated_config);
12822 this.wrapEl = this.el.wrap().wrap();
12823 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12826 if(typeof(this.tpl) == "string"){
12827 this.tpl = new Roo.Template(this.tpl);
12829 // support xtype ctors..
12830 this.tpl = new Roo.factory(this.tpl, Roo);
12834 this.tpl.compile();
12839 * @event beforeclick
12840 * Fires before a click is processed. Returns false to cancel the default action.
12841 * @param {Roo.View} this
12842 * @param {Number} index The index of the target node
12843 * @param {HTMLElement} node The target node
12844 * @param {Roo.EventObject} e The raw event object
12846 "beforeclick" : true,
12849 * Fires when a template node is clicked.
12850 * @param {Roo.View} this
12851 * @param {Number} index The index of the target node
12852 * @param {HTMLElement} node The target node
12853 * @param {Roo.EventObject} e The raw event object
12858 * Fires when a template node is double clicked.
12859 * @param {Roo.View} this
12860 * @param {Number} index The index of the target node
12861 * @param {HTMLElement} node The target node
12862 * @param {Roo.EventObject} e The raw event object
12866 * @event contextmenu
12867 * Fires when a template node is right clicked.
12868 * @param {Roo.View} this
12869 * @param {Number} index The index of the target node
12870 * @param {HTMLElement} node The target node
12871 * @param {Roo.EventObject} e The raw event object
12873 "contextmenu" : true,
12875 * @event selectionchange
12876 * Fires when the selected nodes change.
12877 * @param {Roo.View} this
12878 * @param {Array} selections Array of the selected nodes
12880 "selectionchange" : true,
12883 * @event beforeselect
12884 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12885 * @param {Roo.View} this
12886 * @param {HTMLElement} node The node to be selected
12887 * @param {Array} selections Array of currently selected nodes
12889 "beforeselect" : true,
12891 * @event preparedata
12892 * Fires on every row to render, to allow you to change the data.
12893 * @param {Roo.View} this
12894 * @param {Object} data to be rendered (change this)
12896 "preparedata" : true
12904 "click": this.onClick,
12905 "dblclick": this.onDblClick,
12906 "contextmenu": this.onContextMenu,
12910 this.selections = [];
12912 this.cmp = new Roo.CompositeElementLite([]);
12914 this.store = Roo.factory(this.store, Roo.data);
12915 this.setStore(this.store, true);
12918 if ( this.footer && this.footer.xtype) {
12920 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12922 this.footer.dataSource = this.store
12923 this.footer.container = fctr;
12924 this.footer = Roo.factory(this.footer, Roo);
12925 fctr.insertFirst(this.el);
12927 // this is a bit insane - as the paging toolbar seems to detach the el..
12928 // dom.parentNode.parentNode.parentNode
12929 // they get detached?
12933 Roo.View.superclass.constructor.call(this);
12938 Roo.extend(Roo.View, Roo.util.Observable, {
12941 * @cfg {Roo.data.Store} store Data store to load data from.
12946 * @cfg {String|Roo.Element} el The container element.
12951 * @cfg {String|Roo.Template} tpl The template used by this View
12955 * @cfg {String} dataName the named area of the template to use as the data area
12956 * Works with domtemplates roo-name="name"
12960 * @cfg {String} selectedClass The css class to add to selected nodes
12962 selectedClass : "x-view-selected",
12964 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12969 * @cfg {String} text to display on mask (default Loading)
12973 * @cfg {Boolean} multiSelect Allow multiple selection
12975 multiSelect : false,
12977 * @cfg {Boolean} singleSelect Allow single selection
12979 singleSelect: false,
12982 * @cfg {Boolean} toggleSelect - selecting
12984 toggleSelect : false,
12987 * @cfg {Boolean} tickable - selecting
12992 * Returns the element this view is bound to.
12993 * @return {Roo.Element}
12995 getEl : function(){
12996 return this.wrapEl;
13002 * Refreshes the view. - called by datachanged on the store. - do not call directly.
13004 refresh : function(){
13005 //Roo.log('refresh');
13008 // if we are using something like 'domtemplate', then
13009 // the what gets used is:
13010 // t.applySubtemplate(NAME, data, wrapping data..)
13011 // the outer template then get' applied with
13012 // the store 'extra data'
13013 // and the body get's added to the
13014 // roo-name="data" node?
13015 // <span class='roo-tpl-{name}'></span> ?????
13019 this.clearSelections();
13020 this.el.update("");
13022 var records = this.store.getRange();
13023 if(records.length < 1) {
13025 // is this valid?? = should it render a template??
13027 this.el.update(this.emptyText);
13031 if (this.dataName) {
13032 this.el.update(t.apply(this.store.meta)); //????
13033 el = this.el.child('.roo-tpl-' + this.dataName);
13036 for(var i = 0, len = records.length; i < len; i++){
13037 var data = this.prepareData(records[i].data, i, records[i]);
13038 this.fireEvent("preparedata", this, data, i, records[i]);
13040 var d = Roo.apply({}, data);
13043 Roo.apply(d, {'roo-id' : Roo.id()});
13047 Roo.each(this.parent.item, function(item){
13048 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
13051 Roo.apply(d, {'roo-data-checked' : 'checked'});
13055 html[html.length] = Roo.util.Format.trim(
13057 t.applySubtemplate(this.dataName, d, this.store.meta) :
13064 el.update(html.join(""));
13065 this.nodes = el.dom.childNodes;
13066 this.updateIndexes(0);
13071 * Function to override to reformat the data that is sent to
13072 * the template for each node.
13073 * DEPRICATED - use the preparedata event handler.
13074 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
13075 * a JSON object for an UpdateManager bound view).
13077 prepareData : function(data, index, record)
13079 this.fireEvent("preparedata", this, data, index, record);
13083 onUpdate : function(ds, record){
13084 // Roo.log('on update');
13085 this.clearSelections();
13086 var index = this.store.indexOf(record);
13087 var n = this.nodes[index];
13088 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
13089 n.parentNode.removeChild(n);
13090 this.updateIndexes(index, index);
13096 onAdd : function(ds, records, index)
13098 //Roo.log(['on Add', ds, records, index] );
13099 this.clearSelections();
13100 if(this.nodes.length == 0){
13104 var n = this.nodes[index];
13105 for(var i = 0, len = records.length; i < len; i++){
13106 var d = this.prepareData(records[i].data, i, records[i]);
13108 this.tpl.insertBefore(n, d);
13111 this.tpl.append(this.el, d);
13114 this.updateIndexes(index);
13117 onRemove : function(ds, record, index){
13118 // Roo.log('onRemove');
13119 this.clearSelections();
13120 var el = this.dataName ?
13121 this.el.child('.roo-tpl-' + this.dataName) :
13124 el.dom.removeChild(this.nodes[index]);
13125 this.updateIndexes(index);
13129 * Refresh an individual node.
13130 * @param {Number} index
13132 refreshNode : function(index){
13133 this.onUpdate(this.store, this.store.getAt(index));
13136 updateIndexes : function(startIndex, endIndex){
13137 var ns = this.nodes;
13138 startIndex = startIndex || 0;
13139 endIndex = endIndex || ns.length - 1;
13140 for(var i = startIndex; i <= endIndex; i++){
13141 ns[i].nodeIndex = i;
13146 * Changes the data store this view uses and refresh the view.
13147 * @param {Store} store
13149 setStore : function(store, initial){
13150 if(!initial && this.store){
13151 this.store.un("datachanged", this.refresh);
13152 this.store.un("add", this.onAdd);
13153 this.store.un("remove", this.onRemove);
13154 this.store.un("update", this.onUpdate);
13155 this.store.un("clear", this.refresh);
13156 this.store.un("beforeload", this.onBeforeLoad);
13157 this.store.un("load", this.onLoad);
13158 this.store.un("loadexception", this.onLoad);
13162 store.on("datachanged", this.refresh, this);
13163 store.on("add", this.onAdd, this);
13164 store.on("remove", this.onRemove, this);
13165 store.on("update", this.onUpdate, this);
13166 store.on("clear", this.refresh, this);
13167 store.on("beforeload", this.onBeforeLoad, this);
13168 store.on("load", this.onLoad, this);
13169 store.on("loadexception", this.onLoad, this);
13177 * onbeforeLoad - masks the loading area.
13180 onBeforeLoad : function(store,opts)
13182 //Roo.log('onBeforeLoad');
13184 this.el.update("");
13186 this.el.mask(this.mask ? this.mask : "Loading" );
13188 onLoad : function ()
13195 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13196 * @param {HTMLElement} node
13197 * @return {HTMLElement} The template node
13199 findItemFromChild : function(node){
13200 var el = this.dataName ?
13201 this.el.child('.roo-tpl-' + this.dataName,true) :
13204 if(!node || node.parentNode == el){
13207 var p = node.parentNode;
13208 while(p && p != el){
13209 if(p.parentNode == el){
13218 onClick : function(e){
13219 var item = this.findItemFromChild(e.getTarget());
13221 var index = this.indexOf(item);
13222 if(this.onItemClick(item, index, e) !== false){
13223 this.fireEvent("click", this, index, item, e);
13226 this.clearSelections();
13231 onContextMenu : function(e){
13232 var item = this.findItemFromChild(e.getTarget());
13234 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13239 onDblClick : function(e){
13240 var item = this.findItemFromChild(e.getTarget());
13242 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13246 onItemClick : function(item, index, e)
13248 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13251 if (this.toggleSelect) {
13252 var m = this.isSelected(item) ? 'unselect' : 'select';
13255 _t[m](item, true, false);
13258 if(this.multiSelect || this.singleSelect){
13259 if(this.multiSelect && e.shiftKey && this.lastSelection){
13260 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13262 this.select(item, this.multiSelect && e.ctrlKey);
13263 this.lastSelection = item;
13266 if(!this.tickable){
13267 e.preventDefault();
13275 * Get the number of selected nodes.
13278 getSelectionCount : function(){
13279 return this.selections.length;
13283 * Get the currently selected nodes.
13284 * @return {Array} An array of HTMLElements
13286 getSelectedNodes : function(){
13287 return this.selections;
13291 * Get the indexes of the selected nodes.
13294 getSelectedIndexes : function(){
13295 var indexes = [], s = this.selections;
13296 for(var i = 0, len = s.length; i < len; i++){
13297 indexes.push(s[i].nodeIndex);
13303 * Clear all selections
13304 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13306 clearSelections : function(suppressEvent){
13307 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13308 this.cmp.elements = this.selections;
13309 this.cmp.removeClass(this.selectedClass);
13310 this.selections = [];
13311 if(!suppressEvent){
13312 this.fireEvent("selectionchange", this, this.selections);
13318 * Returns true if the passed node is selected
13319 * @param {HTMLElement/Number} node The node or node index
13320 * @return {Boolean}
13322 isSelected : function(node){
13323 var s = this.selections;
13327 node = this.getNode(node);
13328 return s.indexOf(node) !== -1;
13333 * @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
13334 * @param {Boolean} keepExisting (optional) true to keep existing selections
13335 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13337 select : function(nodeInfo, keepExisting, suppressEvent){
13338 if(nodeInfo instanceof Array){
13340 this.clearSelections(true);
13342 for(var i = 0, len = nodeInfo.length; i < len; i++){
13343 this.select(nodeInfo[i], true, true);
13347 var node = this.getNode(nodeInfo);
13348 if(!node || this.isSelected(node)){
13349 return; // already selected.
13352 this.clearSelections(true);
13355 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13356 Roo.fly(node).addClass(this.selectedClass);
13357 this.selections.push(node);
13358 if(!suppressEvent){
13359 this.fireEvent("selectionchange", this, this.selections);
13367 * @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
13368 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13369 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13371 unselect : function(nodeInfo, keepExisting, suppressEvent)
13373 if(nodeInfo instanceof Array){
13374 Roo.each(this.selections, function(s) {
13375 this.unselect(s, nodeInfo);
13379 var node = this.getNode(nodeInfo);
13380 if(!node || !this.isSelected(node)){
13381 //Roo.log("not selected");
13382 return; // not selected.
13386 Roo.each(this.selections, function(s) {
13388 Roo.fly(node).removeClass(this.selectedClass);
13395 this.selections= ns;
13396 this.fireEvent("selectionchange", this, this.selections);
13400 * Gets a template node.
13401 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13402 * @return {HTMLElement} The node or null if it wasn't found
13404 getNode : function(nodeInfo){
13405 if(typeof nodeInfo == "string"){
13406 return document.getElementById(nodeInfo);
13407 }else if(typeof nodeInfo == "number"){
13408 return this.nodes[nodeInfo];
13414 * Gets a range template nodes.
13415 * @param {Number} startIndex
13416 * @param {Number} endIndex
13417 * @return {Array} An array of nodes
13419 getNodes : function(start, end){
13420 var ns = this.nodes;
13421 start = start || 0;
13422 end = typeof end == "undefined" ? ns.length - 1 : end;
13425 for(var i = start; i <= end; i++){
13429 for(var i = start; i >= end; i--){
13437 * Finds the index of the passed node
13438 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13439 * @return {Number} The index of the node or -1
13441 indexOf : function(node){
13442 node = this.getNode(node);
13443 if(typeof node.nodeIndex == "number"){
13444 return node.nodeIndex;
13446 var ns = this.nodes;
13447 for(var i = 0, len = ns.length; i < len; i++){
13458 * based on jquery fullcalendar
13462 Roo.bootstrap = Roo.bootstrap || {};
13464 * @class Roo.bootstrap.Calendar
13465 * @extends Roo.bootstrap.Component
13466 * Bootstrap Calendar class
13467 * @cfg {Boolean} loadMask (true|false) default false
13468 * @cfg {Object} header generate the user specific header of the calendar, default false
13471 * Create a new Container
13472 * @param {Object} config The config object
13477 Roo.bootstrap.Calendar = function(config){
13478 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13482 * Fires when a date is selected
13483 * @param {DatePicker} this
13484 * @param {Date} date The selected date
13488 * @event monthchange
13489 * Fires when the displayed month changes
13490 * @param {DatePicker} this
13491 * @param {Date} date The selected month
13493 'monthchange': true,
13495 * @event evententer
13496 * Fires when mouse over an event
13497 * @param {Calendar} this
13498 * @param {event} Event
13500 'evententer': true,
13502 * @event eventleave
13503 * Fires when the mouse leaves an
13504 * @param {Calendar} this
13507 'eventleave': true,
13509 * @event eventclick
13510 * Fires when the mouse click an
13511 * @param {Calendar} this
13520 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13523 * @cfg {Number} startDay
13524 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13532 getAutoCreate : function(){
13535 var fc_button = function(name, corner, style, content ) {
13536 return Roo.apply({},{
13538 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13540 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13543 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13554 style : 'width:100%',
13561 cls : 'fc-header-left',
13563 fc_button('prev', 'left', 'arrow', '‹' ),
13564 fc_button('next', 'right', 'arrow', '›' ),
13565 { tag: 'span', cls: 'fc-header-space' },
13566 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13574 cls : 'fc-header-center',
13578 cls: 'fc-header-title',
13581 html : 'month / year'
13589 cls : 'fc-header-right',
13591 /* fc_button('month', 'left', '', 'month' ),
13592 fc_button('week', '', '', 'week' ),
13593 fc_button('day', 'right', '', 'day' )
13605 header = this.header;
13608 var cal_heads = function() {
13610 // fixme - handle this.
13612 for (var i =0; i < Date.dayNames.length; i++) {
13613 var d = Date.dayNames[i];
13616 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13617 html : d.substring(0,3)
13621 ret[0].cls += ' fc-first';
13622 ret[6].cls += ' fc-last';
13625 var cal_cell = function(n) {
13628 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13633 cls: 'fc-day-number',
13637 cls: 'fc-day-content',
13641 style: 'position: relative;' // height: 17px;
13653 var cal_rows = function() {
13656 for (var r = 0; r < 6; r++) {
13663 for (var i =0; i < Date.dayNames.length; i++) {
13664 var d = Date.dayNames[i];
13665 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13668 row.cn[0].cls+=' fc-first';
13669 row.cn[0].cn[0].style = 'min-height:90px';
13670 row.cn[6].cls+=' fc-last';
13674 ret[0].cls += ' fc-first';
13675 ret[4].cls += ' fc-prev-last';
13676 ret[5].cls += ' fc-last';
13683 cls: 'fc-border-separate',
13684 style : 'width:100%',
13692 cls : 'fc-first fc-last',
13710 cls : 'fc-content',
13711 style : "position: relative;",
13714 cls : 'fc-view fc-view-month fc-grid',
13715 style : 'position: relative',
13716 unselectable : 'on',
13719 cls : 'fc-event-container',
13720 style : 'position:absolute;z-index:8;top:0;left:0;'
13738 initEvents : function()
13741 throw "can not find store for calendar";
13747 style: "text-align:center",
13751 style: "background-color:white;width:50%;margin:250 auto",
13755 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13766 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13768 var size = this.el.select('.fc-content', true).first().getSize();
13769 this.maskEl.setSize(size.width, size.height);
13770 this.maskEl.enableDisplayMode("block");
13771 if(!this.loadMask){
13772 this.maskEl.hide();
13775 this.store = Roo.factory(this.store, Roo.data);
13776 this.store.on('load', this.onLoad, this);
13777 this.store.on('beforeload', this.onBeforeLoad, this);
13781 this.cells = this.el.select('.fc-day',true);
13782 //Roo.log(this.cells);
13783 this.textNodes = this.el.query('.fc-day-number');
13784 this.cells.addClassOnOver('fc-state-hover');
13786 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13787 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13788 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13789 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13791 this.on('monthchange', this.onMonthChange, this);
13793 this.update(new Date().clearTime());
13796 resize : function() {
13797 var sz = this.el.getSize();
13799 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13800 this.el.select('.fc-day-content div',true).setHeight(34);
13805 showPrevMonth : function(e){
13806 this.update(this.activeDate.add("mo", -1));
13808 showToday : function(e){
13809 this.update(new Date().clearTime());
13812 showNextMonth : function(e){
13813 this.update(this.activeDate.add("mo", 1));
13817 showPrevYear : function(){
13818 this.update(this.activeDate.add("y", -1));
13822 showNextYear : function(){
13823 this.update(this.activeDate.add("y", 1));
13828 update : function(date)
13830 var vd = this.activeDate;
13831 this.activeDate = date;
13832 // if(vd && this.el){
13833 // var t = date.getTime();
13834 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13835 // Roo.log('using add remove');
13837 // this.fireEvent('monthchange', this, date);
13839 // this.cells.removeClass("fc-state-highlight");
13840 // this.cells.each(function(c){
13841 // if(c.dateValue == t){
13842 // c.addClass("fc-state-highlight");
13843 // setTimeout(function(){
13844 // try{c.dom.firstChild.focus();}catch(e){}
13854 var days = date.getDaysInMonth();
13856 var firstOfMonth = date.getFirstDateOfMonth();
13857 var startingPos = firstOfMonth.getDay()-this.startDay;
13859 if(startingPos < this.startDay){
13863 var pm = date.add(Date.MONTH, -1);
13864 var prevStart = pm.getDaysInMonth()-startingPos;
13866 this.cells = this.el.select('.fc-day',true);
13867 this.textNodes = this.el.query('.fc-day-number');
13868 this.cells.addClassOnOver('fc-state-hover');
13870 var cells = this.cells.elements;
13871 var textEls = this.textNodes;
13873 Roo.each(cells, function(cell){
13874 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13877 days += startingPos;
13879 // convert everything to numbers so it's fast
13880 var day = 86400000;
13881 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13884 //Roo.log(prevStart);
13886 var today = new Date().clearTime().getTime();
13887 var sel = date.clearTime().getTime();
13888 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13889 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13890 var ddMatch = this.disabledDatesRE;
13891 var ddText = this.disabledDatesText;
13892 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13893 var ddaysText = this.disabledDaysText;
13894 var format = this.format;
13896 var setCellClass = function(cal, cell){
13900 //Roo.log('set Cell Class');
13902 var t = d.getTime();
13906 cell.dateValue = t;
13908 cell.className += " fc-today";
13909 cell.className += " fc-state-highlight";
13910 cell.title = cal.todayText;
13913 // disable highlight in other month..
13914 //cell.className += " fc-state-highlight";
13919 cell.className = " fc-state-disabled";
13920 cell.title = cal.minText;
13924 cell.className = " fc-state-disabled";
13925 cell.title = cal.maxText;
13929 if(ddays.indexOf(d.getDay()) != -1){
13930 cell.title = ddaysText;
13931 cell.className = " fc-state-disabled";
13934 if(ddMatch && format){
13935 var fvalue = d.dateFormat(format);
13936 if(ddMatch.test(fvalue)){
13937 cell.title = ddText.replace("%0", fvalue);
13938 cell.className = " fc-state-disabled";
13942 if (!cell.initialClassName) {
13943 cell.initialClassName = cell.dom.className;
13946 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13951 for(; i < startingPos; i++) {
13952 textEls[i].innerHTML = (++prevStart);
13953 d.setDate(d.getDate()+1);
13955 cells[i].className = "fc-past fc-other-month";
13956 setCellClass(this, cells[i]);
13961 for(; i < days; i++){
13962 intDay = i - startingPos + 1;
13963 textEls[i].innerHTML = (intDay);
13964 d.setDate(d.getDate()+1);
13966 cells[i].className = ''; // "x-date-active";
13967 setCellClass(this, cells[i]);
13971 for(; i < 42; i++) {
13972 textEls[i].innerHTML = (++extraDays);
13973 d.setDate(d.getDate()+1);
13975 cells[i].className = "fc-future fc-other-month";
13976 setCellClass(this, cells[i]);
13979 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
13981 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
13983 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
13984 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
13986 if(totalRows != 6){
13987 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
13988 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
13991 this.fireEvent('monthchange', this, date);
13995 if(!this.internalRender){
13996 var main = this.el.dom.firstChild;
13997 var w = main.offsetWidth;
13998 this.el.setWidth(w + this.el.getBorderWidth("lr"));
13999 Roo.fly(main).setWidth(w);
14000 this.internalRender = true;
14001 // opera does not respect the auto grow header center column
14002 // then, after it gets a width opera refuses to recalculate
14003 // without a second pass
14004 if(Roo.isOpera && !this.secondPass){
14005 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
14006 this.secondPass = true;
14007 this.update.defer(10, this, [date]);
14014 findCell : function(dt) {
14015 dt = dt.clearTime().getTime();
14017 this.cells.each(function(c){
14018 //Roo.log("check " +c.dateValue + '?=' + dt);
14019 if(c.dateValue == dt){
14029 findCells : function(ev) {
14030 var s = ev.start.clone().clearTime().getTime();
14032 var e= ev.end.clone().clearTime().getTime();
14035 this.cells.each(function(c){
14036 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
14038 if(c.dateValue > e){
14041 if(c.dateValue < s){
14050 // findBestRow: function(cells)
14054 // for (var i =0 ; i < cells.length;i++) {
14055 // ret = Math.max(cells[i].rows || 0,ret);
14062 addItem : function(ev)
14064 // look for vertical location slot in
14065 var cells = this.findCells(ev);
14067 // ev.row = this.findBestRow(cells);
14069 // work out the location.
14073 for(var i =0; i < cells.length; i++) {
14075 cells[i].row = cells[0].row;
14078 cells[i].row = cells[i].row + 1;
14088 if (crow.start.getY() == cells[i].getY()) {
14090 crow.end = cells[i];
14107 cells[0].events.push(ev);
14109 this.calevents.push(ev);
14112 clearEvents: function() {
14114 if(!this.calevents){
14118 Roo.each(this.cells.elements, function(c){
14124 Roo.each(this.calevents, function(e) {
14125 Roo.each(e.els, function(el) {
14126 el.un('mouseenter' ,this.onEventEnter, this);
14127 el.un('mouseleave' ,this.onEventLeave, this);
14132 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14138 renderEvents: function()
14142 this.cells.each(function(c) {
14151 if(c.row != c.events.length){
14152 r = 4 - (4 - (c.row - c.events.length));
14155 c.events = ev.slice(0, r);
14156 c.more = ev.slice(r);
14158 if(c.more.length && c.more.length == 1){
14159 c.events.push(c.more.pop());
14162 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14166 this.cells.each(function(c) {
14168 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14171 for (var e = 0; e < c.events.length; e++){
14172 var ev = c.events[e];
14173 var rows = ev.rows;
14175 for(var i = 0; i < rows.length; i++) {
14177 // how many rows should it span..
14180 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14181 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14183 unselectable : "on",
14186 cls: 'fc-event-inner',
14190 // cls: 'fc-event-time',
14191 // html : cells.length > 1 ? '' : ev.time
14195 cls: 'fc-event-title',
14196 html : String.format('{0}', ev.title)
14203 cls: 'ui-resizable-handle ui-resizable-e',
14204 html : '  '
14211 cfg.cls += ' fc-event-start';
14213 if ((i+1) == rows.length) {
14214 cfg.cls += ' fc-event-end';
14217 var ctr = _this.el.select('.fc-event-container',true).first();
14218 var cg = ctr.createChild(cfg);
14220 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14221 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14223 var r = (c.more.length) ? 1 : 0;
14224 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14225 cg.setWidth(ebox.right - sbox.x -2);
14227 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14228 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14229 cg.on('click', _this.onEventClick, _this, ev);
14240 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14241 style : 'position: absolute',
14242 unselectable : "on",
14245 cls: 'fc-event-inner',
14249 cls: 'fc-event-title',
14257 cls: 'ui-resizable-handle ui-resizable-e',
14258 html : '  '
14264 var ctr = _this.el.select('.fc-event-container',true).first();
14265 var cg = ctr.createChild(cfg);
14267 var sbox = c.select('.fc-day-content',true).first().getBox();
14268 var ebox = c.select('.fc-day-content',true).first().getBox();
14270 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14271 cg.setWidth(ebox.right - sbox.x -2);
14273 cg.on('click', _this.onMoreEventClick, _this, c.more);
14283 onEventEnter: function (e, el,event,d) {
14284 this.fireEvent('evententer', this, el, event);
14287 onEventLeave: function (e, el,event,d) {
14288 this.fireEvent('eventleave', this, el, event);
14291 onEventClick: function (e, el,event,d) {
14292 this.fireEvent('eventclick', this, el, event);
14295 onMonthChange: function () {
14299 onMoreEventClick: function(e, el, more)
14303 this.calpopover.placement = 'right';
14304 this.calpopover.setTitle('More');
14306 this.calpopover.setContent('');
14308 var ctr = this.calpopover.el.select('.popover-content', true).first();
14310 Roo.each(more, function(m){
14312 cls : 'fc-event-hori fc-event-draggable',
14315 var cg = ctr.createChild(cfg);
14317 cg.on('click', _this.onEventClick, _this, m);
14320 this.calpopover.show(el);
14325 onLoad: function ()
14327 this.calevents = [];
14330 if(this.store.getCount() > 0){
14331 this.store.data.each(function(d){
14334 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14335 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14336 time : d.data.start_time,
14337 title : d.data.title,
14338 description : d.data.description,
14339 venue : d.data.venue
14344 this.renderEvents();
14346 if(this.calevents.length && this.loadMask){
14347 this.maskEl.hide();
14351 onBeforeLoad: function()
14353 this.clearEvents();
14355 this.maskEl.show();
14369 * @class Roo.bootstrap.Popover
14370 * @extends Roo.bootstrap.Component
14371 * Bootstrap Popover class
14372 * @cfg {String} html contents of the popover (or false to use children..)
14373 * @cfg {String} title of popover (or false to hide)
14374 * @cfg {String} placement how it is placed
14375 * @cfg {String} trigger click || hover (or false to trigger manually)
14376 * @cfg {String} over what (parent or false to trigger manually.)
14377 * @cfg {Number} delay - delay before showing
14380 * Create a new Popover
14381 * @param {Object} config The config object
14384 Roo.bootstrap.Popover = function(config){
14385 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14388 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14390 title: 'Fill in a title',
14393 placement : 'right',
14394 trigger : 'hover', // hover
14400 can_build_overlaid : false,
14402 getChildContainer : function()
14404 return this.el.select('.popover-content',true).first();
14407 getAutoCreate : function(){
14408 Roo.log('make popover?');
14410 cls : 'popover roo-dynamic',
14411 style: 'display:block',
14417 cls : 'popover-inner',
14421 cls: 'popover-title',
14425 cls : 'popover-content',
14436 setTitle: function(str)
14438 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14440 setContent: function(str)
14442 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14444 // as it get's added to the bottom of the page.
14445 onRender : function(ct, position)
14447 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14449 var cfg = Roo.apply({}, this.getAutoCreate());
14453 cfg.cls += ' ' + this.cls;
14456 cfg.style = this.style;
14458 Roo.log("adding to ")
14459 this.el = Roo.get(document.body).createChild(cfg, position);
14465 initEvents : function()
14467 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14468 this.el.enableDisplayMode('block');
14470 if (this.over === false) {
14473 if (this.triggers === false) {
14476 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14477 var triggers = this.trigger ? this.trigger.split(' ') : [];
14478 Roo.each(triggers, function(trigger) {
14480 if (trigger == 'click') {
14481 on_el.on('click', this.toggle, this);
14482 } else if (trigger != 'manual') {
14483 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14484 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14486 on_el.on(eventIn ,this.enter, this);
14487 on_el.on(eventOut, this.leave, this);
14498 toggle : function () {
14499 this.hoverState == 'in' ? this.leave() : this.enter();
14502 enter : function () {
14505 clearTimeout(this.timeout);
14507 this.hoverState = 'in';
14509 if (!this.delay || !this.delay.show) {
14514 this.timeout = setTimeout(function () {
14515 if (_t.hoverState == 'in') {
14518 }, this.delay.show)
14520 leave : function() {
14521 clearTimeout(this.timeout);
14523 this.hoverState = 'out';
14525 if (!this.delay || !this.delay.hide) {
14530 this.timeout = setTimeout(function () {
14531 if (_t.hoverState == 'out') {
14534 }, this.delay.hide)
14537 show : function (on_el)
14540 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14543 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14544 if (this.html !== false) {
14545 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14547 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14548 if (!this.title.length) {
14549 this.el.select('.popover-title',true).hide();
14552 var placement = typeof this.placement == 'function' ?
14553 this.placement.call(this, this.el, on_el) :
14556 var autoToken = /\s?auto?\s?/i;
14557 var autoPlace = autoToken.test(placement);
14559 placement = placement.replace(autoToken, '') || 'top';
14563 //this.el.setXY([0,0]);
14565 this.el.dom.style.display='block';
14566 this.el.addClass(placement);
14568 //this.el.appendTo(on_el);
14570 var p = this.getPosition();
14571 var box = this.el.getBox();
14576 var align = Roo.bootstrap.Popover.alignment[placement];
14577 this.el.alignTo(on_el, align[0],align[1]);
14578 //var arrow = this.el.select('.arrow',true).first();
14579 //arrow.set(align[2],
14581 this.el.addClass('in');
14582 this.hoverState = null;
14584 if (this.el.hasClass('fade')) {
14591 this.el.setXY([0,0]);
14592 this.el.removeClass('in');
14599 Roo.bootstrap.Popover.alignment = {
14600 'left' : ['r-l', [-10,0], 'right'],
14601 'right' : ['l-r', [10,0], 'left'],
14602 'bottom' : ['t-b', [0,10], 'top'],
14603 'top' : [ 'b-t', [0,-10], 'bottom']
14614 * @class Roo.bootstrap.Progress
14615 * @extends Roo.bootstrap.Component
14616 * Bootstrap Progress class
14617 * @cfg {Boolean} striped striped of the progress bar
14618 * @cfg {Boolean} active animated of the progress bar
14622 * Create a new Progress
14623 * @param {Object} config The config object
14626 Roo.bootstrap.Progress = function(config){
14627 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14630 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14635 getAutoCreate : function(){
14643 cfg.cls += ' progress-striped';
14647 cfg.cls += ' active';
14666 * @class Roo.bootstrap.ProgressBar
14667 * @extends Roo.bootstrap.Component
14668 * Bootstrap ProgressBar class
14669 * @cfg {Number} aria_valuenow aria-value now
14670 * @cfg {Number} aria_valuemin aria-value min
14671 * @cfg {Number} aria_valuemax aria-value max
14672 * @cfg {String} label label for the progress bar
14673 * @cfg {String} panel (success | info | warning | danger )
14674 * @cfg {String} role role of the progress bar
14675 * @cfg {String} sr_only text
14679 * Create a new ProgressBar
14680 * @param {Object} config The config object
14683 Roo.bootstrap.ProgressBar = function(config){
14684 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14687 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14691 aria_valuemax : 100,
14697 getAutoCreate : function()
14702 cls: 'progress-bar',
14703 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14715 cfg.role = this.role;
14718 if(this.aria_valuenow){
14719 cfg['aria-valuenow'] = this.aria_valuenow;
14722 if(this.aria_valuemin){
14723 cfg['aria-valuemin'] = this.aria_valuemin;
14726 if(this.aria_valuemax){
14727 cfg['aria-valuemax'] = this.aria_valuemax;
14730 if(this.label && !this.sr_only){
14731 cfg.html = this.label;
14735 cfg.cls += ' progress-bar-' + this.panel;
14741 update : function(aria_valuenow)
14743 this.aria_valuenow = aria_valuenow;
14745 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14760 * @class Roo.bootstrap.TabGroup
14761 * @extends Roo.bootstrap.Column
14762 * Bootstrap Column class
14763 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14764 * @cfg {Boolean} carousel true to make the group behave like a carousel
14765 * @cfg {Number} bullets show the panel pointer.. default 0
14766 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
14767 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
14768 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14771 * Create a new TabGroup
14772 * @param {Object} config The config object
14775 Roo.bootstrap.TabGroup = function(config){
14776 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14778 this.navId = Roo.id();
14781 Roo.bootstrap.TabGroup.register(this);
14785 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14788 transition : false,
14793 slideOnTouch : false,
14795 getAutoCreate : function()
14797 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14799 cfg.cls += ' tab-content';
14801 Roo.log('get auto create...............');
14803 if (this.carousel) {
14804 cfg.cls += ' carousel slide';
14807 cls : 'carousel-inner'
14810 if(this.bullets > 0 && !Roo.isTouch){
14813 cls : 'carousel-bullets',
14817 if(this.bullets_cls){
14818 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14821 for (var i = 0; i < this.bullets; i++){
14823 cls : 'bullet bullet-' + i
14831 cfg.cn[0].cn = bullets;
14838 initEvents: function()
14840 Roo.log('-------- init events on tab group ---------');
14842 if(this.bullets > 0 && !Roo.isTouch){
14848 if(Roo.isTouch && this.slideOnTouch){
14849 this.el.on("touchstart", this.onTouchStart, this);
14852 if(this.autoslide){
14855 this.slideFn = window.setInterval(function() {
14856 _this.showPanelNext();
14862 onTouchStart : function(e, el, o)
14864 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
14868 this.showPanelNext();
14871 getChildContainer : function()
14873 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14877 * register a Navigation item
14878 * @param {Roo.bootstrap.NavItem} the navitem to add
14880 register : function(item)
14882 this.tabs.push( item);
14883 item.navId = this.navId; // not really needed..
14887 getActivePanel : function()
14890 Roo.each(this.tabs, function(t) {
14900 getPanelByName : function(n)
14903 Roo.each(this.tabs, function(t) {
14904 if (t.tabId == n) {
14912 indexOfPanel : function(p)
14915 Roo.each(this.tabs, function(t,i) {
14916 if (t.tabId == p.tabId) {
14925 * show a specific panel
14926 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14927 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14929 showPanel : function (pan)
14931 if(this.transition){
14932 Roo.log("waiting for the transitionend");
14936 if (typeof(pan) == 'number') {
14937 pan = this.tabs[pan];
14939 if (typeof(pan) == 'string') {
14940 pan = this.getPanelByName(pan);
14942 if (pan.tabId == this.getActivePanel().tabId) {
14945 var cur = this.getActivePanel();
14947 if (false === cur.fireEvent('beforedeactivate')) {
14951 if(this.bullets > 0 && !Roo.isTouch){
14952 this.setActiveBullet(this.indexOfPanel(pan));
14955 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14957 this.transition = true;
14958 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14959 var lr = dir == 'next' ? 'left' : 'right';
14960 pan.el.addClass(dir); // or prev
14961 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14962 cur.el.addClass(lr); // or right
14963 pan.el.addClass(lr);
14966 cur.el.on('transitionend', function() {
14967 Roo.log("trans end?");
14969 pan.el.removeClass([lr,dir]);
14970 pan.setActive(true);
14972 cur.el.removeClass([lr]);
14973 cur.setActive(false);
14975 _this.transition = false;
14977 }, this, { single: true } );
14982 cur.setActive(false);
14983 pan.setActive(true);
14988 showPanelNext : function()
14990 var i = this.indexOfPanel(this.getActivePanel());
14992 if (i >= this.tabs.length - 1 && !this.autoslide) {
14996 if (i >= this.tabs.length - 1 && this.autoslide) {
15000 this.showPanel(this.tabs[i+1]);
15003 showPanelPrev : function()
15005 var i = this.indexOfPanel(this.getActivePanel());
15007 if (i < 1 && !this.autoslide) {
15011 if (i < 1 && this.autoslide) {
15012 i = this.tabs.length;
15015 this.showPanel(this.tabs[i-1]);
15018 initBullet : function()
15026 for (var i = 0; i < this.bullets; i++){
15027 var bullet = this.el.select('.bullet-' + i, true).first();
15033 bullet.on('click', (function(e, el, o, ii, t){
15035 e.preventDefault();
15037 _this.showPanel(ii);
15039 if(_this.autoslide && _this.slideFn){
15040 clearInterval(_this.slideFn);
15041 _this.slideFn = window.setInterval(function() {
15042 _this.showPanelNext();
15046 }).createDelegate(this, [i, bullet], true));
15050 setActiveBullet : function(i)
15056 Roo.each(this.el.select('.bullet', true).elements, function(el){
15057 el.removeClass('selected');
15060 var bullet = this.el.select('.bullet-' + i, true).first();
15066 bullet.addClass('selected');
15077 Roo.apply(Roo.bootstrap.TabGroup, {
15081 * register a Navigation Group
15082 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15084 register : function(navgrp)
15086 this.groups[navgrp.navId] = navgrp;
15090 * fetch a Navigation Group based on the navigation ID
15091 * if one does not exist , it will get created.
15092 * @param {string} the navgroup to add
15093 * @returns {Roo.bootstrap.NavGroup} the navgroup
15095 get: function(navId) {
15096 if (typeof(this.groups[navId]) == 'undefined') {
15097 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15099 return this.groups[navId] ;
15114 * @class Roo.bootstrap.TabPanel
15115 * @extends Roo.bootstrap.Component
15116 * Bootstrap TabPanel class
15117 * @cfg {Boolean} active panel active
15118 * @cfg {String} html panel content
15119 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15120 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15124 * Create a new TabPanel
15125 * @param {Object} config The config object
15128 Roo.bootstrap.TabPanel = function(config){
15129 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15133 * Fires when the active status changes
15134 * @param {Roo.bootstrap.TabPanel} this
15135 * @param {Boolean} state the new state
15140 * @event beforedeactivate
15141 * Fires before a tab is de-activated - can be used to do validation on a form.
15142 * @param {Roo.bootstrap.TabPanel} this
15143 * @return {Boolean} false if there is an error
15146 'beforedeactivate': true
15149 this.tabId = this.tabId || Roo.id();
15153 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15160 getAutoCreate : function(){
15163 // item is needed for carousel - not sure if it has any effect otherwise
15164 cls: 'tab-pane item',
15165 html: this.html || ''
15169 cfg.cls += ' active';
15173 cfg.tabId = this.tabId;
15180 initEvents: function()
15182 Roo.log('-------- init events on tab panel ---------');
15184 var p = this.parent();
15185 this.navId = this.navId || p.navId;
15187 if (typeof(this.navId) != 'undefined') {
15188 // not really needed.. but just in case.. parent should be a NavGroup.
15189 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15190 Roo.log(['register', tg, this]);
15193 var i = tg.tabs.length - 1;
15195 if(this.active && tg.bullets > 0 && i < tg.bullets){
15196 tg.setActiveBullet(i);
15203 onRender : function(ct, position)
15205 // Roo.log("Call onRender: " + this.xtype);
15207 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15215 setActive: function(state)
15217 Roo.log("panel - set active " + this.tabId + "=" + state);
15219 this.active = state;
15221 this.el.removeClass('active');
15223 } else if (!this.el.hasClass('active')) {
15224 this.el.addClass('active');
15227 this.fireEvent('changed', this, state);
15244 * @class Roo.bootstrap.DateField
15245 * @extends Roo.bootstrap.Input
15246 * Bootstrap DateField class
15247 * @cfg {Number} weekStart default 0
15248 * @cfg {String} viewMode default empty, (months|years)
15249 * @cfg {String} minViewMode default empty, (months|years)
15250 * @cfg {Number} startDate default -Infinity
15251 * @cfg {Number} endDate default Infinity
15252 * @cfg {Boolean} todayHighlight default false
15253 * @cfg {Boolean} todayBtn default false
15254 * @cfg {Boolean} calendarWeeks default false
15255 * @cfg {Object} daysOfWeekDisabled default empty
15256 * @cfg {Boolean} singleMode default false (true | false)
15258 * @cfg {Boolean} keyboardNavigation default true
15259 * @cfg {String} language default en
15262 * Create a new DateField
15263 * @param {Object} config The config object
15266 Roo.bootstrap.DateField = function(config){
15267 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15271 * Fires when this field show.
15272 * @param {Roo.bootstrap.DateField} this
15273 * @param {Mixed} date The date value
15278 * Fires when this field hide.
15279 * @param {Roo.bootstrap.DateField} this
15280 * @param {Mixed} date The date value
15285 * Fires when select a date.
15286 * @param {Roo.bootstrap.DateField} this
15287 * @param {Mixed} date The date value
15293 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15296 * @cfg {String} format
15297 * The default date format string which can be overriden for localization support. The format must be
15298 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15302 * @cfg {String} altFormats
15303 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15304 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15306 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15314 todayHighlight : false,
15320 keyboardNavigation: true,
15322 calendarWeeks: false,
15324 startDate: -Infinity,
15328 daysOfWeekDisabled: [],
15332 singleMode : false,
15334 UTCDate: function()
15336 return new Date(Date.UTC.apply(Date, arguments));
15339 UTCToday: function()
15341 var today = new Date();
15342 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15345 getDate: function() {
15346 var d = this.getUTCDate();
15347 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15350 getUTCDate: function() {
15354 setDate: function(d) {
15355 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15358 setUTCDate: function(d) {
15360 this.setValue(this.formatDate(this.date));
15363 onRender: function(ct, position)
15366 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15368 this.language = this.language || 'en';
15369 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15370 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15372 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15373 this.format = this.format || 'm/d/y';
15374 this.isInline = false;
15375 this.isInput = true;
15376 this.component = this.el.select('.add-on', true).first() || false;
15377 this.component = (this.component && this.component.length === 0) ? false : this.component;
15378 this.hasInput = this.component && this.inputEL().length;
15380 if (typeof(this.minViewMode === 'string')) {
15381 switch (this.minViewMode) {
15383 this.minViewMode = 1;
15386 this.minViewMode = 2;
15389 this.minViewMode = 0;
15394 if (typeof(this.viewMode === 'string')) {
15395 switch (this.viewMode) {
15408 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15410 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15412 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15414 this.picker().on('mousedown', this.onMousedown, this);
15415 this.picker().on('click', this.onClick, this);
15417 this.picker().addClass('datepicker-dropdown');
15419 this.startViewMode = this.viewMode;
15421 if(this.singleMode){
15422 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15423 v.setVisibilityMode(Roo.Element.DISPLAY)
15427 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15428 v.setStyle('width', '189px');
15432 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15433 if(!this.calendarWeeks){
15438 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15439 v.attr('colspan', function(i, val){
15440 return parseInt(val) + 1;
15445 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15447 this.setStartDate(this.startDate);
15448 this.setEndDate(this.endDate);
15450 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15457 if(this.isInline) {
15462 picker : function()
15464 return this.pickerEl;
15465 // return this.el.select('.datepicker', true).first();
15468 fillDow: function()
15470 var dowCnt = this.weekStart;
15479 if(this.calendarWeeks){
15487 while (dowCnt < this.weekStart + 7) {
15491 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15495 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15498 fillMonths: function()
15501 var months = this.picker().select('>.datepicker-months td', true).first();
15503 months.dom.innerHTML = '';
15509 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15512 months.createChild(month);
15519 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;
15521 if (this.date < this.startDate) {
15522 this.viewDate = new Date(this.startDate);
15523 } else if (this.date > this.endDate) {
15524 this.viewDate = new Date(this.endDate);
15526 this.viewDate = new Date(this.date);
15534 var d = new Date(this.viewDate),
15535 year = d.getUTCFullYear(),
15536 month = d.getUTCMonth(),
15537 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15538 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15539 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15540 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15541 currentDate = this.date && this.date.valueOf(),
15542 today = this.UTCToday();
15544 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15546 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15548 // this.picker.select('>tfoot th.today').
15549 // .text(dates[this.language].today)
15550 // .toggle(this.todayBtn !== false);
15552 this.updateNavArrows();
15555 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15557 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15559 prevMonth.setUTCDate(day);
15561 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15563 var nextMonth = new Date(prevMonth);
15565 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15567 nextMonth = nextMonth.valueOf();
15569 var fillMonths = false;
15571 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15573 while(prevMonth.valueOf() < nextMonth) {
15576 if (prevMonth.getUTCDay() === this.weekStart) {
15578 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15586 if(this.calendarWeeks){
15587 // ISO 8601: First week contains first thursday.
15588 // ISO also states week starts on Monday, but we can be more abstract here.
15590 // Start of current week: based on weekstart/current date
15591 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15592 // Thursday of this week
15593 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15594 // First Thursday of year, year from thursday
15595 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15596 // Calendar week: ms between thursdays, div ms per day, div 7 days
15597 calWeek = (th - yth) / 864e5 / 7 + 1;
15599 fillMonths.cn.push({
15607 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15609 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15612 if (this.todayHighlight &&
15613 prevMonth.getUTCFullYear() == today.getFullYear() &&
15614 prevMonth.getUTCMonth() == today.getMonth() &&
15615 prevMonth.getUTCDate() == today.getDate()) {
15616 clsName += ' today';
15619 if (currentDate && prevMonth.valueOf() === currentDate) {
15620 clsName += ' active';
15623 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15624 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15625 clsName += ' disabled';
15628 fillMonths.cn.push({
15630 cls: 'day ' + clsName,
15631 html: prevMonth.getDate()
15634 prevMonth.setDate(prevMonth.getDate()+1);
15637 var currentYear = this.date && this.date.getUTCFullYear();
15638 var currentMonth = this.date && this.date.getUTCMonth();
15640 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15642 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15643 v.removeClass('active');
15645 if(currentYear === year && k === currentMonth){
15646 v.addClass('active');
15649 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15650 v.addClass('disabled');
15656 year = parseInt(year/10, 10) * 10;
15658 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15660 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15663 for (var i = -1; i < 11; i++) {
15664 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15666 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15674 showMode: function(dir)
15677 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15680 Roo.each(this.picker().select('>div',true).elements, function(v){
15681 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15684 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15689 if(this.isInline) return;
15691 this.picker().removeClass(['bottom', 'top']);
15693 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15695 * place to the top of element!
15699 this.picker().addClass('top');
15700 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15705 this.picker().addClass('bottom');
15707 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15710 parseDate : function(value)
15712 if(!value || value instanceof Date){
15715 var v = Date.parseDate(value, this.format);
15716 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15717 v = Date.parseDate(value, 'Y-m-d');
15719 if(!v && this.altFormats){
15720 if(!this.altFormatsArray){
15721 this.altFormatsArray = this.altFormats.split("|");
15723 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15724 v = Date.parseDate(value, this.altFormatsArray[i]);
15730 formatDate : function(date, fmt)
15732 return (!date || !(date instanceof Date)) ?
15733 date : date.dateFormat(fmt || this.format);
15736 onFocus : function()
15738 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15742 onBlur : function()
15744 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15746 var d = this.inputEl().getValue();
15755 this.picker().show();
15759 this.fireEvent('show', this, this.date);
15764 if(this.isInline) return;
15765 this.picker().hide();
15766 this.viewMode = this.startViewMode;
15769 this.fireEvent('hide', this, this.date);
15773 onMousedown: function(e)
15775 e.stopPropagation();
15776 e.preventDefault();
15781 Roo.bootstrap.DateField.superclass.keyup.call(this);
15785 setValue: function(v)
15788 // v can be a string or a date..
15791 var d = new Date(this.parseDate(v) ).clearTime();
15793 if(isNaN(d.getTime())){
15794 this.date = this.viewDate = '';
15795 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15799 v = this.formatDate(d);
15801 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15803 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15807 this.fireEvent('select', this, this.date);
15811 getValue: function()
15813 return this.formatDate(this.date);
15816 fireKey: function(e)
15818 if (!this.picker().isVisible()){
15819 if (e.keyCode == 27) // allow escape to hide and re-show picker
15824 var dateChanged = false,
15826 newDate, newViewDate;
15831 e.preventDefault();
15835 if (!this.keyboardNavigation) break;
15836 dir = e.keyCode == 37 ? -1 : 1;
15839 newDate = this.moveYear(this.date, dir);
15840 newViewDate = this.moveYear(this.viewDate, dir);
15841 } else if (e.shiftKey){
15842 newDate = this.moveMonth(this.date, dir);
15843 newViewDate = this.moveMonth(this.viewDate, dir);
15845 newDate = new Date(this.date);
15846 newDate.setUTCDate(this.date.getUTCDate() + dir);
15847 newViewDate = new Date(this.viewDate);
15848 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15850 if (this.dateWithinRange(newDate)){
15851 this.date = newDate;
15852 this.viewDate = newViewDate;
15853 this.setValue(this.formatDate(this.date));
15855 e.preventDefault();
15856 dateChanged = true;
15861 if (!this.keyboardNavigation) break;
15862 dir = e.keyCode == 38 ? -1 : 1;
15864 newDate = this.moveYear(this.date, dir);
15865 newViewDate = this.moveYear(this.viewDate, dir);
15866 } else if (e.shiftKey){
15867 newDate = this.moveMonth(this.date, dir);
15868 newViewDate = this.moveMonth(this.viewDate, dir);
15870 newDate = new Date(this.date);
15871 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15872 newViewDate = new Date(this.viewDate);
15873 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15875 if (this.dateWithinRange(newDate)){
15876 this.date = newDate;
15877 this.viewDate = newViewDate;
15878 this.setValue(this.formatDate(this.date));
15880 e.preventDefault();
15881 dateChanged = true;
15885 this.setValue(this.formatDate(this.date));
15887 e.preventDefault();
15890 this.setValue(this.formatDate(this.date));
15904 onClick: function(e)
15906 e.stopPropagation();
15907 e.preventDefault();
15909 var target = e.getTarget();
15911 if(target.nodeName.toLowerCase() === 'i'){
15912 target = Roo.get(target).dom.parentNode;
15915 var nodeName = target.nodeName;
15916 var className = target.className;
15917 var html = target.innerHTML;
15918 //Roo.log(nodeName);
15920 switch(nodeName.toLowerCase()) {
15922 switch(className) {
15928 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15929 switch(this.viewMode){
15931 this.viewDate = this.moveMonth(this.viewDate, dir);
15935 this.viewDate = this.moveYear(this.viewDate, dir);
15941 var date = new Date();
15942 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15944 this.setValue(this.formatDate(this.date));
15951 if (className.indexOf('disabled') < 0) {
15952 this.viewDate.setUTCDate(1);
15953 if (className.indexOf('month') > -1) {
15954 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15956 var year = parseInt(html, 10) || 0;
15957 this.viewDate.setUTCFullYear(year);
15961 if(this.singleMode){
15962 this.setValue(this.formatDate(this.viewDate));
15973 //Roo.log(className);
15974 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15975 var day = parseInt(html, 10) || 1;
15976 var year = this.viewDate.getUTCFullYear(),
15977 month = this.viewDate.getUTCMonth();
15979 if (className.indexOf('old') > -1) {
15986 } else if (className.indexOf('new') > -1) {
15994 //Roo.log([year,month,day]);
15995 this.date = this.UTCDate(year, month, day,0,0,0,0);
15996 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
15998 //Roo.log(this.formatDate(this.date));
15999 this.setValue(this.formatDate(this.date));
16006 setStartDate: function(startDate)
16008 this.startDate = startDate || -Infinity;
16009 if (this.startDate !== -Infinity) {
16010 this.startDate = this.parseDate(this.startDate);
16013 this.updateNavArrows();
16016 setEndDate: function(endDate)
16018 this.endDate = endDate || Infinity;
16019 if (this.endDate !== Infinity) {
16020 this.endDate = this.parseDate(this.endDate);
16023 this.updateNavArrows();
16026 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16028 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16029 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16030 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16032 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16033 return parseInt(d, 10);
16036 this.updateNavArrows();
16039 updateNavArrows: function()
16041 if(this.singleMode){
16045 var d = new Date(this.viewDate),
16046 year = d.getUTCFullYear(),
16047 month = d.getUTCMonth();
16049 Roo.each(this.picker().select('.prev', true).elements, function(v){
16051 switch (this.viewMode) {
16054 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16060 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16067 Roo.each(this.picker().select('.next', true).elements, function(v){
16069 switch (this.viewMode) {
16072 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16078 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16086 moveMonth: function(date, dir)
16088 if (!dir) return date;
16089 var new_date = new Date(date.valueOf()),
16090 day = new_date.getUTCDate(),
16091 month = new_date.getUTCMonth(),
16092 mag = Math.abs(dir),
16094 dir = dir > 0 ? 1 : -1;
16097 // If going back one month, make sure month is not current month
16098 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16100 return new_date.getUTCMonth() == month;
16102 // If going forward one month, make sure month is as expected
16103 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16105 return new_date.getUTCMonth() != new_month;
16107 new_month = month + dir;
16108 new_date.setUTCMonth(new_month);
16109 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16110 if (new_month < 0 || new_month > 11)
16111 new_month = (new_month + 12) % 12;
16113 // For magnitudes >1, move one month at a time...
16114 for (var i=0; i<mag; i++)
16115 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16116 new_date = this.moveMonth(new_date, dir);
16117 // ...then reset the day, keeping it in the new month
16118 new_month = new_date.getUTCMonth();
16119 new_date.setUTCDate(day);
16121 return new_month != new_date.getUTCMonth();
16124 // Common date-resetting loop -- if date is beyond end of month, make it
16127 new_date.setUTCDate(--day);
16128 new_date.setUTCMonth(new_month);
16133 moveYear: function(date, dir)
16135 return this.moveMonth(date, dir*12);
16138 dateWithinRange: function(date)
16140 return date >= this.startDate && date <= this.endDate;
16146 this.picker().remove();
16151 Roo.apply(Roo.bootstrap.DateField, {
16162 html: '<i class="fa fa-arrow-left"/>'
16172 html: '<i class="fa fa-arrow-right"/>'
16214 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16215 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16216 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16217 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16218 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16231 navFnc: 'FullYear',
16236 navFnc: 'FullYear',
16241 Roo.apply(Roo.bootstrap.DateField, {
16245 cls: 'datepicker dropdown-menu roo-dynamic',
16249 cls: 'datepicker-days',
16253 cls: 'table-condensed',
16255 Roo.bootstrap.DateField.head,
16259 Roo.bootstrap.DateField.footer
16266 cls: 'datepicker-months',
16270 cls: 'table-condensed',
16272 Roo.bootstrap.DateField.head,
16273 Roo.bootstrap.DateField.content,
16274 Roo.bootstrap.DateField.footer
16281 cls: 'datepicker-years',
16285 cls: 'table-condensed',
16287 Roo.bootstrap.DateField.head,
16288 Roo.bootstrap.DateField.content,
16289 Roo.bootstrap.DateField.footer
16308 * @class Roo.bootstrap.TimeField
16309 * @extends Roo.bootstrap.Input
16310 * Bootstrap DateField class
16314 * Create a new TimeField
16315 * @param {Object} config The config object
16318 Roo.bootstrap.TimeField = function(config){
16319 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16323 * Fires when this field show.
16324 * @param {Roo.bootstrap.DateField} thisthis
16325 * @param {Mixed} date The date value
16330 * Fires when this field hide.
16331 * @param {Roo.bootstrap.DateField} this
16332 * @param {Mixed} date The date value
16337 * Fires when select a date.
16338 * @param {Roo.bootstrap.DateField} this
16339 * @param {Mixed} date The date value
16345 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16348 * @cfg {String} format
16349 * The default time format string which can be overriden for localization support. The format must be
16350 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16354 onRender: function(ct, position)
16357 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16359 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16361 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16363 this.pop = this.picker().select('>.datepicker-time',true).first();
16364 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16366 this.picker().on('mousedown', this.onMousedown, this);
16367 this.picker().on('click', this.onClick, this);
16369 this.picker().addClass('datepicker-dropdown');
16374 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16375 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16376 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16377 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16378 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16379 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16383 fireKey: function(e){
16384 if (!this.picker().isVisible()){
16385 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16391 e.preventDefault();
16399 this.onTogglePeriod();
16402 this.onIncrementMinutes();
16405 this.onDecrementMinutes();
16414 onClick: function(e) {
16415 e.stopPropagation();
16416 e.preventDefault();
16419 picker : function()
16421 return this.el.select('.datepicker', true).first();
16424 fillTime: function()
16426 var time = this.pop.select('tbody', true).first();
16428 time.dom.innerHTML = '';
16443 cls: 'hours-up glyphicon glyphicon-chevron-up'
16463 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16484 cls: 'timepicker-hour',
16499 cls: 'timepicker-minute',
16514 cls: 'btn btn-primary period',
16536 cls: 'hours-down glyphicon glyphicon-chevron-down'
16556 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16574 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16581 var hours = this.time.getHours();
16582 var minutes = this.time.getMinutes();
16595 hours = hours - 12;
16599 hours = '0' + hours;
16603 minutes = '0' + minutes;
16606 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16607 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16608 this.pop.select('button', true).first().dom.innerHTML = period;
16614 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16616 var cls = ['bottom'];
16618 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16625 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16630 this.picker().addClass(cls.join('-'));
16634 Roo.each(cls, function(c){
16636 _this.picker().setTop(_this.inputEl().getHeight());
16640 _this.picker().setTop(0 - _this.picker().getHeight());
16645 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16649 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16656 onFocus : function()
16658 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16662 onBlur : function()
16664 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16670 this.picker().show();
16675 this.fireEvent('show', this, this.date);
16680 this.picker().hide();
16683 this.fireEvent('hide', this, this.date);
16686 setTime : function()
16689 this.setValue(this.time.format(this.format));
16691 this.fireEvent('select', this, this.date);
16696 onMousedown: function(e){
16697 e.stopPropagation();
16698 e.preventDefault();
16701 onIncrementHours: function()
16703 Roo.log('onIncrementHours');
16704 this.time = this.time.add(Date.HOUR, 1);
16709 onDecrementHours: function()
16711 Roo.log('onDecrementHours');
16712 this.time = this.time.add(Date.HOUR, -1);
16716 onIncrementMinutes: function()
16718 Roo.log('onIncrementMinutes');
16719 this.time = this.time.add(Date.MINUTE, 1);
16723 onDecrementMinutes: function()
16725 Roo.log('onDecrementMinutes');
16726 this.time = this.time.add(Date.MINUTE, -1);
16730 onTogglePeriod: function()
16732 Roo.log('onTogglePeriod');
16733 this.time = this.time.add(Date.HOUR, 12);
16740 Roo.apply(Roo.bootstrap.TimeField, {
16770 cls: 'btn btn-info ok',
16782 Roo.apply(Roo.bootstrap.TimeField, {
16786 cls: 'datepicker dropdown-menu',
16790 cls: 'datepicker-time',
16794 cls: 'table-condensed',
16796 Roo.bootstrap.TimeField.content,
16797 Roo.bootstrap.TimeField.footer
16816 * @class Roo.bootstrap.MonthField
16817 * @extends Roo.bootstrap.Input
16818 * Bootstrap MonthField class
16820 * @cfg {String} language default en
16823 * Create a new MonthField
16824 * @param {Object} config The config object
16827 Roo.bootstrap.MonthField = function(config){
16828 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16833 * Fires when this field show.
16834 * @param {Roo.bootstrap.MonthField} this
16835 * @param {Mixed} date The date value
16840 * Fires when this field hide.
16841 * @param {Roo.bootstrap.MonthField} this
16842 * @param {Mixed} date The date value
16847 * Fires when select a date.
16848 * @param {Roo.bootstrap.MonthField} this
16849 * @param {String} oldvalue The old value
16850 * @param {String} newvalue The new value
16856 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16858 onRender: function(ct, position)
16861 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16863 this.language = this.language || 'en';
16864 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16865 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16867 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16868 this.isInline = false;
16869 this.isInput = true;
16870 this.component = this.el.select('.add-on', true).first() || false;
16871 this.component = (this.component && this.component.length === 0) ? false : this.component;
16872 this.hasInput = this.component && this.inputEL().length;
16874 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16876 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16878 this.picker().on('mousedown', this.onMousedown, this);
16879 this.picker().on('click', this.onClick, this);
16881 this.picker().addClass('datepicker-dropdown');
16883 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16884 v.setStyle('width', '189px');
16891 if(this.isInline) {
16897 setValue: function(v, suppressEvent)
16899 var o = this.getValue();
16901 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16905 if(suppressEvent !== true){
16906 this.fireEvent('select', this, o, v);
16911 getValue: function()
16916 onClick: function(e)
16918 e.stopPropagation();
16919 e.preventDefault();
16921 var target = e.getTarget();
16923 if(target.nodeName.toLowerCase() === 'i'){
16924 target = Roo.get(target).dom.parentNode;
16927 var nodeName = target.nodeName;
16928 var className = target.className;
16929 var html = target.innerHTML;
16931 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16935 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16937 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16943 picker : function()
16945 return this.pickerEl;
16948 fillMonths: function()
16951 var months = this.picker().select('>.datepicker-months td', true).first();
16953 months.dom.innerHTML = '';
16959 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16962 months.createChild(month);
16971 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16972 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16975 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16976 e.removeClass('active');
16978 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16979 e.addClass('active');
16986 if(this.isInline) return;
16988 this.picker().removeClass(['bottom', 'top']);
16990 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
16992 * place to the top of element!
16996 this.picker().addClass('top');
16997 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17002 this.picker().addClass('bottom');
17004 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17007 onFocus : function()
17009 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17013 onBlur : function()
17015 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17017 var d = this.inputEl().getValue();
17026 this.picker().show();
17027 this.picker().select('>.datepicker-months', true).first().show();
17031 this.fireEvent('show', this, this.date);
17036 if(this.isInline) return;
17037 this.picker().hide();
17038 this.fireEvent('hide', this, this.date);
17042 onMousedown: function(e)
17044 e.stopPropagation();
17045 e.preventDefault();
17050 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17054 fireKey: function(e)
17056 if (!this.picker().isVisible()){
17057 if (e.keyCode == 27) // allow escape to hide and re-show picker
17067 e.preventDefault();
17071 dir = e.keyCode == 37 ? -1 : 1;
17073 this.vIndex = this.vIndex + dir;
17075 if(this.vIndex < 0){
17079 if(this.vIndex > 11){
17083 if(isNaN(this.vIndex)){
17087 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17093 dir = e.keyCode == 38 ? -1 : 1;
17095 this.vIndex = this.vIndex + dir * 4;
17097 if(this.vIndex < 0){
17101 if(this.vIndex > 11){
17105 if(isNaN(this.vIndex)){
17109 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17114 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17115 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17119 e.preventDefault();
17122 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17123 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17139 this.picker().remove();
17144 Roo.apply(Roo.bootstrap.MonthField, {
17163 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17164 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17169 Roo.apply(Roo.bootstrap.MonthField, {
17173 cls: 'datepicker dropdown-menu roo-dynamic',
17177 cls: 'datepicker-months',
17181 cls: 'table-condensed',
17183 Roo.bootstrap.DateField.content
17203 * @class Roo.bootstrap.CheckBox
17204 * @extends Roo.bootstrap.Input
17205 * Bootstrap CheckBox class
17207 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17208 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17209 * @cfg {String} boxLabel The text that appears beside the checkbox
17210 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17211 * @cfg {Boolean} checked initnal the element
17212 * @cfg {Boolean} inline inline the element (default false)
17213 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17216 * Create a new CheckBox
17217 * @param {Object} config The config object
17220 Roo.bootstrap.CheckBox = function(config){
17221 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17226 * Fires when the element is checked or unchecked.
17227 * @param {Roo.bootstrap.CheckBox} this This input
17228 * @param {Boolean} checked The new checked value
17235 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17237 inputType: 'checkbox',
17245 getAutoCreate : function()
17247 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17253 cfg.cls = 'form-group ' + this.inputType; //input-group
17256 cfg.cls += ' ' + this.inputType + '-inline';
17262 type : this.inputType,
17263 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17264 cls : 'roo-' + this.inputType, //'form-box',
17265 placeholder : this.placeholder || ''
17269 if (this.weight) { // Validity check?
17270 cfg.cls += " " + this.inputType + "-" + this.weight;
17273 if (this.disabled) {
17274 input.disabled=true;
17278 input.checked = this.checked;
17282 input.name = this.name;
17286 input.cls += ' input-' + this.size;
17291 ['xs','sm','md','lg'].map(function(size){
17292 if (settings[size]) {
17293 cfg.cls += ' col-' + size + '-' + settings[size];
17297 var inputblock = input;
17299 if (this.before || this.after) {
17302 cls : 'input-group',
17307 inputblock.cn.push({
17309 cls : 'input-group-addon',
17314 inputblock.cn.push(input);
17317 inputblock.cn.push({
17319 cls : 'input-group-addon',
17326 if (align ==='left' && this.fieldLabel.length) {
17327 Roo.log("left and has label");
17333 cls : 'control-label col-md-' + this.labelWidth,
17334 html : this.fieldLabel
17338 cls : "col-md-" + (12 - this.labelWidth),
17345 } else if ( this.fieldLabel.length) {
17350 tag: this.boxLabel ? 'span' : 'label',
17352 cls: 'control-label box-input-label',
17353 //cls : 'input-group-addon',
17354 html : this.fieldLabel
17364 Roo.log(" no label && no align");
17365 cfg.cn = [ inputblock ] ;
17370 var boxLabelCfg = {
17372 //'for': id, // box label is handled by onclick - so no for...
17374 html: this.boxLabel
17378 boxLabelCfg.tooltip = this.tooltip;
17381 cfg.cn.push(boxLabelCfg);
17391 * return the real input element.
17393 inputEl: function ()
17395 return this.el.select('input.roo-' + this.inputType,true).first();
17398 labelEl: function()
17400 return this.el.select('label.control-label',true).first();
17402 /* depricated... */
17406 return this.labelEl();
17409 initEvents : function()
17411 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17413 this.inputEl().on('click', this.onClick, this);
17415 if (this.boxLabel) {
17416 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17419 this.startValue = this.getValue();
17422 Roo.bootstrap.CheckBox.register(this);
17426 onClick : function()
17428 this.setChecked(!this.checked);
17431 setChecked : function(state,suppressEvent)
17433 this.startValue = this.getValue();
17435 if(this.inputType == 'radio'){
17437 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17438 e.dom.checked = false;
17441 this.inputEl().dom.checked = true;
17443 this.inputEl().dom.value = this.inputValue;
17445 if(suppressEvent !== true){
17446 this.fireEvent('check', this, true);
17454 this.checked = state;
17456 this.inputEl().dom.checked = state;
17458 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17460 if(suppressEvent !== true){
17461 this.fireEvent('check', this, state);
17467 getValue : function()
17469 if(this.inputType == 'radio'){
17470 return this.getGroupValue();
17473 return this.inputEl().getValue();
17477 getGroupValue : function()
17479 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17483 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17486 setValue : function(v,suppressEvent)
17488 if(this.inputType == 'radio'){
17489 this.setGroupValue(v, suppressEvent);
17493 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17498 setGroupValue : function(v, suppressEvent)
17500 this.startValue = this.getValue();
17502 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17503 e.dom.checked = false;
17505 if(e.dom.value == v){
17506 e.dom.checked = true;
17510 if(suppressEvent !== true){
17511 this.fireEvent('check', this, true);
17519 validate : function()
17523 (this.inputType == 'radio' && this.validateRadio()) ||
17524 (this.inputType == 'checkbox' && this.validateCheckbox())
17530 this.markInvalid();
17534 validateRadio : function()
17538 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17539 if(!e.dom.checked){
17551 validateCheckbox : function()
17554 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17557 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17565 for(var i in group){
17570 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17577 * Mark this field as valid
17579 markValid : function()
17581 if(this.allowBlank){
17587 this.fireEvent('valid', this);
17589 if(this.inputType == 'radio'){
17590 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17591 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17592 e.findParent('.form-group', false, true).addClass(_this.validClass);
17599 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17600 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17604 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17610 for(var i in group){
17611 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17612 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17617 * Mark this field as invalid
17618 * @param {String} msg The validation message
17620 markInvalid : function(msg)
17622 if(this.allowBlank){
17628 this.fireEvent('invalid', this, msg);
17630 if(this.inputType == 'radio'){
17631 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17632 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17633 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17640 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17641 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17645 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17651 for(var i in group){
17652 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17653 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17660 Roo.apply(Roo.bootstrap.CheckBox, {
17665 * register a CheckBox Group
17666 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17668 register : function(checkbox)
17670 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17671 this.groups[checkbox.groupId] = {};
17674 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17678 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17682 * fetch a CheckBox Group based on the group ID
17683 * @param {string} the group ID
17684 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17686 get: function(groupId) {
17687 if (typeof(this.groups[groupId]) == 'undefined') {
17691 return this.groups[groupId] ;
17703 *<div class="radio">
17705 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17706 Option one is this and that—be sure to include why it's great
17713 *<label class="radio-inline">fieldLabel</label>
17714 *<label class="radio-inline">
17715 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17723 * @class Roo.bootstrap.Radio
17724 * @extends Roo.bootstrap.CheckBox
17725 * Bootstrap Radio class
17728 * Create a new Radio
17729 * @param {Object} config The config object
17732 Roo.bootstrap.Radio = function(config){
17733 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17737 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17739 inputType: 'radio',
17743 getAutoCreate : function()
17745 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17746 align = align || 'left'; // default...
17753 tag : this.inline ? 'span' : 'div',
17758 var inline = this.inline ? ' radio-inline' : '';
17762 // does not need for, as we wrap the input with it..
17764 cls : 'control-label box-label' + inline,
17767 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17771 //cls : 'control-label' + inline,
17772 html : this.fieldLabel,
17773 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17782 type : this.inputType,
17783 //value : (!this.checked) ? this.valueOff : this.inputValue,
17784 value : this.inputValue,
17786 placeholder : this.placeholder || '' // ?? needed????
17789 if (this.weight) { // Validity check?
17790 input.cls += " radio-" + this.weight;
17792 if (this.disabled) {
17793 input.disabled=true;
17797 input.checked = this.checked;
17801 input.name = this.name;
17805 input.cls += ' input-' + this.size;
17808 //?? can span's inline have a width??
17811 ['xs','sm','md','lg'].map(function(size){
17812 if (settings[size]) {
17813 cfg.cls += ' col-' + size + '-' + settings[size];
17817 var inputblock = input;
17819 if (this.before || this.after) {
17822 cls : 'input-group',
17827 inputblock.cn.push({
17829 cls : 'input-group-addon',
17833 inputblock.cn.push(input);
17835 inputblock.cn.push({
17837 cls : 'input-group-addon',
17845 if (this.fieldLabel && this.fieldLabel.length) {
17846 cfg.cn.push(fieldLabel);
17849 // normal bootstrap puts the input inside the label.
17850 // however with our styled version - it has to go after the input.
17852 //lbl.cn.push(inputblock);
17856 cls: 'radio' + inline,
17863 cfg.cn.push( lblwrap);
17868 html: this.boxLabel
17877 initEvents : function()
17879 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17881 this.inputEl().on('click', this.onClick, this);
17882 if (this.boxLabel) {
17883 Roo.log('find label')
17884 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17889 inputEl: function ()
17891 return this.el.select('input.roo-radio',true).first();
17893 onClick : function()
17896 this.setChecked(true);
17899 setChecked : function(state,suppressEvent)
17902 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17903 v.dom.checked = false;
17906 Roo.log(this.inputEl().dom);
17907 this.checked = state;
17908 this.inputEl().dom.checked = state;
17910 if(suppressEvent !== true){
17911 this.fireEvent('check', this, state);
17914 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17918 getGroupValue : function()
17921 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17922 if(v.dom.checked == true){
17923 value = v.dom.value;
17931 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17932 * @return {Mixed} value The field value
17934 getValue : function(){
17935 return this.getGroupValue();
17941 //<script type="text/javascript">
17944 * Based Ext JS Library 1.1.1
17945 * Copyright(c) 2006-2007, Ext JS, LLC.
17951 * @class Roo.HtmlEditorCore
17952 * @extends Roo.Component
17953 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17955 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17958 Roo.HtmlEditorCore = function(config){
17961 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17966 * @event initialize
17967 * Fires when the editor is fully initialized (including the iframe)
17968 * @param {Roo.HtmlEditorCore} this
17973 * Fires when the editor is first receives the focus. Any insertion must wait
17974 * until after this event.
17975 * @param {Roo.HtmlEditorCore} this
17979 * @event beforesync
17980 * Fires before the textarea is updated with content from the editor iframe. Return false
17981 * to cancel the sync.
17982 * @param {Roo.HtmlEditorCore} this
17983 * @param {String} html
17987 * @event beforepush
17988 * Fires before the iframe editor is updated with content from the textarea. Return false
17989 * to cancel the push.
17990 * @param {Roo.HtmlEditorCore} this
17991 * @param {String} html
17996 * Fires when the textarea is updated with content from the editor iframe.
17997 * @param {Roo.HtmlEditorCore} this
17998 * @param {String} html
18003 * Fires when the iframe editor is updated with content from the textarea.
18004 * @param {Roo.HtmlEditorCore} this
18005 * @param {String} html
18010 * @event editorevent
18011 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18012 * @param {Roo.HtmlEditorCore} this
18018 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18020 // defaults : white / black...
18021 this.applyBlacklists();
18028 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18032 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18038 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18043 * @cfg {Number} height (in pixels)
18047 * @cfg {Number} width (in pixels)
18052 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18055 stylesheets: false,
18060 // private properties
18061 validationEvent : false,
18063 initialized : false,
18065 sourceEditMode : false,
18066 onFocus : Roo.emptyFn,
18068 hideMode:'offsets',
18072 // blacklist + whitelisted elements..
18079 * Protected method that will not generally be called directly. It
18080 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18081 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18083 getDocMarkup : function(){
18087 // inherit styels from page...??
18088 if (this.stylesheets === false) {
18090 Roo.get(document.head).select('style').each(function(node) {
18091 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18094 Roo.get(document.head).select('link').each(function(node) {
18095 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18098 } else if (!this.stylesheets.length) {
18100 st = '<style type="text/css">' +
18101 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18107 st += '<style type="text/css">' +
18108 'IMG { cursor: pointer } ' +
18112 return '<html><head>' + st +
18113 //<style type="text/css">' +
18114 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18116 ' </head><body class="roo-htmleditor-body"></body></html>';
18120 onRender : function(ct, position)
18123 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18124 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18127 this.el.dom.style.border = '0 none';
18128 this.el.dom.setAttribute('tabIndex', -1);
18129 this.el.addClass('x-hidden hide');
18133 if(Roo.isIE){ // fix IE 1px bogus margin
18134 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18138 this.frameId = Roo.id();
18142 var iframe = this.owner.wrap.createChild({
18144 cls: 'form-control', // bootstrap..
18146 name: this.frameId,
18147 frameBorder : 'no',
18148 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18153 this.iframe = iframe.dom;
18155 this.assignDocWin();
18157 this.doc.designMode = 'on';
18160 this.doc.write(this.getDocMarkup());
18164 var task = { // must defer to wait for browser to be ready
18166 //console.log("run task?" + this.doc.readyState);
18167 this.assignDocWin();
18168 if(this.doc.body || this.doc.readyState == 'complete'){
18170 this.doc.designMode="on";
18174 Roo.TaskMgr.stop(task);
18175 this.initEditor.defer(10, this);
18182 Roo.TaskMgr.start(task);
18187 onResize : function(w, h)
18189 Roo.log('resize: ' +w + ',' + h );
18190 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18194 if(typeof w == 'number'){
18196 this.iframe.style.width = w + 'px';
18198 if(typeof h == 'number'){
18200 this.iframe.style.height = h + 'px';
18202 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18209 * Toggles the editor between standard and source edit mode.
18210 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18212 toggleSourceEdit : function(sourceEditMode){
18214 this.sourceEditMode = sourceEditMode === true;
18216 if(this.sourceEditMode){
18218 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18221 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18222 //this.iframe.className = '';
18225 //this.setSize(this.owner.wrap.getSize());
18226 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18233 * Protected method that will not generally be called directly. If you need/want
18234 * custom HTML cleanup, this is the method you should override.
18235 * @param {String} html The HTML to be cleaned
18236 * return {String} The cleaned HTML
18238 cleanHtml : function(html){
18239 html = String(html);
18240 if(html.length > 5){
18241 if(Roo.isSafari){ // strip safari nonsense
18242 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18245 if(html == ' '){
18252 * HTML Editor -> Textarea
18253 * Protected method that will not generally be called directly. Syncs the contents
18254 * of the editor iframe with the textarea.
18256 syncValue : function(){
18257 if(this.initialized){
18258 var bd = (this.doc.body || this.doc.documentElement);
18259 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18260 var html = bd.innerHTML;
18262 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18263 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18265 html = '<div style="'+m[0]+'">' + html + '</div>';
18268 html = this.cleanHtml(html);
18269 // fix up the special chars.. normaly like back quotes in word...
18270 // however we do not want to do this with chinese..
18271 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18272 var cc = b.charCodeAt();
18274 (cc >= 0x4E00 && cc < 0xA000 ) ||
18275 (cc >= 0x3400 && cc < 0x4E00 ) ||
18276 (cc >= 0xf900 && cc < 0xfb00 )
18282 if(this.owner.fireEvent('beforesync', this, html) !== false){
18283 this.el.dom.value = html;
18284 this.owner.fireEvent('sync', this, html);
18290 * Protected method that will not generally be called directly. Pushes the value of the textarea
18291 * into the iframe editor.
18293 pushValue : function(){
18294 if(this.initialized){
18295 var v = this.el.dom.value.trim();
18297 // if(v.length < 1){
18301 if(this.owner.fireEvent('beforepush', this, v) !== false){
18302 var d = (this.doc.body || this.doc.documentElement);
18304 this.cleanUpPaste();
18305 this.el.dom.value = d.innerHTML;
18306 this.owner.fireEvent('push', this, v);
18312 deferFocus : function(){
18313 this.focus.defer(10, this);
18317 focus : function(){
18318 if(this.win && !this.sourceEditMode){
18325 assignDocWin: function()
18327 var iframe = this.iframe;
18330 this.doc = iframe.contentWindow.document;
18331 this.win = iframe.contentWindow;
18333 // if (!Roo.get(this.frameId)) {
18336 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18337 // this.win = Roo.get(this.frameId).dom.contentWindow;
18339 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18343 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18344 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18349 initEditor : function(){
18350 //console.log("INIT EDITOR");
18351 this.assignDocWin();
18355 this.doc.designMode="on";
18357 this.doc.write(this.getDocMarkup());
18360 var dbody = (this.doc.body || this.doc.documentElement);
18361 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18362 // this copies styles from the containing element into thsi one..
18363 // not sure why we need all of this..
18364 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18366 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18367 //ss['background-attachment'] = 'fixed'; // w3c
18368 dbody.bgProperties = 'fixed'; // ie
18369 //Roo.DomHelper.applyStyles(dbody, ss);
18370 Roo.EventManager.on(this.doc, {
18371 //'mousedown': this.onEditorEvent,
18372 'mouseup': this.onEditorEvent,
18373 'dblclick': this.onEditorEvent,
18374 'click': this.onEditorEvent,
18375 'keyup': this.onEditorEvent,
18380 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18382 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18383 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18385 this.initialized = true;
18387 this.owner.fireEvent('initialize', this);
18392 onDestroy : function(){
18398 //for (var i =0; i < this.toolbars.length;i++) {
18399 // // fixme - ask toolbars for heights?
18400 // this.toolbars[i].onDestroy();
18403 //this.wrap.dom.innerHTML = '';
18404 //this.wrap.remove();
18409 onFirstFocus : function(){
18411 this.assignDocWin();
18414 this.activated = true;
18417 if(Roo.isGecko){ // prevent silly gecko errors
18419 var s = this.win.getSelection();
18420 if(!s.focusNode || s.focusNode.nodeType != 3){
18421 var r = s.getRangeAt(0);
18422 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18427 this.execCmd('useCSS', true);
18428 this.execCmd('styleWithCSS', false);
18431 this.owner.fireEvent('activate', this);
18435 adjustFont: function(btn){
18436 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18437 //if(Roo.isSafari){ // safari
18440 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18441 if(Roo.isSafari){ // safari
18442 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18443 v = (v < 10) ? 10 : v;
18444 v = (v > 48) ? 48 : v;
18445 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18450 v = Math.max(1, v+adjust);
18452 this.execCmd('FontSize', v );
18455 onEditorEvent : function(e){
18456 this.owner.fireEvent('editorevent', this, e);
18457 // this.updateToolbar();
18458 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18461 insertTag : function(tg)
18463 // could be a bit smarter... -> wrap the current selected tRoo..
18464 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18466 range = this.createRange(this.getSelection());
18467 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18468 wrappingNode.appendChild(range.extractContents());
18469 range.insertNode(wrappingNode);
18476 this.execCmd("formatblock", tg);
18480 insertText : function(txt)
18484 var range = this.createRange();
18485 range.deleteContents();
18486 //alert(Sender.getAttribute('label'));
18488 range.insertNode(this.doc.createTextNode(txt));
18494 * Executes a Midas editor command on the editor document and performs necessary focus and
18495 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18496 * @param {String} cmd The Midas command
18497 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18499 relayCmd : function(cmd, value){
18501 this.execCmd(cmd, value);
18502 this.owner.fireEvent('editorevent', this);
18503 //this.updateToolbar();
18504 this.owner.deferFocus();
18508 * Executes a Midas editor command directly on the editor document.
18509 * For visual commands, you should use {@link #relayCmd} instead.
18510 * <b>This should only be called after the editor is initialized.</b>
18511 * @param {String} cmd The Midas command
18512 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18514 execCmd : function(cmd, value){
18515 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18522 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18524 * @param {String} text | dom node..
18526 insertAtCursor : function(text)
18531 if(!this.activated){
18537 var r = this.doc.selection.createRange();
18548 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18552 // from jquery ui (MIT licenced)
18554 var win = this.win;
18556 if (win.getSelection && win.getSelection().getRangeAt) {
18557 range = win.getSelection().getRangeAt(0);
18558 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18559 range.insertNode(node);
18560 } else if (win.document.selection && win.document.selection.createRange) {
18561 // no firefox support
18562 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18563 win.document.selection.createRange().pasteHTML(txt);
18565 // no firefox support
18566 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18567 this.execCmd('InsertHTML', txt);
18576 mozKeyPress : function(e){
18578 var c = e.getCharCode(), cmd;
18581 c = String.fromCharCode(c).toLowerCase();
18595 this.cleanUpPaste.defer(100, this);
18603 e.preventDefault();
18611 fixKeys : function(){ // load time branching for fastest keydown performance
18613 return function(e){
18614 var k = e.getKey(), r;
18617 r = this.doc.selection.createRange();
18620 r.pasteHTML('    ');
18627 r = this.doc.selection.createRange();
18629 var target = r.parentElement();
18630 if(!target || target.tagName.toLowerCase() != 'li'){
18632 r.pasteHTML('<br />');
18638 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18639 this.cleanUpPaste.defer(100, this);
18645 }else if(Roo.isOpera){
18646 return function(e){
18647 var k = e.getKey();
18651 this.execCmd('InsertHTML','    ');
18654 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18655 this.cleanUpPaste.defer(100, this);
18660 }else if(Roo.isSafari){
18661 return function(e){
18662 var k = e.getKey();
18666 this.execCmd('InsertText','\t');
18670 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18671 this.cleanUpPaste.defer(100, this);
18679 getAllAncestors: function()
18681 var p = this.getSelectedNode();
18684 a.push(p); // push blank onto stack..
18685 p = this.getParentElement();
18689 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18693 a.push(this.doc.body);
18697 lastSelNode : false,
18700 getSelection : function()
18702 this.assignDocWin();
18703 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18706 getSelectedNode: function()
18708 // this may only work on Gecko!!!
18710 // should we cache this!!!!
18715 var range = this.createRange(this.getSelection()).cloneRange();
18718 var parent = range.parentElement();
18720 var testRange = range.duplicate();
18721 testRange.moveToElementText(parent);
18722 if (testRange.inRange(range)) {
18725 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18728 parent = parent.parentElement;
18733 // is ancestor a text element.
18734 var ac = range.commonAncestorContainer;
18735 if (ac.nodeType == 3) {
18736 ac = ac.parentNode;
18739 var ar = ac.childNodes;
18742 var other_nodes = [];
18743 var has_other_nodes = false;
18744 for (var i=0;i<ar.length;i++) {
18745 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18748 // fullly contained node.
18750 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18755 // probably selected..
18756 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18757 other_nodes.push(ar[i]);
18761 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18766 has_other_nodes = true;
18768 if (!nodes.length && other_nodes.length) {
18769 nodes= other_nodes;
18771 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18777 createRange: function(sel)
18779 // this has strange effects when using with
18780 // top toolbar - not sure if it's a great idea.
18781 //this.editor.contentWindow.focus();
18782 if (typeof sel != "undefined") {
18784 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18786 return this.doc.createRange();
18789 return this.doc.createRange();
18792 getParentElement: function()
18795 this.assignDocWin();
18796 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18798 var range = this.createRange(sel);
18801 var p = range.commonAncestorContainer;
18802 while (p.nodeType == 3) { // text node
18813 * Range intersection.. the hard stuff...
18817 * [ -- selected range --- ]
18821 * if end is before start or hits it. fail.
18822 * if start is after end or hits it fail.
18824 * if either hits (but other is outside. - then it's not
18830 // @see http://www.thismuchiknow.co.uk/?p=64.
18831 rangeIntersectsNode : function(range, node)
18833 var nodeRange = node.ownerDocument.createRange();
18835 nodeRange.selectNode(node);
18837 nodeRange.selectNodeContents(node);
18840 var rangeStartRange = range.cloneRange();
18841 rangeStartRange.collapse(true);
18843 var rangeEndRange = range.cloneRange();
18844 rangeEndRange.collapse(false);
18846 var nodeStartRange = nodeRange.cloneRange();
18847 nodeStartRange.collapse(true);
18849 var nodeEndRange = nodeRange.cloneRange();
18850 nodeEndRange.collapse(false);
18852 return rangeStartRange.compareBoundaryPoints(
18853 Range.START_TO_START, nodeEndRange) == -1 &&
18854 rangeEndRange.compareBoundaryPoints(
18855 Range.START_TO_START, nodeStartRange) == 1;
18859 rangeCompareNode : function(range, node)
18861 var nodeRange = node.ownerDocument.createRange();
18863 nodeRange.selectNode(node);
18865 nodeRange.selectNodeContents(node);
18869 range.collapse(true);
18871 nodeRange.collapse(true);
18873 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18874 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18876 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18878 var nodeIsBefore = ss == 1;
18879 var nodeIsAfter = ee == -1;
18881 if (nodeIsBefore && nodeIsAfter)
18883 if (!nodeIsBefore && nodeIsAfter)
18884 return 1; //right trailed.
18886 if (nodeIsBefore && !nodeIsAfter)
18887 return 2; // left trailed.
18892 // private? - in a new class?
18893 cleanUpPaste : function()
18895 // cleans up the whole document..
18896 Roo.log('cleanuppaste');
18898 this.cleanUpChildren(this.doc.body);
18899 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18900 if (clean != this.doc.body.innerHTML) {
18901 this.doc.body.innerHTML = clean;
18906 cleanWordChars : function(input) {// change the chars to hex code
18907 var he = Roo.HtmlEditorCore;
18909 var output = input;
18910 Roo.each(he.swapCodes, function(sw) {
18911 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18913 output = output.replace(swapper, sw[1]);
18920 cleanUpChildren : function (n)
18922 if (!n.childNodes.length) {
18925 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18926 this.cleanUpChild(n.childNodes[i]);
18933 cleanUpChild : function (node)
18936 //console.log(node);
18937 if (node.nodeName == "#text") {
18938 // clean up silly Windows -- stuff?
18941 if (node.nodeName == "#comment") {
18942 node.parentNode.removeChild(node);
18943 // clean up silly Windows -- stuff?
18946 var lcname = node.tagName.toLowerCase();
18947 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18948 // whitelist of tags..
18950 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18952 node.parentNode.removeChild(node);
18957 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18959 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18960 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18962 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18963 // remove_keep_children = true;
18966 if (remove_keep_children) {
18967 this.cleanUpChildren(node);
18968 // inserts everything just before this node...
18969 while (node.childNodes.length) {
18970 var cn = node.childNodes[0];
18971 node.removeChild(cn);
18972 node.parentNode.insertBefore(cn, node);
18974 node.parentNode.removeChild(node);
18978 if (!node.attributes || !node.attributes.length) {
18979 this.cleanUpChildren(node);
18983 function cleanAttr(n,v)
18986 if (v.match(/^\./) || v.match(/^\//)) {
18989 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
18992 if (v.match(/^#/)) {
18995 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
18996 node.removeAttribute(n);
19000 var cwhite = this.cwhite;
19001 var cblack = this.cblack;
19003 function cleanStyle(n,v)
19005 if (v.match(/expression/)) { //XSS?? should we even bother..
19006 node.removeAttribute(n);
19010 var parts = v.split(/;/);
19013 Roo.each(parts, function(p) {
19014 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19018 var l = p.split(':').shift().replace(/\s+/g,'');
19019 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19021 if ( cwhite.length && cblack.indexOf(l) > -1) {
19022 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19023 //node.removeAttribute(n);
19027 // only allow 'c whitelisted system attributes'
19028 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19029 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19030 //node.removeAttribute(n);
19040 if (clean.length) {
19041 node.setAttribute(n, clean.join(';'));
19043 node.removeAttribute(n);
19049 for (var i = node.attributes.length-1; i > -1 ; i--) {
19050 var a = node.attributes[i];
19053 if (a.name.toLowerCase().substr(0,2)=='on') {
19054 node.removeAttribute(a.name);
19057 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19058 node.removeAttribute(a.name);
19061 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19062 cleanAttr(a.name,a.value); // fixme..
19065 if (a.name == 'style') {
19066 cleanStyle(a.name,a.value);
19069 /// clean up MS crap..
19070 // tecnically this should be a list of valid class'es..
19073 if (a.name == 'class') {
19074 if (a.value.match(/^Mso/)) {
19075 node.className = '';
19078 if (a.value.match(/body/)) {
19079 node.className = '';
19090 this.cleanUpChildren(node);
19095 * Clean up MS wordisms...
19097 cleanWord : function(node)
19100 var cleanWordChildren = function()
19102 if (!node.childNodes.length) {
19105 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19106 _t.cleanWord(node.childNodes[i]);
19112 this.cleanWord(this.doc.body);
19115 if (node.nodeName == "#text") {
19116 // clean up silly Windows -- stuff?
19119 if (node.nodeName == "#comment") {
19120 node.parentNode.removeChild(node);
19121 // clean up silly Windows -- stuff?
19125 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19126 node.parentNode.removeChild(node);
19130 // remove - but keep children..
19131 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19132 while (node.childNodes.length) {
19133 var cn = node.childNodes[0];
19134 node.removeChild(cn);
19135 node.parentNode.insertBefore(cn, node);
19137 node.parentNode.removeChild(node);
19138 cleanWordChildren();
19142 if (node.className.length) {
19144 var cn = node.className.split(/\W+/);
19146 Roo.each(cn, function(cls) {
19147 if (cls.match(/Mso[a-zA-Z]+/)) {
19152 node.className = cna.length ? cna.join(' ') : '';
19154 node.removeAttribute("class");
19158 if (node.hasAttribute("lang")) {
19159 node.removeAttribute("lang");
19162 if (node.hasAttribute("style")) {
19164 var styles = node.getAttribute("style").split(";");
19166 Roo.each(styles, function(s) {
19167 if (!s.match(/:/)) {
19170 var kv = s.split(":");
19171 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19174 // what ever is left... we allow.
19177 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19178 if (!nstyle.length) {
19179 node.removeAttribute('style');
19183 cleanWordChildren();
19187 domToHTML : function(currentElement, depth, nopadtext) {
19189 depth = depth || 0;
19190 nopadtext = nopadtext || false;
19192 if (!currentElement) {
19193 return this.domToHTML(this.doc.body);
19196 //Roo.log(currentElement);
19198 var allText = false;
19199 var nodeName = currentElement.nodeName;
19200 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19202 if (nodeName == '#text') {
19204 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19209 if (nodeName != 'BODY') {
19212 // Prints the node tagName, such as <A>, <IMG>, etc
19215 for(i = 0; i < currentElement.attributes.length;i++) {
19217 var aname = currentElement.attributes.item(i).name;
19218 if (!currentElement.attributes.item(i).value.length) {
19221 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19224 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19233 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19236 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19241 // Traverse the tree
19243 var currentElementChild = currentElement.childNodes.item(i);
19244 var allText = true;
19245 var innerHTML = '';
19247 while (currentElementChild) {
19248 // Formatting code (indent the tree so it looks nice on the screen)
19249 var nopad = nopadtext;
19250 if (lastnode == 'SPAN') {
19254 if (currentElementChild.nodeName == '#text') {
19255 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19256 toadd = nopadtext ? toadd : toadd.trim();
19257 if (!nopad && toadd.length > 80) {
19258 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19260 innerHTML += toadd;
19263 currentElementChild = currentElement.childNodes.item(i);
19269 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19271 // Recursively traverse the tree structure of the child node
19272 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19273 lastnode = currentElementChild.nodeName;
19275 currentElementChild=currentElement.childNodes.item(i);
19281 // The remaining code is mostly for formatting the tree
19282 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19287 ret+= "</"+tagName+">";
19293 applyBlacklists : function()
19295 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19296 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19300 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19301 if (b.indexOf(tag) > -1) {
19304 this.white.push(tag);
19308 Roo.each(w, function(tag) {
19309 if (b.indexOf(tag) > -1) {
19312 if (this.white.indexOf(tag) > -1) {
19315 this.white.push(tag);
19320 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19321 if (w.indexOf(tag) > -1) {
19324 this.black.push(tag);
19328 Roo.each(b, function(tag) {
19329 if (w.indexOf(tag) > -1) {
19332 if (this.black.indexOf(tag) > -1) {
19335 this.black.push(tag);
19340 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19341 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19345 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19346 if (b.indexOf(tag) > -1) {
19349 this.cwhite.push(tag);
19353 Roo.each(w, function(tag) {
19354 if (b.indexOf(tag) > -1) {
19357 if (this.cwhite.indexOf(tag) > -1) {
19360 this.cwhite.push(tag);
19365 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19366 if (w.indexOf(tag) > -1) {
19369 this.cblack.push(tag);
19373 Roo.each(b, function(tag) {
19374 if (w.indexOf(tag) > -1) {
19377 if (this.cblack.indexOf(tag) > -1) {
19380 this.cblack.push(tag);
19385 setStylesheets : function(stylesheets)
19387 if(typeof(stylesheets) == 'string'){
19388 Roo.get(this.iframe.contentDocument.head).createChild({
19390 rel : 'stylesheet',
19399 Roo.each(stylesheets, function(s) {
19404 Roo.get(_this.iframe.contentDocument.head).createChild({
19406 rel : 'stylesheet',
19415 removeStylesheets : function()
19419 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19424 // hide stuff that is not compatible
19438 * @event specialkey
19442 * @cfg {String} fieldClass @hide
19445 * @cfg {String} focusClass @hide
19448 * @cfg {String} autoCreate @hide
19451 * @cfg {String} inputType @hide
19454 * @cfg {String} invalidClass @hide
19457 * @cfg {String} invalidText @hide
19460 * @cfg {String} msgFx @hide
19463 * @cfg {String} validateOnBlur @hide
19467 Roo.HtmlEditorCore.white = [
19468 'area', 'br', 'img', 'input', 'hr', 'wbr',
19470 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19471 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19472 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19473 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19474 'table', 'ul', 'xmp',
19476 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19479 'dir', 'menu', 'ol', 'ul', 'dl',
19485 Roo.HtmlEditorCore.black = [
19486 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19488 'base', 'basefont', 'bgsound', 'blink', 'body',
19489 'frame', 'frameset', 'head', 'html', 'ilayer',
19490 'iframe', 'layer', 'link', 'meta', 'object',
19491 'script', 'style' ,'title', 'xml' // clean later..
19493 Roo.HtmlEditorCore.clean = [
19494 'script', 'style', 'title', 'xml'
19496 Roo.HtmlEditorCore.remove = [
19501 Roo.HtmlEditorCore.ablack = [
19505 Roo.HtmlEditorCore.aclean = [
19506 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19510 Roo.HtmlEditorCore.pwhite= [
19511 'http', 'https', 'mailto'
19514 // white listed style attributes.
19515 Roo.HtmlEditorCore.cwhite= [
19516 // 'text-align', /// default is to allow most things..
19522 // black listed style attributes.
19523 Roo.HtmlEditorCore.cblack= [
19524 // 'font-size' -- this can be set by the project
19528 Roo.HtmlEditorCore.swapCodes =[
19547 * @class Roo.bootstrap.HtmlEditor
19548 * @extends Roo.bootstrap.TextArea
19549 * Bootstrap HtmlEditor class
19552 * Create a new HtmlEditor
19553 * @param {Object} config The config object
19556 Roo.bootstrap.HtmlEditor = function(config){
19557 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19558 if (!this.toolbars) {
19559 this.toolbars = [];
19561 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19564 * @event initialize
19565 * Fires when the editor is fully initialized (including the iframe)
19566 * @param {HtmlEditor} this
19571 * Fires when the editor is first receives the focus. Any insertion must wait
19572 * until after this event.
19573 * @param {HtmlEditor} this
19577 * @event beforesync
19578 * Fires before the textarea is updated with content from the editor iframe. Return false
19579 * to cancel the sync.
19580 * @param {HtmlEditor} this
19581 * @param {String} html
19585 * @event beforepush
19586 * Fires before the iframe editor is updated with content from the textarea. Return false
19587 * to cancel the push.
19588 * @param {HtmlEditor} this
19589 * @param {String} html
19594 * Fires when the textarea is updated with content from the editor iframe.
19595 * @param {HtmlEditor} this
19596 * @param {String} html
19601 * Fires when the iframe editor is updated with content from the textarea.
19602 * @param {HtmlEditor} this
19603 * @param {String} html
19607 * @event editmodechange
19608 * Fires when the editor switches edit modes
19609 * @param {HtmlEditor} this
19610 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19612 editmodechange: true,
19614 * @event editorevent
19615 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19616 * @param {HtmlEditor} this
19620 * @event firstfocus
19621 * Fires when on first focus - needed by toolbars..
19622 * @param {HtmlEditor} this
19627 * Auto save the htmlEditor value as a file into Events
19628 * @param {HtmlEditor} this
19632 * @event savedpreview
19633 * preview the saved version of htmlEditor
19634 * @param {HtmlEditor} this
19641 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19645 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19650 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19655 * @cfg {Number} height (in pixels)
19659 * @cfg {Number} width (in pixels)
19664 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19667 stylesheets: false,
19672 // private properties
19673 validationEvent : false,
19675 initialized : false,
19678 onFocus : Roo.emptyFn,
19680 hideMode:'offsets',
19683 tbContainer : false,
19685 toolbarContainer :function() {
19686 return this.wrap.select('.x-html-editor-tb',true).first();
19690 * Protected method that will not generally be called directly. It
19691 * is called when the editor creates its toolbar. Override this method if you need to
19692 * add custom toolbar buttons.
19693 * @param {HtmlEditor} editor
19695 createToolbar : function(){
19697 Roo.log("create toolbars");
19699 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19700 this.toolbars[0].render(this.toolbarContainer());
19704 // if (!editor.toolbars || !editor.toolbars.length) {
19705 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19708 // for (var i =0 ; i < editor.toolbars.length;i++) {
19709 // editor.toolbars[i] = Roo.factory(
19710 // typeof(editor.toolbars[i]) == 'string' ?
19711 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19712 // Roo.bootstrap.HtmlEditor);
19713 // editor.toolbars[i].init(editor);
19719 onRender : function(ct, position)
19721 // Roo.log("Call onRender: " + this.xtype);
19723 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19725 this.wrap = this.inputEl().wrap({
19726 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19729 this.editorcore.onRender(ct, position);
19731 if (this.resizable) {
19732 this.resizeEl = new Roo.Resizable(this.wrap, {
19736 minHeight : this.height,
19737 height: this.height,
19738 handles : this.resizable,
19741 resize : function(r, w, h) {
19742 _t.onResize(w,h); // -something
19748 this.createToolbar(this);
19751 if(!this.width && this.resizable){
19752 this.setSize(this.wrap.getSize());
19754 if (this.resizeEl) {
19755 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19756 // should trigger onReize..
19762 onResize : function(w, h)
19764 Roo.log('resize: ' +w + ',' + h );
19765 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19769 if(this.inputEl() ){
19770 if(typeof w == 'number'){
19771 var aw = w - this.wrap.getFrameWidth('lr');
19772 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19775 if(typeof h == 'number'){
19776 var tbh = -11; // fixme it needs to tool bar size!
19777 for (var i =0; i < this.toolbars.length;i++) {
19778 // fixme - ask toolbars for heights?
19779 tbh += this.toolbars[i].el.getHeight();
19780 //if (this.toolbars[i].footer) {
19781 // tbh += this.toolbars[i].footer.el.getHeight();
19789 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19790 ah -= 5; // knock a few pixes off for look..
19791 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19795 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19796 this.editorcore.onResize(ew,eh);
19801 * Toggles the editor between standard and source edit mode.
19802 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19804 toggleSourceEdit : function(sourceEditMode)
19806 this.editorcore.toggleSourceEdit(sourceEditMode);
19808 if(this.editorcore.sourceEditMode){
19809 Roo.log('editor - showing textarea');
19812 // Roo.log(this.syncValue());
19814 this.inputEl().removeClass(['hide', 'x-hidden']);
19815 this.inputEl().dom.removeAttribute('tabIndex');
19816 this.inputEl().focus();
19818 Roo.log('editor - hiding textarea');
19820 // Roo.log(this.pushValue());
19823 this.inputEl().addClass(['hide', 'x-hidden']);
19824 this.inputEl().dom.setAttribute('tabIndex', -1);
19825 //this.deferFocus();
19828 if(this.resizable){
19829 this.setSize(this.wrap.getSize());
19832 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19835 // private (for BoxComponent)
19836 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19838 // private (for BoxComponent)
19839 getResizeEl : function(){
19843 // private (for BoxComponent)
19844 getPositionEl : function(){
19849 initEvents : function(){
19850 this.originalValue = this.getValue();
19854 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19857 // markInvalid : Roo.emptyFn,
19859 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19862 // clearInvalid : Roo.emptyFn,
19864 setValue : function(v){
19865 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19866 this.editorcore.pushValue();
19871 deferFocus : function(){
19872 this.focus.defer(10, this);
19876 focus : function(){
19877 this.editorcore.focus();
19883 onDestroy : function(){
19889 for (var i =0; i < this.toolbars.length;i++) {
19890 // fixme - ask toolbars for heights?
19891 this.toolbars[i].onDestroy();
19894 this.wrap.dom.innerHTML = '';
19895 this.wrap.remove();
19900 onFirstFocus : function(){
19901 //Roo.log("onFirstFocus");
19902 this.editorcore.onFirstFocus();
19903 for (var i =0; i < this.toolbars.length;i++) {
19904 this.toolbars[i].onFirstFocus();
19910 syncValue : function()
19912 this.editorcore.syncValue();
19915 pushValue : function()
19917 this.editorcore.pushValue();
19921 // hide stuff that is not compatible
19935 * @event specialkey
19939 * @cfg {String} fieldClass @hide
19942 * @cfg {String} focusClass @hide
19945 * @cfg {String} autoCreate @hide
19948 * @cfg {String} inputType @hide
19951 * @cfg {String} invalidClass @hide
19954 * @cfg {String} invalidText @hide
19957 * @cfg {String} msgFx @hide
19960 * @cfg {String} validateOnBlur @hide
19969 Roo.namespace('Roo.bootstrap.htmleditor');
19971 * @class Roo.bootstrap.HtmlEditorToolbar1
19976 new Roo.bootstrap.HtmlEditor({
19979 new Roo.bootstrap.HtmlEditorToolbar1({
19980 disable : { fonts: 1 , format: 1, ..., ... , ...],
19986 * @cfg {Object} disable List of elements to disable..
19987 * @cfg {Array} btns List of additional buttons.
19991 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
19994 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
19997 Roo.apply(this, config);
19999 // default disabled, based on 'good practice'..
20000 this.disable = this.disable || {};
20001 Roo.applyIf(this.disable, {
20004 specialElements : true
20006 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
20008 this.editor = config.editor;
20009 this.editorcore = config.editor.editorcore;
20011 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20013 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20014 // dont call parent... till later.
20016 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20021 editorcore : false,
20026 "h1","h2","h3","h4","h5","h6",
20028 "abbr", "acronym", "address", "cite", "samp", "var",
20032 onRender : function(ct, position)
20034 // Roo.log("Call onRender: " + this.xtype);
20036 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20038 this.el.dom.style.marginBottom = '0';
20040 var editorcore = this.editorcore;
20041 var editor= this.editor;
20044 var btn = function(id,cmd , toggle, handler){
20046 var event = toggle ? 'toggle' : 'click';
20051 xns: Roo.bootstrap,
20054 enableToggle:toggle !== false,
20056 pressed : toggle ? false : null,
20059 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20060 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20069 xns: Roo.bootstrap,
20070 glyphicon : 'font',
20074 xns: Roo.bootstrap,
20078 Roo.each(this.formats, function(f) {
20079 style.menu.items.push({
20081 xns: Roo.bootstrap,
20082 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20087 editorcore.insertTag(this.tagname);
20094 children.push(style);
20097 btn('bold',false,true);
20098 btn('italic',false,true);
20099 btn('align-left', 'justifyleft',true);
20100 btn('align-center', 'justifycenter',true);
20101 btn('align-right' , 'justifyright',true);
20102 btn('link', false, false, function(btn) {
20103 //Roo.log("create link?");
20104 var url = prompt(this.createLinkText, this.defaultLinkValue);
20105 if(url && url != 'http:/'+'/'){
20106 this.editorcore.relayCmd('createlink', url);
20109 btn('list','insertunorderedlist',true);
20110 btn('pencil', false,true, function(btn){
20113 this.toggleSourceEdit(btn.pressed);
20119 xns: Roo.bootstrap,
20124 xns: Roo.bootstrap,
20129 cog.menu.items.push({
20131 xns: Roo.bootstrap,
20132 html : Clean styles,
20137 editorcore.insertTag(this.tagname);
20146 this.xtype = 'NavSimplebar';
20148 for(var i=0;i< children.length;i++) {
20150 this.buttons.add(this.addxtypeChild(children[i]));
20154 editor.on('editorevent', this.updateToolbar, this);
20156 onBtnClick : function(id)
20158 this.editorcore.relayCmd(id);
20159 this.editorcore.focus();
20163 * Protected method that will not generally be called directly. It triggers
20164 * a toolbar update by reading the markup state of the current selection in the editor.
20166 updateToolbar: function(){
20168 if(!this.editorcore.activated){
20169 this.editor.onFirstFocus(); // is this neeed?
20173 var btns = this.buttons;
20174 var doc = this.editorcore.doc;
20175 btns.get('bold').setActive(doc.queryCommandState('bold'));
20176 btns.get('italic').setActive(doc.queryCommandState('italic'));
20177 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20179 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20180 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20181 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20183 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20184 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20187 var ans = this.editorcore.getAllAncestors();
20188 if (this.formatCombo) {
20191 var store = this.formatCombo.store;
20192 this.formatCombo.setValue("");
20193 for (var i =0; i < ans.length;i++) {
20194 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20196 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20204 // hides menus... - so this cant be on a menu...
20205 Roo.bootstrap.MenuMgr.hideAll();
20207 Roo.bootstrap.MenuMgr.hideAll();
20208 //this.editorsyncValue();
20210 onFirstFocus: function() {
20211 this.buttons.each(function(item){
20215 toggleSourceEdit : function(sourceEditMode){
20218 if(sourceEditMode){
20219 Roo.log("disabling buttons");
20220 this.buttons.each( function(item){
20221 if(item.cmd != 'pencil'){
20227 Roo.log("enabling buttons");
20228 if(this.editorcore.initialized){
20229 this.buttons.each( function(item){
20235 Roo.log("calling toggole on editor");
20236 // tell the editor that it's been pressed..
20237 this.editor.toggleSourceEdit(sourceEditMode);
20247 * @class Roo.bootstrap.Table.AbstractSelectionModel
20248 * @extends Roo.util.Observable
20249 * Abstract base class for grid SelectionModels. It provides the interface that should be
20250 * implemented by descendant classes. This class should not be directly instantiated.
20253 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20254 this.locked = false;
20255 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20259 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20260 /** @ignore Called by the grid automatically. Do not call directly. */
20261 init : function(grid){
20267 * Locks the selections.
20270 this.locked = true;
20274 * Unlocks the selections.
20276 unlock : function(){
20277 this.locked = false;
20281 * Returns true if the selections are locked.
20282 * @return {Boolean}
20284 isLocked : function(){
20285 return this.locked;
20289 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20290 * @class Roo.bootstrap.Table.RowSelectionModel
20291 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20292 * It supports multiple selections and keyboard selection/navigation.
20294 * @param {Object} config
20297 Roo.bootstrap.Table.RowSelectionModel = function(config){
20298 Roo.apply(this, config);
20299 this.selections = new Roo.util.MixedCollection(false, function(o){
20304 this.lastActive = false;
20308 * @event selectionchange
20309 * Fires when the selection changes
20310 * @param {SelectionModel} this
20312 "selectionchange" : true,
20314 * @event afterselectionchange
20315 * Fires after the selection changes (eg. by key press or clicking)
20316 * @param {SelectionModel} this
20318 "afterselectionchange" : true,
20320 * @event beforerowselect
20321 * Fires when a row is selected being selected, return false to cancel.
20322 * @param {SelectionModel} this
20323 * @param {Number} rowIndex The selected index
20324 * @param {Boolean} keepExisting False if other selections will be cleared
20326 "beforerowselect" : true,
20329 * Fires when a row is selected.
20330 * @param {SelectionModel} this
20331 * @param {Number} rowIndex The selected index
20332 * @param {Roo.data.Record} r The record
20334 "rowselect" : true,
20336 * @event rowdeselect
20337 * Fires when a row is deselected.
20338 * @param {SelectionModel} this
20339 * @param {Number} rowIndex The selected index
20341 "rowdeselect" : true
20343 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20344 this.locked = false;
20347 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20349 * @cfg {Boolean} singleSelect
20350 * True to allow selection of only one row at a time (defaults to false)
20352 singleSelect : false,
20355 initEvents : function(){
20357 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20358 this.grid.on("mousedown", this.handleMouseDown, this);
20359 }else{ // allow click to work like normal
20360 this.grid.on("rowclick", this.handleDragableRowClick, this);
20363 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20364 "up" : function(e){
20366 this.selectPrevious(e.shiftKey);
20367 }else if(this.last !== false && this.lastActive !== false){
20368 var last = this.last;
20369 this.selectRange(this.last, this.lastActive-1);
20370 this.grid.getView().focusRow(this.lastActive);
20371 if(last !== false){
20375 this.selectFirstRow();
20377 this.fireEvent("afterselectionchange", this);
20379 "down" : function(e){
20381 this.selectNext(e.shiftKey);
20382 }else if(this.last !== false && this.lastActive !== false){
20383 var last = this.last;
20384 this.selectRange(this.last, this.lastActive+1);
20385 this.grid.getView().focusRow(this.lastActive);
20386 if(last !== false){
20390 this.selectFirstRow();
20392 this.fireEvent("afterselectionchange", this);
20397 var view = this.grid.view;
20398 view.on("refresh", this.onRefresh, this);
20399 view.on("rowupdated", this.onRowUpdated, this);
20400 view.on("rowremoved", this.onRemove, this);
20404 onRefresh : function(){
20405 var ds = this.grid.dataSource, i, v = this.grid.view;
20406 var s = this.selections;
20407 s.each(function(r){
20408 if((i = ds.indexOfId(r.id)) != -1){
20417 onRemove : function(v, index, r){
20418 this.selections.remove(r);
20422 onRowUpdated : function(v, index, r){
20423 if(this.isSelected(r)){
20424 v.onRowSelect(index);
20430 * @param {Array} records The records to select
20431 * @param {Boolean} keepExisting (optional) True to keep existing selections
20433 selectRecords : function(records, keepExisting){
20435 this.clearSelections();
20437 var ds = this.grid.dataSource;
20438 for(var i = 0, len = records.length; i < len; i++){
20439 this.selectRow(ds.indexOf(records[i]), true);
20444 * Gets the number of selected rows.
20447 getCount : function(){
20448 return this.selections.length;
20452 * Selects the first row in the grid.
20454 selectFirstRow : function(){
20459 * Select the last row.
20460 * @param {Boolean} keepExisting (optional) True to keep existing selections
20462 selectLastRow : function(keepExisting){
20463 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20467 * Selects the row immediately following the last selected row.
20468 * @param {Boolean} keepExisting (optional) True to keep existing selections
20470 selectNext : function(keepExisting){
20471 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20472 this.selectRow(this.last+1, keepExisting);
20473 this.grid.getView().focusRow(this.last);
20478 * Selects the row that precedes the last selected row.
20479 * @param {Boolean} keepExisting (optional) True to keep existing selections
20481 selectPrevious : function(keepExisting){
20483 this.selectRow(this.last-1, keepExisting);
20484 this.grid.getView().focusRow(this.last);
20489 * Returns the selected records
20490 * @return {Array} Array of selected records
20492 getSelections : function(){
20493 return [].concat(this.selections.items);
20497 * Returns the first selected record.
20500 getSelected : function(){
20501 return this.selections.itemAt(0);
20506 * Clears all selections.
20508 clearSelections : function(fast){
20509 if(this.locked) return;
20511 var ds = this.grid.dataSource;
20512 var s = this.selections;
20513 s.each(function(r){
20514 this.deselectRow(ds.indexOfId(r.id));
20518 this.selections.clear();
20525 * Selects all rows.
20527 selectAll : function(){
20528 if(this.locked) return;
20529 this.selections.clear();
20530 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20531 this.selectRow(i, true);
20536 * Returns True if there is a selection.
20537 * @return {Boolean}
20539 hasSelection : function(){
20540 return this.selections.length > 0;
20544 * Returns True if the specified row is selected.
20545 * @param {Number/Record} record The record or index of the record to check
20546 * @return {Boolean}
20548 isSelected : function(index){
20549 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20550 return (r && this.selections.key(r.id) ? true : false);
20554 * Returns True if the specified record id is selected.
20555 * @param {String} id The id of record to check
20556 * @return {Boolean}
20558 isIdSelected : function(id){
20559 return (this.selections.key(id) ? true : false);
20563 handleMouseDown : function(e, t){
20564 var view = this.grid.getView(), rowIndex;
20565 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20568 if(e.shiftKey && this.last !== false){
20569 var last = this.last;
20570 this.selectRange(last, rowIndex, e.ctrlKey);
20571 this.last = last; // reset the last
20572 view.focusRow(rowIndex);
20574 var isSelected = this.isSelected(rowIndex);
20575 if(e.button !== 0 && isSelected){
20576 view.focusRow(rowIndex);
20577 }else if(e.ctrlKey && isSelected){
20578 this.deselectRow(rowIndex);
20579 }else if(!isSelected){
20580 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20581 view.focusRow(rowIndex);
20584 this.fireEvent("afterselectionchange", this);
20587 handleDragableRowClick : function(grid, rowIndex, e)
20589 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20590 this.selectRow(rowIndex, false);
20591 grid.view.focusRow(rowIndex);
20592 this.fireEvent("afterselectionchange", this);
20597 * Selects multiple rows.
20598 * @param {Array} rows Array of the indexes of the row to select
20599 * @param {Boolean} keepExisting (optional) True to keep existing selections
20601 selectRows : function(rows, keepExisting){
20603 this.clearSelections();
20605 for(var i = 0, len = rows.length; i < len; i++){
20606 this.selectRow(rows[i], true);
20611 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20612 * @param {Number} startRow The index of the first row in the range
20613 * @param {Number} endRow The index of the last row in the range
20614 * @param {Boolean} keepExisting (optional) True to retain existing selections
20616 selectRange : function(startRow, endRow, keepExisting){
20617 if(this.locked) return;
20619 this.clearSelections();
20621 if(startRow <= endRow){
20622 for(var i = startRow; i <= endRow; i++){
20623 this.selectRow(i, true);
20626 for(var i = startRow; i >= endRow; i--){
20627 this.selectRow(i, true);
20633 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20634 * @param {Number} startRow The index of the first row in the range
20635 * @param {Number} endRow The index of the last row in the range
20637 deselectRange : function(startRow, endRow, preventViewNotify){
20638 if(this.locked) return;
20639 for(var i = startRow; i <= endRow; i++){
20640 this.deselectRow(i, preventViewNotify);
20646 * @param {Number} row The index of the row to select
20647 * @param {Boolean} keepExisting (optional) True to keep existing selections
20649 selectRow : function(index, keepExisting, preventViewNotify){
20650 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20651 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20652 if(!keepExisting || this.singleSelect){
20653 this.clearSelections();
20655 var r = this.grid.dataSource.getAt(index);
20656 this.selections.add(r);
20657 this.last = this.lastActive = index;
20658 if(!preventViewNotify){
20659 this.grid.getView().onRowSelect(index);
20661 this.fireEvent("rowselect", this, index, r);
20662 this.fireEvent("selectionchange", this);
20668 * @param {Number} row The index of the row to deselect
20670 deselectRow : function(index, preventViewNotify){
20671 if(this.locked) return;
20672 if(this.last == index){
20675 if(this.lastActive == index){
20676 this.lastActive = false;
20678 var r = this.grid.dataSource.getAt(index);
20679 this.selections.remove(r);
20680 if(!preventViewNotify){
20681 this.grid.getView().onRowDeselect(index);
20683 this.fireEvent("rowdeselect", this, index);
20684 this.fireEvent("selectionchange", this);
20688 restoreLast : function(){
20690 this.last = this._last;
20695 acceptsNav : function(row, col, cm){
20696 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20700 onEditorKey : function(field, e){
20701 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20706 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20708 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20710 }else if(k == e.ENTER && !e.ctrlKey){
20714 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20716 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20718 }else if(k == e.ESC){
20722 g.startEditing(newCell[0], newCell[1]);
20727 * Ext JS Library 1.1.1
20728 * Copyright(c) 2006-2007, Ext JS, LLC.
20730 * Originally Released Under LGPL - original licence link has changed is not relivant.
20733 * <script type="text/javascript">
20737 * @class Roo.bootstrap.PagingToolbar
20739 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20741 * Create a new PagingToolbar
20742 * @param {Object} config The config object
20744 Roo.bootstrap.PagingToolbar = function(config)
20746 // old args format still supported... - xtype is prefered..
20747 // created from xtype...
20748 var ds = config.dataSource;
20749 this.toolbarItems = [];
20750 if (config.items) {
20751 this.toolbarItems = config.items;
20752 // config.items = [];
20755 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20762 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20766 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20768 * @cfg {Roo.data.Store} dataSource
20769 * The underlying data store providing the paged data
20772 * @cfg {String/HTMLElement/Element} container
20773 * container The id or element that will contain the toolbar
20776 * @cfg {Boolean} displayInfo
20777 * True to display the displayMsg (defaults to false)
20780 * @cfg {Number} pageSize
20781 * The number of records to display per page (defaults to 20)
20785 * @cfg {String} displayMsg
20786 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20788 displayMsg : 'Displaying {0} - {1} of {2}',
20790 * @cfg {String} emptyMsg
20791 * The message to display when no records are found (defaults to "No data to display")
20793 emptyMsg : 'No data to display',
20795 * Customizable piece of the default paging text (defaults to "Page")
20798 beforePageText : "Page",
20800 * Customizable piece of the default paging text (defaults to "of %0")
20803 afterPageText : "of {0}",
20805 * Customizable piece of the default paging text (defaults to "First Page")
20808 firstText : "First Page",
20810 * Customizable piece of the default paging text (defaults to "Previous Page")
20813 prevText : "Previous Page",
20815 * Customizable piece of the default paging text (defaults to "Next Page")
20818 nextText : "Next Page",
20820 * Customizable piece of the default paging text (defaults to "Last Page")
20823 lastText : "Last Page",
20825 * Customizable piece of the default paging text (defaults to "Refresh")
20828 refreshText : "Refresh",
20832 onRender : function(ct, position)
20834 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20835 this.navgroup.parentId = this.id;
20836 this.navgroup.onRender(this.el, null);
20837 // add the buttons to the navgroup
20839 if(this.displayInfo){
20840 Roo.log(this.el.select('ul.navbar-nav',true).first());
20841 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20842 this.displayEl = this.el.select('.x-paging-info', true).first();
20843 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20844 // this.displayEl = navel.el.select('span',true).first();
20850 Roo.each(_this.buttons, function(e){
20851 Roo.factory(e).onRender(_this.el, null);
20855 Roo.each(_this.toolbarItems, function(e) {
20856 _this.navgroup.addItem(e);
20860 this.first = this.navgroup.addItem({
20861 tooltip: this.firstText,
20863 icon : 'fa fa-backward',
20865 preventDefault: true,
20866 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20869 this.prev = this.navgroup.addItem({
20870 tooltip: this.prevText,
20872 icon : 'fa fa-step-backward',
20874 preventDefault: true,
20875 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20877 //this.addSeparator();
20880 var field = this.navgroup.addItem( {
20882 cls : 'x-paging-position',
20884 html : this.beforePageText +
20885 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20886 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20889 this.field = field.el.select('input', true).first();
20890 this.field.on("keydown", this.onPagingKeydown, this);
20891 this.field.on("focus", function(){this.dom.select();});
20894 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20895 //this.field.setHeight(18);
20896 //this.addSeparator();
20897 this.next = this.navgroup.addItem({
20898 tooltip: this.nextText,
20900 html : ' <i class="fa fa-step-forward">',
20902 preventDefault: true,
20903 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20905 this.last = this.navgroup.addItem({
20906 tooltip: this.lastText,
20907 icon : 'fa fa-forward',
20910 preventDefault: true,
20911 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20913 //this.addSeparator();
20914 this.loading = this.navgroup.addItem({
20915 tooltip: this.refreshText,
20916 icon: 'fa fa-refresh',
20917 preventDefault: true,
20918 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20924 updateInfo : function(){
20925 if(this.displayEl){
20926 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20927 var msg = count == 0 ?
20931 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20933 this.displayEl.update(msg);
20938 onLoad : function(ds, r, o){
20939 this.cursor = o.params ? o.params.start : 0;
20940 var d = this.getPageData(),
20944 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20945 this.field.dom.value = ap;
20946 this.first.setDisabled(ap == 1);
20947 this.prev.setDisabled(ap == 1);
20948 this.next.setDisabled(ap == ps);
20949 this.last.setDisabled(ap == ps);
20950 this.loading.enable();
20955 getPageData : function(){
20956 var total = this.ds.getTotalCount();
20959 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20960 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20965 onLoadError : function(){
20966 this.loading.enable();
20970 onPagingKeydown : function(e){
20971 var k = e.getKey();
20972 var d = this.getPageData();
20974 var v = this.field.dom.value, pageNum;
20975 if(!v || isNaN(pageNum = parseInt(v, 10))){
20976 this.field.dom.value = d.activePage;
20979 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
20980 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
20983 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))
20985 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
20986 this.field.dom.value = pageNum;
20987 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
20990 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20992 var v = this.field.dom.value, pageNum;
20993 var increment = (e.shiftKey) ? 10 : 1;
20994 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
20996 if(!v || isNaN(pageNum = parseInt(v, 10))) {
20997 this.field.dom.value = d.activePage;
21000 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
21002 this.field.dom.value = parseInt(v, 10) + increment;
21003 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
21004 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21011 beforeLoad : function(){
21013 this.loading.disable();
21018 onClick : function(which){
21027 ds.load({params:{start: 0, limit: this.pageSize}});
21030 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21033 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21036 var total = ds.getTotalCount();
21037 var extra = total % this.pageSize;
21038 var lastStart = extra ? (total - extra) : total-this.pageSize;
21039 ds.load({params:{start: lastStart, limit: this.pageSize}});
21042 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21048 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21049 * @param {Roo.data.Store} store The data store to unbind
21051 unbind : function(ds){
21052 ds.un("beforeload", this.beforeLoad, this);
21053 ds.un("load", this.onLoad, this);
21054 ds.un("loadexception", this.onLoadError, this);
21055 ds.un("remove", this.updateInfo, this);
21056 ds.un("add", this.updateInfo, this);
21057 this.ds = undefined;
21061 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21062 * @param {Roo.data.Store} store The data store to bind
21064 bind : function(ds){
21065 ds.on("beforeload", this.beforeLoad, this);
21066 ds.on("load", this.onLoad, this);
21067 ds.on("loadexception", this.onLoadError, this);
21068 ds.on("remove", this.updateInfo, this);
21069 ds.on("add", this.updateInfo, this);
21080 * @class Roo.bootstrap.MessageBar
21081 * @extends Roo.bootstrap.Component
21082 * Bootstrap MessageBar class
21083 * @cfg {String} html contents of the MessageBar
21084 * @cfg {String} weight (info | success | warning | danger) default info
21085 * @cfg {String} beforeClass insert the bar before the given class
21086 * @cfg {Boolean} closable (true | false) default false
21087 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21090 * Create a new Element
21091 * @param {Object} config The config object
21094 Roo.bootstrap.MessageBar = function(config){
21095 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21098 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21104 beforeClass: 'bootstrap-sticky-wrap',
21106 getAutoCreate : function(){
21110 cls: 'alert alert-dismissable alert-' + this.weight,
21115 html: this.html || ''
21121 cfg.cls += ' alert-messages-fixed';
21135 onRender : function(ct, position)
21137 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21140 var cfg = Roo.apply({}, this.getAutoCreate());
21144 cfg.cls += ' ' + this.cls;
21147 cfg.style = this.style;
21149 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21151 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21154 this.el.select('>button.close').on('click', this.hide, this);
21160 if (!this.rendered) {
21166 this.fireEvent('show', this);
21172 if (!this.rendered) {
21178 this.fireEvent('hide', this);
21181 update : function()
21183 // var e = this.el.dom.firstChild;
21185 // if(this.closable){
21186 // e = e.nextSibling;
21189 // e.data = this.html || '';
21191 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21207 * @class Roo.bootstrap.Graph
21208 * @extends Roo.bootstrap.Component
21209 * Bootstrap Graph class
21213 @cfg {String} graphtype bar | vbar | pie
21214 @cfg {number} g_x coodinator | centre x (pie)
21215 @cfg {number} g_y coodinator | centre y (pie)
21216 @cfg {number} g_r radius (pie)
21217 @cfg {number} g_height height of the chart (respected by all elements in the set)
21218 @cfg {number} g_width width of the chart (respected by all elements in the set)
21219 @cfg {Object} title The title of the chart
21222 -opts (object) options for the chart
21224 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21225 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21227 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.
21228 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21230 o stretch (boolean)
21232 -opts (object) options for the pie
21235 o startAngle (number)
21236 o endAngle (number)
21240 * Create a new Input
21241 * @param {Object} config The config object
21244 Roo.bootstrap.Graph = function(config){
21245 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21251 * The img click event for the img.
21252 * @param {Roo.EventObject} e
21258 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21269 //g_colors: this.colors,
21276 getAutoCreate : function(){
21287 onRender : function(ct,position){
21288 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21289 this.raphael = Raphael(this.el.dom);
21291 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21292 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21293 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21294 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21296 r.text(160, 10, "Single Series Chart").attr(txtattr);
21297 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21298 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21299 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21301 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21302 r.barchart(330, 10, 300, 220, data1);
21303 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21304 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21307 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21308 // r.barchart(30, 30, 560, 250, xdata, {
21309 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21310 // axis : "0 0 1 1",
21311 // axisxlabels : xdata
21312 // //yvalues : cols,
21315 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21317 // this.load(null,xdata,{
21318 // axis : "0 0 1 1",
21319 // axisxlabels : xdata
21324 load : function(graphtype,xdata,opts){
21325 this.raphael.clear();
21327 graphtype = this.graphtype;
21332 var r = this.raphael,
21333 fin = function () {
21334 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21336 fout = function () {
21337 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21339 pfin = function() {
21340 this.sector.stop();
21341 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21344 this.label[0].stop();
21345 this.label[0].attr({ r: 7.5 });
21346 this.label[1].attr({ "font-weight": 800 });
21349 pfout = function() {
21350 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21353 this.label[0].animate({ r: 5 }, 500, "bounce");
21354 this.label[1].attr({ "font-weight": 400 });
21360 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21363 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21366 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21367 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21369 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21376 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21381 setTitle: function(o)
21386 initEvents: function() {
21389 this.el.on('click', this.onClick, this);
21393 onClick : function(e)
21395 Roo.log('img onclick');
21396 this.fireEvent('click', this, e);
21408 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21411 * @class Roo.bootstrap.dash.NumberBox
21412 * @extends Roo.bootstrap.Component
21413 * Bootstrap NumberBox class
21414 * @cfg {String} headline Box headline
21415 * @cfg {String} content Box content
21416 * @cfg {String} icon Box icon
21417 * @cfg {String} footer Footer text
21418 * @cfg {String} fhref Footer href
21421 * Create a new NumberBox
21422 * @param {Object} config The config object
21426 Roo.bootstrap.dash.NumberBox = function(config){
21427 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21431 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21440 getAutoCreate : function(){
21444 cls : 'small-box ',
21452 cls : 'roo-headline',
21453 html : this.headline
21457 cls : 'roo-content',
21458 html : this.content
21472 cls : 'ion ' + this.icon
21481 cls : 'small-box-footer',
21482 href : this.fhref || '#',
21486 cfg.cn.push(footer);
21493 onRender : function(ct,position){
21494 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21501 setHeadline: function (value)
21503 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21506 setFooter: function (value, href)
21508 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21511 this.el.select('a.small-box-footer',true).first().attr('href', href);
21516 setContent: function (value)
21518 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21521 initEvents: function()
21535 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21538 * @class Roo.bootstrap.dash.TabBox
21539 * @extends Roo.bootstrap.Component
21540 * Bootstrap TabBox class
21541 * @cfg {String} title Title of the TabBox
21542 * @cfg {String} icon Icon of the TabBox
21543 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21544 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21547 * Create a new TabBox
21548 * @param {Object} config The config object
21552 Roo.bootstrap.dash.TabBox = function(config){
21553 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21558 * When a pane is added
21559 * @param {Roo.bootstrap.dash.TabPane} pane
21563 * @event activatepane
21564 * When a pane is activated
21565 * @param {Roo.bootstrap.dash.TabPane} pane
21567 "activatepane" : true
21575 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21580 tabScrollable : false,
21582 getChildContainer : function()
21584 return this.el.select('.tab-content', true).first();
21587 getAutoCreate : function(){
21591 cls: 'pull-left header',
21599 cls: 'fa ' + this.icon
21605 cls: 'nav nav-tabs pull-right',
21611 if(this.tabScrollable){
21618 cls: 'nav nav-tabs pull-right',
21629 cls: 'nav-tabs-custom',
21634 cls: 'tab-content no-padding',
21642 initEvents : function()
21644 //Roo.log('add add pane handler');
21645 this.on('addpane', this.onAddPane, this);
21648 * Updates the box title
21649 * @param {String} html to set the title to.
21651 setTitle : function(value)
21653 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21655 onAddPane : function(pane)
21657 this.panes.push(pane);
21658 //Roo.log('addpane');
21660 // tabs are rendere left to right..
21661 if(!this.showtabs){
21665 var ctr = this.el.select('.nav-tabs', true).first();
21668 var existing = ctr.select('.nav-tab',true);
21669 var qty = existing.getCount();;
21672 var tab = ctr.createChild({
21674 cls : 'nav-tab' + (qty ? '' : ' active'),
21682 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21685 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21687 pane.el.addClass('active');
21692 onTabClick : function(ev,un,ob,pane)
21694 //Roo.log('tab - prev default');
21695 ev.preventDefault();
21698 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21699 pane.tab.addClass('active');
21700 //Roo.log(pane.title);
21701 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21702 // technically we should have a deactivate event.. but maybe add later.
21703 // and it should not de-activate the selected tab...
21704 this.fireEvent('activatepane', pane);
21705 pane.el.addClass('active');
21706 pane.fireEvent('activate');
21711 getActivePane : function()
21714 Roo.each(this.panes, function(p) {
21715 if(p.el.hasClass('active')){
21736 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21738 * @class Roo.bootstrap.TabPane
21739 * @extends Roo.bootstrap.Component
21740 * Bootstrap TabPane class
21741 * @cfg {Boolean} active (false | true) Default false
21742 * @cfg {String} title title of panel
21746 * Create a new TabPane
21747 * @param {Object} config The config object
21750 Roo.bootstrap.dash.TabPane = function(config){
21751 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21757 * When a pane is activated
21758 * @param {Roo.bootstrap.dash.TabPane} pane
21765 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21770 // the tabBox that this is attached to.
21773 getAutoCreate : function()
21781 cfg.cls += ' active';
21786 initEvents : function()
21788 //Roo.log('trigger add pane handler');
21789 this.parent().fireEvent('addpane', this)
21793 * Updates the tab title
21794 * @param {String} html to set the title to.
21796 setTitle: function(str)
21802 this.tab.select('a', true).first().dom.innerHTML = str;
21819 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21822 * @class Roo.bootstrap.menu.Menu
21823 * @extends Roo.bootstrap.Component
21824 * Bootstrap Menu class - container for Menu
21825 * @cfg {String} html Text of the menu
21826 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21827 * @cfg {String} icon Font awesome icon
21828 * @cfg {String} pos Menu align to (top | bottom) default bottom
21832 * Create a new Menu
21833 * @param {Object} config The config object
21837 Roo.bootstrap.menu.Menu = function(config){
21838 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21842 * @event beforeshow
21843 * Fires before this menu is displayed
21844 * @param {Roo.bootstrap.menu.Menu} this
21848 * @event beforehide
21849 * Fires before this menu is hidden
21850 * @param {Roo.bootstrap.menu.Menu} this
21855 * Fires after this menu is displayed
21856 * @param {Roo.bootstrap.menu.Menu} this
21861 * Fires after this menu is hidden
21862 * @param {Roo.bootstrap.menu.Menu} this
21867 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21868 * @param {Roo.bootstrap.menu.Menu} this
21869 * @param {Roo.EventObject} e
21876 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21880 weight : 'default',
21885 getChildContainer : function() {
21886 if(this.isSubMenu){
21890 return this.el.select('ul.dropdown-menu', true).first();
21893 getAutoCreate : function()
21898 cls : 'roo-menu-text',
21906 cls : 'fa ' + this.icon
21917 cls : 'dropdown-button btn btn-' + this.weight,
21922 cls : 'dropdown-toggle btn btn-' + this.weight,
21932 cls : 'dropdown-menu'
21938 if(this.pos == 'top'){
21939 cfg.cls += ' dropup';
21942 if(this.isSubMenu){
21945 cls : 'dropdown-menu'
21952 onRender : function(ct, position)
21954 this.isSubMenu = ct.hasClass('dropdown-submenu');
21956 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21959 initEvents : function()
21961 if(this.isSubMenu){
21965 this.hidden = true;
21967 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21968 this.triggerEl.on('click', this.onTriggerPress, this);
21970 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21971 this.buttonEl.on('click', this.onClick, this);
21977 if(this.isSubMenu){
21981 return this.el.select('ul.dropdown-menu', true).first();
21984 onClick : function(e)
21986 this.fireEvent("click", this, e);
21989 onTriggerPress : function(e)
21991 if (this.isVisible()) {
21998 isVisible : function(){
21999 return !this.hidden;
22004 this.fireEvent("beforeshow", this);
22006 this.hidden = false;
22007 this.el.addClass('open');
22009 Roo.get(document).on("mouseup", this.onMouseUp, this);
22011 this.fireEvent("show", this);
22018 this.fireEvent("beforehide", this);
22020 this.hidden = true;
22021 this.el.removeClass('open');
22023 Roo.get(document).un("mouseup", this.onMouseUp);
22025 this.fireEvent("hide", this);
22028 onMouseUp : function()
22042 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22045 * @class Roo.bootstrap.menu.Item
22046 * @extends Roo.bootstrap.Component
22047 * Bootstrap MenuItem class
22048 * @cfg {Boolean} submenu (true | false) default false
22049 * @cfg {String} html text of the item
22050 * @cfg {String} href the link
22051 * @cfg {Boolean} disable (true | false) default false
22052 * @cfg {Boolean} preventDefault (true | false) default true
22053 * @cfg {String} icon Font awesome icon
22054 * @cfg {String} pos Submenu align to (left | right) default right
22058 * Create a new Item
22059 * @param {Object} config The config object
22063 Roo.bootstrap.menu.Item = function(config){
22064 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22068 * Fires when the mouse is hovering over this menu
22069 * @param {Roo.bootstrap.menu.Item} this
22070 * @param {Roo.EventObject} e
22075 * Fires when the mouse exits this menu
22076 * @param {Roo.bootstrap.menu.Item} this
22077 * @param {Roo.EventObject} e
22083 * The raw click event for the entire grid.
22084 * @param {Roo.EventObject} e
22090 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22095 preventDefault: true,
22100 getAutoCreate : function()
22105 cls : 'roo-menu-item-text',
22113 cls : 'fa ' + this.icon
22122 href : this.href || '#',
22129 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22133 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22135 if(this.pos == 'left'){
22136 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22143 initEvents : function()
22145 this.el.on('mouseover', this.onMouseOver, this);
22146 this.el.on('mouseout', this.onMouseOut, this);
22148 this.el.select('a', true).first().on('click', this.onClick, this);
22152 onClick : function(e)
22154 if(this.preventDefault){
22155 e.preventDefault();
22158 this.fireEvent("click", this, e);
22161 onMouseOver : function(e)
22163 if(this.submenu && this.pos == 'left'){
22164 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
22167 this.fireEvent("mouseover", this, e);
22170 onMouseOut : function(e)
22172 this.fireEvent("mouseout", this, e);
22184 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22187 * @class Roo.bootstrap.menu.Separator
22188 * @extends Roo.bootstrap.Component
22189 * Bootstrap Separator class
22192 * Create a new Separator
22193 * @param {Object} config The config object
22197 Roo.bootstrap.menu.Separator = function(config){
22198 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22201 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22203 getAutoCreate : function(){
22224 * @class Roo.bootstrap.Tooltip
22225 * Bootstrap Tooltip class
22226 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22227 * to determine which dom element triggers the tooltip.
22229 * It needs to add support for additional attributes like tooltip-position
22232 * Create a new Toolti
22233 * @param {Object} config The config object
22236 Roo.bootstrap.Tooltip = function(config){
22237 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22240 Roo.apply(Roo.bootstrap.Tooltip, {
22242 * @function init initialize tooltip monitoring.
22246 currentTip : false,
22247 currentRegion : false,
22253 Roo.get(document).on('mouseover', this.enter ,this);
22254 Roo.get(document).on('mouseout', this.leave, this);
22257 this.currentTip = new Roo.bootstrap.Tooltip();
22260 enter : function(ev)
22262 var dom = ev.getTarget();
22264 //Roo.log(['enter',dom]);
22265 var el = Roo.fly(dom);
22266 if (this.currentEl) {
22268 //Roo.log(this.currentEl);
22269 //Roo.log(this.currentEl.contains(dom));
22270 if (this.currentEl == el) {
22273 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22281 if (this.currentTip.el) {
22282 this.currentTip.el.hide(); // force hiding...
22287 // you can not look for children, as if el is the body.. then everythign is the child..
22288 if (!el.attr('tooltip')) { //
22289 if (!el.select("[tooltip]").elements.length) {
22292 // is the mouse over this child...?
22293 bindEl = el.select("[tooltip]").first();
22294 var xy = ev.getXY();
22295 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22296 //Roo.log("not in region.");
22299 //Roo.log("child element over..");
22302 this.currentEl = bindEl;
22303 this.currentTip.bind(bindEl);
22304 this.currentRegion = Roo.lib.Region.getRegion(dom);
22305 this.currentTip.enter();
22308 leave : function(ev)
22310 var dom = ev.getTarget();
22311 //Roo.log(['leave',dom]);
22312 if (!this.currentEl) {
22317 if (dom != this.currentEl.dom) {
22320 var xy = ev.getXY();
22321 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22324 // only activate leave if mouse cursor is outside... bounding box..
22329 if (this.currentTip) {
22330 this.currentTip.leave();
22332 //Roo.log('clear currentEl');
22333 this.currentEl = false;
22338 'left' : ['r-l', [-2,0], 'right'],
22339 'right' : ['l-r', [2,0], 'left'],
22340 'bottom' : ['t-b', [0,2], 'top'],
22341 'top' : [ 'b-t', [0,-2], 'bottom']
22347 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22352 delay : null, // can be { show : 300 , hide: 500}
22356 hoverState : null, //???
22358 placement : 'bottom',
22360 getAutoCreate : function(){
22367 cls : 'tooltip-arrow'
22370 cls : 'tooltip-inner'
22377 bind : function(el)
22383 enter : function () {
22385 if (this.timeout != null) {
22386 clearTimeout(this.timeout);
22389 this.hoverState = 'in';
22390 //Roo.log("enter - show");
22391 if (!this.delay || !this.delay.show) {
22396 this.timeout = setTimeout(function () {
22397 if (_t.hoverState == 'in') {
22400 }, this.delay.show);
22404 clearTimeout(this.timeout);
22406 this.hoverState = 'out';
22407 if (!this.delay || !this.delay.hide) {
22413 this.timeout = setTimeout(function () {
22414 //Roo.log("leave - timeout");
22416 if (_t.hoverState == 'out') {
22418 Roo.bootstrap.Tooltip.currentEl = false;
22426 this.render(document.body);
22429 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22431 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22433 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22435 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22437 var placement = typeof this.placement == 'function' ?
22438 this.placement.call(this, this.el, on_el) :
22441 var autoToken = /\s?auto?\s?/i;
22442 var autoPlace = autoToken.test(placement);
22444 placement = placement.replace(autoToken, '') || 'top';
22448 //this.el.setXY([0,0]);
22450 //this.el.dom.style.display='block';
22451 this.el.addClass(placement);
22453 //this.el.appendTo(on_el);
22455 var p = this.getPosition();
22456 var box = this.el.getBox();
22461 var align = Roo.bootstrap.Tooltip.alignment[placement];
22462 this.el.alignTo(this.bindEl, align[0],align[1]);
22463 //var arrow = this.el.select('.arrow',true).first();
22464 //arrow.set(align[2],
22466 this.el.addClass('in fade');
22467 this.hoverState = null;
22469 if (this.el.hasClass('fade')) {
22480 //this.el.setXY([0,0]);
22481 this.el.removeClass('in');
22497 * @class Roo.bootstrap.LocationPicker
22498 * @extends Roo.bootstrap.Component
22499 * Bootstrap LocationPicker class
22500 * @cfg {Number} latitude Position when init default 0
22501 * @cfg {Number} longitude Position when init default 0
22502 * @cfg {Number} zoom default 15
22503 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22504 * @cfg {Boolean} mapTypeControl default false
22505 * @cfg {Boolean} disableDoubleClickZoom default false
22506 * @cfg {Boolean} scrollwheel default true
22507 * @cfg {Boolean} streetViewControl default false
22508 * @cfg {Number} radius default 0
22509 * @cfg {String} locationName
22510 * @cfg {Boolean} draggable default true
22511 * @cfg {Boolean} enableAutocomplete default false
22512 * @cfg {Boolean} enableReverseGeocode default true
22513 * @cfg {String} markerTitle
22516 * Create a new LocationPicker
22517 * @param {Object} config The config object
22521 Roo.bootstrap.LocationPicker = function(config){
22523 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22528 * Fires when the picker initialized.
22529 * @param {Roo.bootstrap.LocationPicker} this
22530 * @param {Google Location} location
22534 * @event positionchanged
22535 * Fires when the picker position changed.
22536 * @param {Roo.bootstrap.LocationPicker} this
22537 * @param {Google Location} location
22539 positionchanged : true,
22542 * Fires when the map resize.
22543 * @param {Roo.bootstrap.LocationPicker} this
22548 * Fires when the map show.
22549 * @param {Roo.bootstrap.LocationPicker} this
22554 * Fires when the map hide.
22555 * @param {Roo.bootstrap.LocationPicker} this
22560 * Fires when click the map.
22561 * @param {Roo.bootstrap.LocationPicker} this
22562 * @param {Map event} e
22566 * @event mapRightClick
22567 * Fires when right click the map.
22568 * @param {Roo.bootstrap.LocationPicker} this
22569 * @param {Map event} e
22571 mapRightClick : true,
22573 * @event markerClick
22574 * Fires when click the marker.
22575 * @param {Roo.bootstrap.LocationPicker} this
22576 * @param {Map event} e
22578 markerClick : true,
22580 * @event markerRightClick
22581 * Fires when right click the marker.
22582 * @param {Roo.bootstrap.LocationPicker} this
22583 * @param {Map event} e
22585 markerRightClick : true,
22587 * @event OverlayViewDraw
22588 * Fires when OverlayView Draw
22589 * @param {Roo.bootstrap.LocationPicker} this
22591 OverlayViewDraw : true,
22593 * @event OverlayViewOnAdd
22594 * Fires when OverlayView Draw
22595 * @param {Roo.bootstrap.LocationPicker} this
22597 OverlayViewOnAdd : true,
22599 * @event OverlayViewOnRemove
22600 * Fires when OverlayView Draw
22601 * @param {Roo.bootstrap.LocationPicker} this
22603 OverlayViewOnRemove : true,
22605 * @event OverlayViewShow
22606 * Fires when OverlayView Draw
22607 * @param {Roo.bootstrap.LocationPicker} this
22608 * @param {Pixel} cpx
22610 OverlayViewShow : true,
22612 * @event OverlayViewHide
22613 * Fires when OverlayView Draw
22614 * @param {Roo.bootstrap.LocationPicker} this
22616 OverlayViewHide : true
22621 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22623 gMapContext: false,
22629 mapTypeControl: false,
22630 disableDoubleClickZoom: false,
22632 streetViewControl: false,
22636 enableAutocomplete: false,
22637 enableReverseGeocode: true,
22640 getAutoCreate: function()
22645 cls: 'roo-location-picker'
22651 initEvents: function(ct, position)
22653 if(!this.el.getWidth() || this.isApplied()){
22657 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22662 initial: function()
22664 if(!this.mapTypeId){
22665 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22668 this.gMapContext = this.GMapContext();
22670 this.initOverlayView();
22672 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22676 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22677 _this.setPosition(_this.gMapContext.marker.position);
22680 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22681 _this.fireEvent('mapClick', this, event);
22685 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22686 _this.fireEvent('mapRightClick', this, event);
22690 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22691 _this.fireEvent('markerClick', this, event);
22695 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22696 _this.fireEvent('markerRightClick', this, event);
22700 this.setPosition(this.gMapContext.location);
22702 this.fireEvent('initial', this, this.gMapContext.location);
22705 initOverlayView: function()
22709 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22713 _this.fireEvent('OverlayViewDraw', _this);
22718 _this.fireEvent('OverlayViewOnAdd', _this);
22721 onRemove: function()
22723 _this.fireEvent('OverlayViewOnRemove', _this);
22726 show: function(cpx)
22728 _this.fireEvent('OverlayViewShow', _this, cpx);
22733 _this.fireEvent('OverlayViewHide', _this);
22739 fromLatLngToContainerPixel: function(event)
22741 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22744 isApplied: function()
22746 return this.getGmapContext() == false ? false : true;
22749 getGmapContext: function()
22751 return this.gMapContext
22754 GMapContext: function()
22756 var position = new google.maps.LatLng(this.latitude, this.longitude);
22758 var _map = new google.maps.Map(this.el.dom, {
22761 mapTypeId: this.mapTypeId,
22762 mapTypeControl: this.mapTypeControl,
22763 disableDoubleClickZoom: this.disableDoubleClickZoom,
22764 scrollwheel: this.scrollwheel,
22765 streetViewControl: this.streetViewControl,
22766 locationName: this.locationName,
22767 draggable: this.draggable,
22768 enableAutocomplete: this.enableAutocomplete,
22769 enableReverseGeocode: this.enableReverseGeocode
22772 var _marker = new google.maps.Marker({
22773 position: position,
22775 title: this.markerTitle,
22776 draggable: this.draggable
22783 location: position,
22784 radius: this.radius,
22785 locationName: this.locationName,
22786 addressComponents: {
22787 formatted_address: null,
22788 addressLine1: null,
22789 addressLine2: null,
22791 streetNumber: null,
22795 stateOrProvince: null
22798 domContainer: this.el.dom,
22799 geodecoder: new google.maps.Geocoder()
22803 drawCircle: function(center, radius, options)
22805 if (this.gMapContext.circle != null) {
22806 this.gMapContext.circle.setMap(null);
22810 options = Roo.apply({}, options, {
22811 strokeColor: "#0000FF",
22812 strokeOpacity: .35,
22814 fillColor: "#0000FF",
22818 options.map = this.gMapContext.map;
22819 options.radius = radius;
22820 options.center = center;
22821 this.gMapContext.circle = new google.maps.Circle(options);
22822 return this.gMapContext.circle;
22828 setPosition: function(location)
22830 this.gMapContext.location = location;
22831 this.gMapContext.marker.setPosition(location);
22832 this.gMapContext.map.panTo(location);
22833 this.drawCircle(location, this.gMapContext.radius, {});
22837 if (this.gMapContext.settings.enableReverseGeocode) {
22838 this.gMapContext.geodecoder.geocode({
22839 latLng: this.gMapContext.location
22840 }, function(results, status) {
22842 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22843 _this.gMapContext.locationName = results[0].formatted_address;
22844 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22846 _this.fireEvent('positionchanged', this, location);
22853 this.fireEvent('positionchanged', this, location);
22858 google.maps.event.trigger(this.gMapContext.map, "resize");
22860 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22862 this.fireEvent('resize', this);
22865 setPositionByLatLng: function(latitude, longitude)
22867 this.setPosition(new google.maps.LatLng(latitude, longitude));
22870 getCurrentPosition: function()
22873 latitude: this.gMapContext.location.lat(),
22874 longitude: this.gMapContext.location.lng()
22878 getAddressName: function()
22880 return this.gMapContext.locationName;
22883 getAddressComponents: function()
22885 return this.gMapContext.addressComponents;
22888 address_component_from_google_geocode: function(address_components)
22892 for (var i = 0; i < address_components.length; i++) {
22893 var component = address_components[i];
22894 if (component.types.indexOf("postal_code") >= 0) {
22895 result.postalCode = component.short_name;
22896 } else if (component.types.indexOf("street_number") >= 0) {
22897 result.streetNumber = component.short_name;
22898 } else if (component.types.indexOf("route") >= 0) {
22899 result.streetName = component.short_name;
22900 } else if (component.types.indexOf("neighborhood") >= 0) {
22901 result.city = component.short_name;
22902 } else if (component.types.indexOf("locality") >= 0) {
22903 result.city = component.short_name;
22904 } else if (component.types.indexOf("sublocality") >= 0) {
22905 result.district = component.short_name;
22906 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22907 result.stateOrProvince = component.short_name;
22908 } else if (component.types.indexOf("country") >= 0) {
22909 result.country = component.short_name;
22913 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22914 result.addressLine2 = "";
22918 setZoomLevel: function(zoom)
22920 this.gMapContext.map.setZoom(zoom);
22933 this.fireEvent('show', this);
22944 this.fireEvent('hide', this);
22949 Roo.apply(Roo.bootstrap.LocationPicker, {
22951 OverlayView : function(map, options)
22953 options = options || {};
22967 * @class Roo.bootstrap.Alert
22968 * @extends Roo.bootstrap.Component
22969 * Bootstrap Alert class
22970 * @cfg {String} title The title of alert
22971 * @cfg {String} html The content of alert
22972 * @cfg {String} weight ( success | info | warning | danger )
22973 * @cfg {String} faicon font-awesomeicon
22976 * Create a new alert
22977 * @param {Object} config The config object
22981 Roo.bootstrap.Alert = function(config){
22982 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
22986 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
22993 getAutoCreate : function()
23002 cls : 'roo-alert-icon'
23007 cls : 'roo-alert-title',
23012 cls : 'roo-alert-text',
23019 cfg.cn[0].cls += ' fa ' + this.faicon;
23023 cfg.cls += ' alert-' + this.weight;
23029 initEvents: function()
23031 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23034 setTitle : function(str)
23036 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23039 setText : function(str)
23041 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23044 setWeight : function(weight)
23047 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23050 this.weight = weight;
23052 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23055 setIcon : function(icon)
23058 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23063 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);