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, {
1037 getChildContainer : function() {
1043 if (this.panel.length) {
1044 return this.el.select('.panel-body',true).first();
1051 getAutoCreate : function(){
1054 tag : this.tag || 'div',
1058 if (this.jumbotron) {
1059 cfg.cls = 'jumbotron';
1064 // - this is applied by the parent..
1066 // cfg.cls = this.cls + '';
1069 if (this.sticky.length) {
1071 var bd = Roo.get(document.body);
1072 if (!bd.hasClass('bootstrap-sticky')) {
1073 bd.addClass('bootstrap-sticky');
1074 Roo.select('html',true).setStyle('height', '100%');
1077 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1081 if (this.well.length) {
1082 switch (this.well) {
1085 cfg.cls +=' well well-' +this.well;
1094 cfg.cls += ' hidden';
1098 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1099 cfg.cls +=' alert alert-' + this.alert;
1104 if (this.panel.length) {
1105 cfg.cls += ' panel panel-' + this.panel;
1107 if (this.header.length) {
1111 if(this.expandable){
1121 cls : 'panel-title',
1126 cls: 'panel-header-right',
1132 cls : 'panel-heading',
1145 if (this.footer.length) {
1147 cls : 'panel-footer',
1156 body.html = this.html || cfg.html;
1157 // prefix with the icons..
1159 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1162 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1167 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1168 cfg.cls = 'container';
1174 initEvents: function()
1176 if(!this.expandable){
1180 var headerEl = this.headerEl();
1186 headerEl.on('click', this.onToggleClick, this);
1190 onToggleClick : function()
1192 var headerEl = this.headerEl();
1208 if(this.fireEvent('expand', this)) {
1210 this.expanded = true;
1212 this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1214 var toggleEl = this.toggleEl();
1220 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1225 collapse : function()
1227 if(this.fireEvent('collapse', this)) {
1229 this.expanded = false;
1231 this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1233 var toggleEl = this.toggleEl();
1239 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1243 toggleEl : function()
1245 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1249 return this.el.select('.panel-heading .fa',true).first();
1252 headerEl : function()
1254 if(!this.el || !this.panel.length || !this.header.length){
1258 return this.el.select('.panel-heading',true).first()
1261 titleEl : function()
1263 if(!this.el || !this.panel.length || !this.header.length){
1267 return this.el.select('.panel-title',true).first();
1270 setTitle : function(v)
1272 var titleEl = this.titleEl();
1278 titleEl.dom.innerHTML = v;
1281 getTitle : function()
1284 var titleEl = this.titleEl();
1290 return titleEl.dom.innerHTML;
1293 setRightTitle : function(v)
1295 var t = this.el.select('.panel-header-right',true).first();
1301 t.dom.innerHTML = v;
1315 * @class Roo.bootstrap.Img
1316 * @extends Roo.bootstrap.Component
1317 * Bootstrap Img class
1318 * @cfg {Boolean} imgResponsive false | true
1319 * @cfg {String} border rounded | circle | thumbnail
1320 * @cfg {String} src image source
1321 * @cfg {String} alt image alternative text
1322 * @cfg {String} href a tag href
1323 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1326 * Create a new Input
1327 * @param {Object} config The config object
1330 Roo.bootstrap.Img = function(config){
1331 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1337 * The img click event for the img.
1338 * @param {Roo.EventObject} e
1344 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1346 imgResponsive: true,
1352 getAutoCreate : function(){
1356 cls: (this.imgResponsive) ? 'img-responsive' : '',
1360 cfg.html = this.html || cfg.html;
1362 cfg.src = this.src || cfg.src;
1364 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1365 cfg.cls += ' img-' + this.border;
1382 a.target = this.target;
1388 return (this.href) ? a : cfg;
1391 initEvents: function() {
1394 this.el.on('click', this.onClick, this);
1398 onClick : function(e)
1400 Roo.log('img onclick');
1401 this.fireEvent('click', this, e);
1415 * @class Roo.bootstrap.Link
1416 * @extends Roo.bootstrap.Component
1417 * Bootstrap Link Class
1418 * @cfg {String} alt image alternative text
1419 * @cfg {String} href a tag href
1420 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1421 * @cfg {String} html the content of the link.
1422 * @cfg {String} anchor name for the anchor link
1424 * @cfg {Boolean} preventDefault (true | false) default false
1428 * Create a new Input
1429 * @param {Object} config The config object
1432 Roo.bootstrap.Link = function(config){
1433 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1439 * The img click event for the img.
1440 * @param {Roo.EventObject} e
1446 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1450 preventDefault: false,
1454 getAutoCreate : function()
1460 // anchor's do not require html/href...
1461 if (this.anchor === false) {
1462 cfg.html = this.html || 'html-missing';
1463 cfg.href = this.href || '#';
1465 cfg.name = this.anchor;
1466 if (this.html !== false) {
1467 cfg.html = this.html;
1469 if (this.href !== false) {
1470 cfg.href = this.href;
1474 if(this.alt !== false){
1479 if(this.target !== false) {
1480 cfg.target = this.target;
1486 initEvents: function() {
1488 if(!this.href || this.preventDefault){
1489 this.el.on('click', this.onClick, this);
1493 onClick : function(e)
1495 if(this.preventDefault){
1498 //Roo.log('img onclick');
1499 this.fireEvent('click', this, e);
1512 * @class Roo.bootstrap.Header
1513 * @extends Roo.bootstrap.Component
1514 * Bootstrap Header class
1515 * @cfg {String} html content of header
1516 * @cfg {Number} level (1|2|3|4|5|6) default 1
1519 * Create a new Header
1520 * @param {Object} config The config object
1524 Roo.bootstrap.Header = function(config){
1525 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1528 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1536 getAutoCreate : function(){
1541 tag: 'h' + (1 *this.level),
1542 html: this.html || ''
1554 * Ext JS Library 1.1.1
1555 * Copyright(c) 2006-2007, Ext JS, LLC.
1557 * Originally Released Under LGPL - original licence link has changed is not relivant.
1560 * <script type="text/javascript">
1564 * @class Roo.bootstrap.MenuMgr
1565 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1568 Roo.bootstrap.MenuMgr = function(){
1569 var menus, active, groups = {}, attached = false, lastShow = new Date();
1571 // private - called when first menu is created
1574 active = new Roo.util.MixedCollection();
1575 Roo.get(document).addKeyListener(27, function(){
1576 if(active.length > 0){
1584 if(active && active.length > 0){
1585 var c = active.clone();
1595 if(active.length < 1){
1596 Roo.get(document).un("mouseup", onMouseDown);
1604 var last = active.last();
1605 lastShow = new Date();
1608 Roo.get(document).on("mouseup", onMouseDown);
1613 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1614 m.parentMenu.activeChild = m;
1615 }else if(last && last.isVisible()){
1616 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1621 function onBeforeHide(m){
1623 m.activeChild.hide();
1625 if(m.autoHideTimer){
1626 clearTimeout(m.autoHideTimer);
1627 delete m.autoHideTimer;
1632 function onBeforeShow(m){
1633 var pm = m.parentMenu;
1634 if(!pm && !m.allowOtherMenus){
1636 }else if(pm && pm.activeChild && active != m){
1637 pm.activeChild.hide();
1642 function onMouseDown(e){
1643 Roo.log("on MouseDown");
1644 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu") && !e.getTarget('.user-menu')){
1654 function onBeforeCheck(mi, state){
1656 var g = groups[mi.group];
1657 for(var i = 0, l = g.length; i < l; i++){
1659 g[i].setChecked(false);
1668 * Hides all menus that are currently visible
1670 hideAll : function(){
1675 register : function(menu){
1679 menus[menu.id] = menu;
1680 menu.on("beforehide", onBeforeHide);
1681 menu.on("hide", onHide);
1682 menu.on("beforeshow", onBeforeShow);
1683 menu.on("show", onShow);
1685 if(g && menu.events["checkchange"]){
1689 groups[g].push(menu);
1690 menu.on("checkchange", onCheck);
1695 * Returns a {@link Roo.menu.Menu} object
1696 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1697 * be used to generate and return a new Menu instance.
1699 get : function(menu){
1700 if(typeof menu == "string"){ // menu id
1702 }else if(menu.events){ // menu instance
1705 /*else if(typeof menu.length == 'number'){ // array of menu items?
1706 return new Roo.bootstrap.Menu({items:menu});
1707 }else{ // otherwise, must be a config
1708 return new Roo.bootstrap.Menu(menu);
1715 unregister : function(menu){
1716 delete menus[menu.id];
1717 menu.un("beforehide", onBeforeHide);
1718 menu.un("hide", onHide);
1719 menu.un("beforeshow", onBeforeShow);
1720 menu.un("show", onShow);
1722 if(g && menu.events["checkchange"]){
1723 groups[g].remove(menu);
1724 menu.un("checkchange", onCheck);
1729 registerCheckable : function(menuItem){
1730 var g = menuItem.group;
1735 groups[g].push(menuItem);
1736 menuItem.on("beforecheckchange", onBeforeCheck);
1741 unregisterCheckable : function(menuItem){
1742 var g = menuItem.group;
1744 groups[g].remove(menuItem);
1745 menuItem.un("beforecheckchange", onBeforeCheck);
1757 * @class Roo.bootstrap.Menu
1758 * @extends Roo.bootstrap.Component
1759 * Bootstrap Menu class - container for MenuItems
1760 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1764 * @param {Object} config The config object
1768 Roo.bootstrap.Menu = function(config){
1769 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1770 if (this.registerMenu) {
1771 Roo.bootstrap.MenuMgr.register(this);
1776 * Fires before this menu is displayed
1777 * @param {Roo.menu.Menu} this
1782 * Fires before this menu is hidden
1783 * @param {Roo.menu.Menu} this
1788 * Fires after this menu is displayed
1789 * @param {Roo.menu.Menu} this
1794 * Fires after this menu is hidden
1795 * @param {Roo.menu.Menu} this
1800 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1801 * @param {Roo.menu.Menu} this
1802 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1803 * @param {Roo.EventObject} e
1808 * Fires when the mouse is hovering over this menu
1809 * @param {Roo.menu.Menu} this
1810 * @param {Roo.EventObject} e
1811 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1816 * Fires when the mouse exits this menu
1817 * @param {Roo.menu.Menu} this
1818 * @param {Roo.EventObject} e
1819 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1824 * Fires when a menu item contained in this menu is clicked
1825 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1826 * @param {Roo.EventObject} e
1830 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1833 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1837 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1840 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1842 registerMenu : true,
1844 menuItems :false, // stores the menu items..
1850 getChildContainer : function() {
1854 getAutoCreate : function(){
1856 //if (['right'].indexOf(this.align)!==-1) {
1857 // cfg.cn[1].cls += ' pull-right'
1863 cls : 'dropdown-menu' ,
1864 style : 'z-index:1000'
1868 if (this.type === 'submenu') {
1869 cfg.cls = 'submenu active';
1871 if (this.type === 'treeview') {
1872 cfg.cls = 'treeview-menu';
1877 initEvents : function() {
1879 // Roo.log("ADD event");
1880 // Roo.log(this.triggerEl.dom);
1881 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
1883 this.triggerEl.addClass('dropdown-toggle');
1884 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1886 this.el.on("mouseover", this.onMouseOver, this);
1887 this.el.on("mouseout", this.onMouseOut, this);
1891 findTargetItem : function(e){
1892 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1896 //Roo.log(t); Roo.log(t.id);
1898 //Roo.log(this.menuitems);
1899 return this.menuitems.get(t.id);
1901 //return this.items.get(t.menuItemId);
1906 onClick : function(e){
1907 Roo.log("menu.onClick");
1908 var t = this.findTargetItem(e);
1909 if(!t || t.isContainer){
1914 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1915 if(t == this.activeItem && t.shouldDeactivate(e)){
1916 this.activeItem.deactivate();
1917 delete this.activeItem;
1921 this.setActiveItem(t, true);
1929 Roo.log('pass click event');
1933 this.fireEvent("click", this, t, e);
1937 onMouseOver : function(e){
1938 var t = this.findTargetItem(e);
1941 // if(t.canActivate && !t.disabled){
1942 // this.setActiveItem(t, true);
1946 this.fireEvent("mouseover", this, e, t);
1948 isVisible : function(){
1949 return !this.hidden;
1951 onMouseOut : function(e){
1952 var t = this.findTargetItem(e);
1955 // if(t == this.activeItem && t.shouldDeactivate(e)){
1956 // this.activeItem.deactivate();
1957 // delete this.activeItem;
1960 this.fireEvent("mouseout", this, e, t);
1965 * Displays this menu relative to another element
1966 * @param {String/HTMLElement/Roo.Element} element The element to align to
1967 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1968 * the element (defaults to this.defaultAlign)
1969 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1971 show : function(el, pos, parentMenu){
1972 this.parentMenu = parentMenu;
1976 this.fireEvent("beforeshow", this);
1977 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1980 * Displays this menu at a specific xy position
1981 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1982 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1984 showAt : function(xy, parentMenu, /* private: */_e){
1985 this.parentMenu = parentMenu;
1990 this.fireEvent("beforeshow", this);
1991 //xy = this.el.adjustForConstraints(xy);
1995 this.hideMenuItems();
1996 this.hidden = false;
1997 this.triggerEl.addClass('open');
1999 if(this.el.getWidth() + xy[0] > Roo.lib.Dom.getViewWidth()){
2000 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2005 this.fireEvent("show", this);
2011 this.doFocus.defer(50, this);
2015 doFocus : function(){
2017 this.focusEl.focus();
2022 * Hides this menu and optionally all parent menus
2023 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2025 hide : function(deep){
2027 this.hideMenuItems();
2028 if(this.el && this.isVisible()){
2029 this.fireEvent("beforehide", this);
2030 if(this.activeItem){
2031 this.activeItem.deactivate();
2032 this.activeItem = null;
2034 this.triggerEl.removeClass('open');;
2036 this.fireEvent("hide", this);
2038 if(deep === true && this.parentMenu){
2039 this.parentMenu.hide(true);
2043 onTriggerPress : function(e)
2046 Roo.log('trigger press');
2047 //Roo.log(e.getTarget());
2048 // Roo.log(this.triggerEl.dom);
2049 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
2053 if (this.isVisible()) {
2058 this.show(this.triggerEl, false, false);
2067 hideMenuItems : function()
2069 //$(backdrop).remove()
2070 Roo.select('.open',true).each(function(aa) {
2072 aa.removeClass('open');
2073 //var parent = getParent($(this))
2074 //var relatedTarget = { relatedTarget: this }
2076 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2077 //if (e.isDefaultPrevented()) return
2078 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2081 addxtypeChild : function (tree, cntr) {
2082 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2084 this.menuitems.add(comp);
2105 * @class Roo.bootstrap.MenuItem
2106 * @extends Roo.bootstrap.Component
2107 * Bootstrap MenuItem class
2108 * @cfg {String} html the menu label
2109 * @cfg {String} href the link
2110 * @cfg {Boolean} preventDefault (true | false) default true
2111 * @cfg {Boolean} isContainer (true | false) default false
2115 * Create a new MenuItem
2116 * @param {Object} config The config object
2120 Roo.bootstrap.MenuItem = function(config){
2121 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2126 * The raw click event for the entire grid.
2127 * @param {Roo.bootstrap.MenuItem} this
2128 * @param {Roo.EventObject} e
2134 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2138 preventDefault: true,
2139 isContainer : false,
2141 getAutoCreate : function(){
2143 if(this.isContainer){
2146 cls: 'dropdown-menu-item'
2152 cls: 'dropdown-menu-item',
2161 if (this.parent().type == 'treeview') {
2162 cfg.cls = 'treeview-menu';
2165 cfg.cn[0].href = this.href || cfg.cn[0].href ;
2166 cfg.cn[0].html = this.html || cfg.cn[0].html ;
2170 initEvents: function() {
2172 //this.el.select('a').on('click', this.onClick, this);
2175 onClick : function(e)
2177 Roo.log('item on click ');
2178 //if(this.preventDefault){
2179 // e.preventDefault();
2181 //this.parent().hideMenuItems();
2183 this.fireEvent('click', this, e);
2202 * @class Roo.bootstrap.MenuSeparator
2203 * @extends Roo.bootstrap.Component
2204 * Bootstrap MenuSeparator class
2207 * Create a new MenuItem
2208 * @param {Object} config The config object
2212 Roo.bootstrap.MenuSeparator = function(config){
2213 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2216 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2218 getAutoCreate : function(){
2237 * @class Roo.bootstrap.Modal
2238 * @extends Roo.bootstrap.Component
2239 * Bootstrap Modal class
2240 * @cfg {String} title Title of dialog
2241 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2242 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2243 * @cfg {Boolean} specificTitle default false
2244 * @cfg {Array} buttons Array of buttons or standard button set..
2245 * @cfg {String} buttonPosition (left|right|center) default right
2246 * @cfg {Boolean} animate default true
2247 * @cfg {Boolean} allow_close default true
2250 * Create a new Modal Dialog
2251 * @param {Object} config The config object
2254 Roo.bootstrap.Modal = function(config){
2255 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2260 * The raw btnclick event for the button
2261 * @param {Roo.EventObject} e
2265 this.buttons = this.buttons || [];
2268 this.tmpl = Roo.factory(this.tmpl);
2273 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2275 title : 'test dialog',
2285 specificTitle: false,
2287 buttonPosition: 'right',
2301 onRender : function(ct, position)
2303 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2306 var cfg = Roo.apply({}, this.getAutoCreate());
2309 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2311 //if (!cfg.name.length) {
2315 cfg.cls += ' ' + this.cls;
2318 cfg.style = this.style;
2320 this.el = Roo.get(document.body).createChild(cfg, position);
2322 //var type = this.el.dom.type;
2327 if(this.tabIndex !== undefined){
2328 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2332 this.bodyEl = this.el.select('.modal-body',true).first();
2333 this.closeEl = this.el.select('.modal-header .close', true).first();
2334 this.footerEl = this.el.select('.modal-footer',true).first();
2335 this.titleEl = this.el.select('.modal-title',true).first();
2339 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2340 this.maskEl.enableDisplayMode("block");
2342 //this.el.addClass("x-dlg-modal");
2344 if (this.buttons.length) {
2345 Roo.each(this.buttons, function(bb) {
2346 b = Roo.apply({}, bb);
2347 b.xns = b.xns || Roo.bootstrap;
2348 b.xtype = b.xtype || 'Button';
2349 if (typeof(b.listeners) == 'undefined') {
2350 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2353 var btn = Roo.factory(b);
2355 btn.onRender(this.el.select('.modal-footer div').first());
2359 // render the children.
2362 if(typeof(this.items) != 'undefined'){
2363 var items = this.items;
2366 for(var i =0;i < items.length;i++) {
2367 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2371 this.items = nitems;
2373 // where are these used - they used to be body/close/footer
2377 //this.el.addClass([this.fieldClass, this.cls]);
2380 getAutoCreate : function(){
2385 html : this.html || ''
2390 cls : 'modal-title',
2394 if(this.specificTitle){
2400 if (this.allow_close) {
2411 style : 'display: none',
2414 cls: "modal-dialog",
2417 cls : "modal-content",
2420 cls : 'modal-header',
2425 cls : 'modal-footer',
2429 cls: 'btn-' + this.buttonPosition
2446 modal.cls += ' fade';
2452 getChildContainer : function() {
2457 getButtonContainer : function() {
2458 return this.el.select('.modal-footer div',true).first();
2461 initEvents : function()
2463 if (this.allow_close) {
2464 this.closeEl.on('click', this.hide, this);
2470 if (!this.rendered) {
2474 this.el.setStyle('display', 'block');
2478 (function(){ _this.el.addClass('in'); }).defer(50);
2480 this.el.addClass('in');
2483 // not sure how we can show data in here..
2485 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2488 Roo.get(document.body).addClass("x-body-masked");
2489 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2491 this.el.setStyle('zIndex', '10001');
2493 this.fireEvent('show', this);
2500 Roo.get(document.body).removeClass("x-body-masked");
2501 this.el.removeClass('in');
2505 (function(){ _this.el.setStyle('display', 'none'); }).defer(150);
2507 this.el.setStyle('display', 'none');
2510 this.fireEvent('hide', this);
2513 addButton : function(str, cb)
2517 var b = Roo.apply({}, { html : str } );
2518 b.xns = b.xns || Roo.bootstrap;
2519 b.xtype = b.xtype || 'Button';
2520 if (typeof(b.listeners) == 'undefined') {
2521 b.listeners = { click : cb.createDelegate(this) };
2524 var btn = Roo.factory(b);
2526 btn.onRender(this.el.select('.modal-footer div').first());
2532 setDefaultButton : function(btn)
2534 //this.el.select('.modal-footer').()
2536 resizeTo: function(w,h)
2540 setContentSize : function(w, h)
2544 onButtonClick: function(btn,e)
2547 this.fireEvent('btnclick', btn.name, e);
2550 * Set the title of the Dialog
2551 * @param {String} str new Title
2553 setTitle: function(str) {
2554 this.titleEl.dom.innerHTML = str;
2557 * Set the body of the Dialog
2558 * @param {String} str new Title
2560 setBody: function(str) {
2561 this.bodyEl.dom.innerHTML = str;
2564 * Set the body of the Dialog using the template
2565 * @param {Obj} data - apply this data to the template and replace the body contents.
2567 applyBody: function(obj)
2570 Roo.log("Error - using apply Body without a template");
2573 this.tmpl.overwrite(this.bodyEl, obj);
2579 Roo.apply(Roo.bootstrap.Modal, {
2581 * Button config that displays a single OK button
2590 * Button config that displays Yes and No buttons
2606 * Button config that displays OK and Cancel buttons
2621 * Button config that displays Yes, No and Cancel buttons
2644 * messagebox - can be used as a replace
2648 * @class Roo.MessageBox
2649 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2653 Roo.Msg.alert('Status', 'Changes saved successfully.');
2655 // Prompt for user data:
2656 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2658 // process text value...
2662 // Show a dialog using config options:
2664 title:'Save Changes?',
2665 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2666 buttons: Roo.Msg.YESNOCANCEL,
2673 Roo.bootstrap.MessageBox = function(){
2674 var dlg, opt, mask, waitTimer;
2675 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2676 var buttons, activeTextEl, bwidth;
2680 var handleButton = function(button){
2682 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2686 var handleHide = function(){
2688 dlg.el.removeClass(opt.cls);
2691 // Roo.TaskMgr.stop(waitTimer);
2692 // waitTimer = null;
2697 var updateButtons = function(b){
2700 buttons["ok"].hide();
2701 buttons["cancel"].hide();
2702 buttons["yes"].hide();
2703 buttons["no"].hide();
2704 //dlg.footer.dom.style.display = 'none';
2707 dlg.footerEl.dom.style.display = '';
2708 for(var k in buttons){
2709 if(typeof buttons[k] != "function"){
2712 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2713 width += buttons[k].el.getWidth()+15;
2723 var handleEsc = function(d, k, e){
2724 if(opt && opt.closable !== false){
2734 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2735 * @return {Roo.BasicDialog} The BasicDialog element
2737 getDialog : function(){
2739 dlg = new Roo.bootstrap.Modal( {
2742 //constraintoviewport:false,
2744 //collapsible : false,
2749 //buttonAlign:"center",
2750 closeClick : function(){
2751 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2754 handleButton("cancel");
2759 dlg.on("hide", handleHide);
2761 //dlg.addKeyListener(27, handleEsc);
2763 this.buttons = buttons;
2764 var bt = this.buttonText;
2765 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2766 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2767 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2768 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2770 bodyEl = dlg.bodyEl.createChild({
2772 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2773 '<textarea class="roo-mb-textarea"></textarea>' +
2774 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2776 msgEl = bodyEl.dom.firstChild;
2777 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2778 textboxEl.enableDisplayMode();
2779 textboxEl.addKeyListener([10,13], function(){
2780 if(dlg.isVisible() && opt && opt.buttons){
2783 }else if(opt.buttons.yes){
2784 handleButton("yes");
2788 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2789 textareaEl.enableDisplayMode();
2790 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2791 progressEl.enableDisplayMode();
2792 var pf = progressEl.dom.firstChild;
2794 pp = Roo.get(pf.firstChild);
2795 pp.setHeight(pf.offsetHeight);
2803 * Updates the message box body text
2804 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2805 * the XHTML-compliant non-breaking space character '&#160;')
2806 * @return {Roo.MessageBox} This message box
2808 updateText : function(text){
2809 if(!dlg.isVisible() && !opt.width){
2810 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2812 msgEl.innerHTML = text || ' ';
2814 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2815 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2817 Math.min(opt.width || cw , this.maxWidth),
2818 Math.max(opt.minWidth || this.minWidth, bwidth)
2821 activeTextEl.setWidth(w);
2823 if(dlg.isVisible()){
2824 dlg.fixedcenter = false;
2826 // to big, make it scroll. = But as usual stupid IE does not support
2829 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2830 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2831 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2833 bodyEl.dom.style.height = '';
2834 bodyEl.dom.style.overflowY = '';
2837 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2839 bodyEl.dom.style.overflowX = '';
2842 dlg.setContentSize(w, bodyEl.getHeight());
2843 if(dlg.isVisible()){
2844 dlg.fixedcenter = true;
2850 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2851 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2852 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2853 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2854 * @return {Roo.MessageBox} This message box
2856 updateProgress : function(value, text){
2858 this.updateText(text);
2860 if (pp) { // weird bug on my firefox - for some reason this is not defined
2861 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2867 * Returns true if the message box is currently displayed
2868 * @return {Boolean} True if the message box is visible, else false
2870 isVisible : function(){
2871 return dlg && dlg.isVisible();
2875 * Hides the message box if it is displayed
2878 if(this.isVisible()){
2884 * Displays a new message box, or reinitializes an existing message box, based on the config options
2885 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2886 * The following config object properties are supported:
2888 Property Type Description
2889 ---------- --------------- ------------------------------------------------------------------------------------
2890 animEl String/Element An id or Element from which the message box should animate as it opens and
2891 closes (defaults to undefined)
2892 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2893 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2894 closable Boolean False to hide the top-right close button (defaults to true). Note that
2895 progress and wait dialogs will ignore this property and always hide the
2896 close button as they can only be closed programmatically.
2897 cls String A custom CSS class to apply to the message box element
2898 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2899 displayed (defaults to 75)
2900 fn Function A callback function to execute after closing the dialog. The arguments to the
2901 function will be btn (the name of the button that was clicked, if applicable,
2902 e.g. "ok"), and text (the value of the active text field, if applicable).
2903 Progress and wait dialogs will ignore this option since they do not respond to
2904 user actions and can only be closed programmatically, so any required function
2905 should be called by the same code after it closes the dialog.
2906 icon String A CSS class that provides a background image to be used as an icon for
2907 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2908 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2909 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2910 modal Boolean False to allow user interaction with the page while the message box is
2911 displayed (defaults to true)
2912 msg String A string that will replace the existing message box body text (defaults
2913 to the XHTML-compliant non-breaking space character ' ')
2914 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2915 progress Boolean True to display a progress bar (defaults to false)
2916 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2917 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2918 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2919 title String The title text
2920 value String The string value to set into the active textbox element if displayed
2921 wait Boolean True to display a progress bar (defaults to false)
2922 width Number The width of the dialog in pixels
2929 msg: 'Please enter your address:',
2931 buttons: Roo.MessageBox.OKCANCEL,
2934 animEl: 'addAddressBtn'
2937 * @param {Object} config Configuration options
2938 * @return {Roo.MessageBox} This message box
2940 show : function(options)
2943 // this causes nightmares if you show one dialog after another
2944 // especially on callbacks..
2946 if(this.isVisible()){
2949 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2950 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2951 Roo.log("New Dialog Message:" + options.msg )
2952 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2953 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2956 var d = this.getDialog();
2958 d.setTitle(opt.title || " ");
2959 d.closeEl.setDisplayed(opt.closable !== false);
2960 activeTextEl = textboxEl;
2961 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2966 textareaEl.setHeight(typeof opt.multiline == "number" ?
2967 opt.multiline : this.defaultTextHeight);
2968 activeTextEl = textareaEl;
2977 progressEl.setDisplayed(opt.progress === true);
2978 this.updateProgress(0);
2979 activeTextEl.dom.value = opt.value || "";
2981 dlg.setDefaultButton(activeTextEl);
2983 var bs = opt.buttons;
2987 }else if(bs && bs.yes){
2988 db = buttons["yes"];
2990 dlg.setDefaultButton(db);
2992 bwidth = updateButtons(opt.buttons);
2993 this.updateText(opt.msg);
2995 d.el.addClass(opt.cls);
2997 d.proxyDrag = opt.proxyDrag === true;
2998 d.modal = opt.modal !== false;
2999 d.mask = opt.modal !== false ? mask : false;
3001 // force it to the end of the z-index stack so it gets a cursor in FF
3002 document.body.appendChild(dlg.el.dom);
3003 d.animateTarget = null;
3004 d.show(options.animEl);
3010 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3011 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3012 * and closing the message box when the process is complete.
3013 * @param {String} title The title bar text
3014 * @param {String} msg The message box body text
3015 * @return {Roo.MessageBox} This message box
3017 progress : function(title, msg){
3024 minWidth: this.minProgressWidth,
3031 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3032 * If a callback function is passed it will be called after the user clicks the button, and the
3033 * id of the button that was clicked will be passed as the only parameter to the callback
3034 * (could also be the top-right close button).
3035 * @param {String} title The title bar text
3036 * @param {String} msg The message box body text
3037 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3038 * @param {Object} scope (optional) The scope of the callback function
3039 * @return {Roo.MessageBox} This message box
3041 alert : function(title, msg, fn, scope){
3054 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3055 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3056 * You are responsible for closing the message box when the process is complete.
3057 * @param {String} msg The message box body text
3058 * @param {String} title (optional) The title bar text
3059 * @return {Roo.MessageBox} This message box
3061 wait : function(msg, title){
3072 waitTimer = Roo.TaskMgr.start({
3074 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3082 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3083 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3084 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3085 * @param {String} title The title bar text
3086 * @param {String} msg The message box body text
3087 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3088 * @param {Object} scope (optional) The scope of the callback function
3089 * @return {Roo.MessageBox} This message box
3091 confirm : function(title, msg, fn, scope){
3095 buttons: this.YESNO,
3104 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3105 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3106 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3107 * (could also be the top-right close button) and the text that was entered will be passed as the two
3108 * parameters to the callback.
3109 * @param {String} title The title bar text
3110 * @param {String} msg The message box body text
3111 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3112 * @param {Object} scope (optional) The scope of the callback function
3113 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3114 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3115 * @return {Roo.MessageBox} This message box
3117 prompt : function(title, msg, fn, scope, multiline){
3121 buttons: this.OKCANCEL,
3126 multiline: multiline,
3133 * Button config that displays a single OK button
3138 * Button config that displays Yes and No buttons
3141 YESNO : {yes:true, no:true},
3143 * Button config that displays OK and Cancel buttons
3146 OKCANCEL : {ok:true, cancel:true},
3148 * Button config that displays Yes, No and Cancel buttons
3151 YESNOCANCEL : {yes:true, no:true, cancel:true},
3154 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3157 defaultTextHeight : 75,
3159 * The maximum width in pixels of the message box (defaults to 600)
3164 * The minimum width in pixels of the message box (defaults to 100)
3169 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3170 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3173 minProgressWidth : 250,
3175 * An object containing the default button text strings that can be overriden for localized language support.
3176 * Supported properties are: ok, cancel, yes and no.
3177 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3190 * Shorthand for {@link Roo.MessageBox}
3192 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3193 Roo.Msg = Roo.Msg || Roo.MessageBox;
3202 * @class Roo.bootstrap.Navbar
3203 * @extends Roo.bootstrap.Component
3204 * Bootstrap Navbar class
3207 * Create a new Navbar
3208 * @param {Object} config The config object
3212 Roo.bootstrap.Navbar = function(config){
3213 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3217 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3226 getAutoCreate : function(){
3229 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3233 initEvents :function ()
3235 //Roo.log(this.el.select('.navbar-toggle',true));
3236 this.el.select('.navbar-toggle',true).on('click', function() {
3237 // Roo.log('click');
3238 this.el.select('.navbar-collapse',true).toggleClass('in');
3246 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3248 var size = this.el.getSize();
3249 this.maskEl.setSize(size.width, size.height);
3250 this.maskEl.enableDisplayMode("block");
3259 getChildContainer : function()
3261 if (this.el.select('.collapse').getCount()) {
3262 return this.el.select('.collapse',true).first();
3295 * @class Roo.bootstrap.NavSimplebar
3296 * @extends Roo.bootstrap.Navbar
3297 * Bootstrap Sidebar class
3299 * @cfg {Boolean} inverse is inverted color
3301 * @cfg {String} type (nav | pills | tabs)
3302 * @cfg {Boolean} arrangement stacked | justified
3303 * @cfg {String} align (left | right) alignment
3305 * @cfg {Boolean} main (true|false) main nav bar? default false
3306 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3308 * @cfg {String} tag (header|footer|nav|div) default is nav
3314 * Create a new Sidebar
3315 * @param {Object} config The config object
3319 Roo.bootstrap.NavSimplebar = function(config){
3320 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3323 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
3339 getAutoCreate : function(){
3343 tag : this.tag || 'div',
3356 this.type = this.type || 'nav';
3357 if (['tabs','pills'].indexOf(this.type)!==-1) {
3358 cfg.cn[0].cls += ' nav-' + this.type
3362 if (this.type!=='nav') {
3363 Roo.log('nav type must be nav/tabs/pills')
3365 cfg.cn[0].cls += ' navbar-nav'
3371 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
3372 cfg.cn[0].cls += ' nav-' + this.arrangement;
3376 if (this.align === 'right') {
3377 cfg.cn[0].cls += ' navbar-right';
3381 cfg.cls += ' navbar-inverse';
3408 * @class Roo.bootstrap.NavHeaderbar
3409 * @extends Roo.bootstrap.NavSimplebar
3410 * Bootstrap Sidebar class
3412 * @cfg {String} brand what is brand
3413 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3414 * @cfg {String} brand_href href of the brand
3415 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
3416 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
3417 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
3418 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
3421 * Create a new Sidebar
3422 * @param {Object} config The config object
3426 Roo.bootstrap.NavHeaderbar = function(config){
3427 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3431 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3438 desktopCenter : false,
3441 getAutoCreate : function(){
3444 tag: this.nav || 'nav',
3451 if (this.desktopCenter) {
3452 cn.push({cls : 'container', cn : []});
3459 cls: 'navbar-header',
3464 cls: 'navbar-toggle',
3465 'data-toggle': 'collapse',
3470 html: 'Toggle navigation'
3492 cls: 'collapse navbar-collapse',
3496 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3498 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3499 cfg.cls += ' navbar-' + this.position;
3501 // tag can override this..
3503 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3506 if (this.brand !== '') {
3509 href: this.brand_href ? this.brand_href : '#',
3510 cls: 'navbar-brand',
3518 cfg.cls += ' main-nav';
3526 getHeaderChildContainer : function()
3528 if (this.el.select('.navbar-header').getCount()) {
3529 return this.el.select('.navbar-header',true).first();
3532 return this.getChildContainer();
3536 initEvents : function()
3538 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
3540 if (this.autohide) {
3545 Roo.get(document).on('scroll',function(e) {
3546 var ns = Roo.get(document).getScroll().top;
3547 var os = prevScroll;
3551 ft.removeClass('slideDown');
3552 ft.addClass('slideUp');
3555 ft.removeClass('slideUp');
3556 ft.addClass('slideDown');
3577 * @class Roo.bootstrap.NavSidebar
3578 * @extends Roo.bootstrap.Navbar
3579 * Bootstrap Sidebar class
3582 * Create a new Sidebar
3583 * @param {Object} config The config object
3587 Roo.bootstrap.NavSidebar = function(config){
3588 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3591 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3593 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3595 getAutoCreate : function(){
3600 cls: 'sidebar sidebar-nav'
3622 * @class Roo.bootstrap.NavGroup
3623 * @extends Roo.bootstrap.Component
3624 * Bootstrap NavGroup class
3625 * @cfg {String} align left | right
3626 * @cfg {Boolean} inverse false | true
3627 * @cfg {String} type (nav|pills|tab) default nav
3628 * @cfg {String} navId - reference Id for navbar.
3632 * Create a new nav group
3633 * @param {Object} config The config object
3636 Roo.bootstrap.NavGroup = function(config){
3637 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3640 Roo.bootstrap.NavGroup.register(this);
3644 * Fires when the active item changes
3645 * @param {Roo.bootstrap.NavGroup} this
3646 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
3647 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
3654 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3665 getAutoCreate : function()
3667 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3674 if (['tabs','pills'].indexOf(this.type)!==-1) {
3675 cfg.cls += ' nav-' + this.type
3677 if (this.type!=='nav') {
3678 Roo.log('nav type must be nav/tabs/pills')
3680 cfg.cls += ' navbar-nav'
3683 if (this.parent().sidebar) {
3686 cls: 'dashboard-menu sidebar-menu'
3692 if (this.form === true) {
3698 if (this.align === 'right') {
3699 cfg.cls += ' navbar-right';
3701 cfg.cls += ' navbar-left';
3705 if (this.align === 'right') {
3706 cfg.cls += ' navbar-right';
3710 cfg.cls += ' navbar-inverse';
3718 * sets the active Navigation item
3719 * @param {Roo.bootstrap.NavItem} the new current navitem
3721 setActiveItem : function(item)
3724 Roo.each(this.navItems, function(v){
3729 v.setActive(false, true);
3736 item.setActive(true, true);
3737 this.fireEvent('changed', this, item, prev);
3742 * gets the active Navigation item
3743 * @return {Roo.bootstrap.NavItem} the current navitem
3745 getActive : function()
3749 Roo.each(this.navItems, function(v){
3760 indexOfNav : function()
3764 Roo.each(this.navItems, function(v,i){
3775 * adds a Navigation item
3776 * @param {Roo.bootstrap.NavItem} the navitem to add
3778 addItem : function(cfg)
3780 var cn = new Roo.bootstrap.NavItem(cfg);
3782 cn.parentId = this.id;
3783 cn.onRender(this.el, null);
3787 * register a Navigation item
3788 * @param {Roo.bootstrap.NavItem} the navitem to add
3790 register : function(item)
3792 this.navItems.push( item);
3793 item.navId = this.navId;
3798 * clear all the Navigation item
3801 clearAll : function()
3804 this.el.dom.innerHTML = '';
3807 getNavItem: function(tabId)
3810 Roo.each(this.navItems, function(e) {
3811 if (e.tabId == tabId) {
3821 setActiveNext : function()
3823 var i = this.indexOfNav(this.getActive());
3824 if (i > this.navItems.length) {
3827 this.setActiveItem(this.navItems[i+1]);
3829 setActivePrev : function()
3831 var i = this.indexOfNav(this.getActive());
3835 this.setActiveItem(this.navItems[i-1]);
3837 clearWasActive : function(except) {
3838 Roo.each(this.navItems, function(e) {
3839 if (e.tabId != except.tabId && e.was_active) {
3840 e.was_active = false;
3847 getWasActive : function ()
3850 Roo.each(this.navItems, function(e) {
3865 Roo.apply(Roo.bootstrap.NavGroup, {
3869 * register a Navigation Group
3870 * @param {Roo.bootstrap.NavGroup} the navgroup to add
3872 register : function(navgrp)
3874 this.groups[navgrp.navId] = navgrp;
3878 * fetch a Navigation Group based on the navigation ID
3879 * @param {string} the navgroup to add
3880 * @returns {Roo.bootstrap.NavGroup} the navgroup
3882 get: function(navId) {
3883 if (typeof(this.groups[navId]) == 'undefined') {
3885 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
3887 return this.groups[navId] ;
3902 * @class Roo.bootstrap.NavItem
3903 * @extends Roo.bootstrap.Component
3904 * Bootstrap Navbar.NavItem class
3905 * @cfg {String} href link to
3906 * @cfg {String} html content of button
3907 * @cfg {String} badge text inside badge
3908 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3909 * @cfg {String} glyphicon name of glyphicon
3910 * @cfg {String} icon name of font awesome icon
3911 * @cfg {Boolean} active Is item active
3912 * @cfg {Boolean} disabled Is item disabled
3914 * @cfg {Boolean} preventDefault (true | false) default false
3915 * @cfg {String} tabId the tab that this item activates.
3916 * @cfg {String} tagtype (a|span) render as a href or span?
3917 * @cfg {Boolean} animateRef (true|false) link to element default false
3920 * Create a new Navbar Item
3921 * @param {Object} config The config object
3923 Roo.bootstrap.NavItem = function(config){
3924 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3929 * The raw click event for the entire grid.
3930 * @param {Roo.EventObject} e
3935 * Fires when the active item active state changes
3936 * @param {Roo.bootstrap.NavItem} this
3937 * @param {boolean} state the new state
3943 * Fires when scroll to element
3944 * @param {Roo.bootstrap.NavItem} this
3945 * @param {Object} options
3946 * @param {Roo.EventObject} e
3954 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3962 preventDefault : false,
3969 getAutoCreate : function(){
3977 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3979 if (this.disabled) {
3980 cfg.cls += ' disabled';
3983 if (this.href || this.html || this.glyphicon || this.icon) {
3987 href : this.href || "#",
3988 html: this.html || ''
3993 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3996 if(this.glyphicon) {
3997 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4002 cfg.cn[0].html += " <span class='caret'></span>";
4006 if (this.badge !== '') {
4008 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
4016 initEvents: function()
4018 if (typeof (this.menu) != 'undefined') {
4019 this.menu.parentType = this.xtype;
4020 this.menu.triggerEl = this.el;
4021 this.menu = this.addxtype(Roo.apply({}, this.menu));
4024 this.el.select('a',true).on('click', this.onClick, this);
4026 if(this.tagtype == 'span'){
4027 this.el.select('span',true).on('click', this.onClick, this);
4030 // at this point parent should be available..
4031 this.parent().register(this);
4034 onClick : function(e)
4037 this.preventDefault ||
4044 if (this.disabled) {
4048 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4049 if (tg && tg.transition) {
4050 Roo.log("waiting for the transitionend");
4056 //Roo.log("fire event clicked");
4057 if(this.fireEvent('click', this, e) === false){
4061 if(this.tagtype == 'span'){
4065 //Roo.log(this.href);
4066 var ael = this.el.select('a',true).first();
4069 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4070 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4071 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4072 return; // ignore... - it's a 'hash' to another page.
4076 this.scrollToElement(e);
4080 var p = this.parent();
4082 if (['tabs','pills'].indexOf(p.type)!==-1) {
4083 if (typeof(p.setActiveItem) !== 'undefined') {
4084 p.setActiveItem(this);
4088 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4089 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4090 // remove the collapsed menu expand...
4091 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4095 isActive: function () {
4098 setActive : function(state, fire, is_was_active)
4100 if (this.active && !state & this.navId) {
4101 this.was_active = true;
4102 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4104 nv.clearWasActive(this);
4108 this.active = state;
4111 this.el.removeClass('active');
4112 } else if (!this.el.hasClass('active')) {
4113 this.el.addClass('active');
4116 this.fireEvent('changed', this, state);
4119 // show a panel if it's registered and related..
4121 if (!this.navId || !this.tabId || !state || is_was_active) {
4125 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4129 var pan = tg.getPanelByName(this.tabId);
4133 // if we can not flip to new panel - go back to old nav highlight..
4134 if (false == tg.showPanel(pan)) {
4135 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4137 var onav = nv.getWasActive();
4139 onav.setActive(true, false, true);
4148 // this should not be here...
4149 setDisabled : function(state)
4151 this.disabled = state;
4153 this.el.removeClass('disabled');
4154 } else if (!this.el.hasClass('disabled')) {
4155 this.el.addClass('disabled');
4161 * Fetch the element to display the tooltip on.
4162 * @return {Roo.Element} defaults to this.el
4164 tooltipEl : function()
4166 return this.el.select('' + this.tagtype + '', true).first();
4169 scrollToElement : function(e)
4171 var c = document.body;
4174 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4176 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4177 c = document.documentElement;
4180 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4186 var o = target.calcOffsetsTo(c);
4193 this.fireEvent('scrollto', this, options, e);
4195 Roo.get(c).scrollTo('top', options.value, true);
4208 * <span> icon </span>
4209 * <span> text </span>
4210 * <span>badge </span>
4214 * @class Roo.bootstrap.NavSidebarItem
4215 * @extends Roo.bootstrap.NavItem
4216 * Bootstrap Navbar.NavSidebarItem class
4218 * Create a new Navbar Button
4219 * @param {Object} config The config object
4221 Roo.bootstrap.NavSidebarItem = function(config){
4222 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4227 * The raw click event for the entire grid.
4228 * @param {Roo.EventObject} e
4233 * Fires when the active item active state changes
4234 * @param {Roo.bootstrap.NavSidebarItem} this
4235 * @param {boolean} state the new state
4243 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4246 getAutoCreate : function(){
4251 href : this.href || '#',
4263 html : this.html || ''
4268 cfg.cls += ' active';
4272 if (this.glyphicon || this.icon) {
4273 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
4274 a.cn.push({ tag : 'i', cls : c }) ;
4279 if (this.badge !== '') {
4280 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
4284 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
4285 a.cls += 'dropdown-toggle treeview' ;
4309 * @class Roo.bootstrap.Row
4310 * @extends Roo.bootstrap.Component
4311 * Bootstrap Row class (contains columns...)
4315 * @param {Object} config The config object
4318 Roo.bootstrap.Row = function(config){
4319 Roo.bootstrap.Row.superclass.constructor.call(this, config);
4322 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
4324 getAutoCreate : function(){
4343 * @class Roo.bootstrap.Element
4344 * @extends Roo.bootstrap.Component
4345 * Bootstrap Element class
4346 * @cfg {String} html contents of the element
4347 * @cfg {String} tag tag of the element
4348 * @cfg {String} cls class of the element
4349 * @cfg {Boolean} preventDefault (true|false) default false
4350 * @cfg {Boolean} clickable (true|false) default false
4353 * Create a new Element
4354 * @param {Object} config The config object
4357 Roo.bootstrap.Element = function(config){
4358 Roo.bootstrap.Element.superclass.constructor.call(this, config);
4364 * When a element is chick
4365 * @param {Roo.bootstrap.Element} this
4366 * @param {Roo.EventObject} e
4372 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
4377 preventDefault: false,
4380 getAutoCreate : function(){
4391 initEvents: function()
4393 Roo.bootstrap.Element.superclass.initEvents.call(this);
4396 this.el.on('click', this.onClick, this);
4401 onClick : function(e)
4403 if(this.preventDefault){
4407 this.fireEvent('click', this, e);
4410 getValue : function()
4412 return this.el.dom.innerHTML;
4415 setValue : function(value)
4417 this.el.dom.innerHTML = value;
4432 * @class Roo.bootstrap.Pagination
4433 * @extends Roo.bootstrap.Component
4434 * Bootstrap Pagination class
4435 * @cfg {String} size xs | sm | md | lg
4436 * @cfg {Boolean} inverse false | true
4439 * Create a new Pagination
4440 * @param {Object} config The config object
4443 Roo.bootstrap.Pagination = function(config){
4444 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
4447 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
4453 getAutoCreate : function(){
4459 cfg.cls += ' inverse';
4465 cfg.cls += " " + this.cls;
4483 * @class Roo.bootstrap.PaginationItem
4484 * @extends Roo.bootstrap.Component
4485 * Bootstrap PaginationItem class
4486 * @cfg {String} html text
4487 * @cfg {String} href the link
4488 * @cfg {Boolean} preventDefault (true | false) default true
4489 * @cfg {Boolean} active (true | false) default false
4490 * @cfg {Boolean} disabled default false
4494 * Create a new PaginationItem
4495 * @param {Object} config The config object
4499 Roo.bootstrap.PaginationItem = function(config){
4500 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
4505 * The raw click event for the entire grid.
4506 * @param {Roo.EventObject} e
4512 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
4516 preventDefault: true,
4521 getAutoCreate : function(){
4527 href : this.href ? this.href : '#',
4528 html : this.html ? this.html : ''
4538 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
4542 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
4548 initEvents: function() {
4550 this.el.on('click', this.onClick, this);
4553 onClick : function(e)
4555 Roo.log('PaginationItem on click ');
4556 if(this.preventDefault){
4564 this.fireEvent('click', this, e);
4580 * @class Roo.bootstrap.Slider
4581 * @extends Roo.bootstrap.Component
4582 * Bootstrap Slider class
4585 * Create a new Slider
4586 * @param {Object} config The config object
4589 Roo.bootstrap.Slider = function(config){
4590 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
4593 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
4595 getAutoCreate : function(){
4599 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
4603 cls: 'ui-slider-handle ui-state-default ui-corner-all'
4615 * Ext JS Library 1.1.1
4616 * Copyright(c) 2006-2007, Ext JS, LLC.
4618 * Originally Released Under LGPL - original licence link has changed is not relivant.
4621 * <script type="text/javascript">
4626 * @class Roo.grid.ColumnModel
4627 * @extends Roo.util.Observable
4628 * This is the default implementation of a ColumnModel used by the Grid. It defines
4629 * the columns in the grid.
4632 var colModel = new Roo.grid.ColumnModel([
4633 {header: "Ticker", width: 60, sortable: true, locked: true},
4634 {header: "Company Name", width: 150, sortable: true},
4635 {header: "Market Cap.", width: 100, sortable: true},
4636 {header: "$ Sales", width: 100, sortable: true, renderer: money},
4637 {header: "Employees", width: 100, sortable: true, resizable: false}
4642 * The config options listed for this class are options which may appear in each
4643 * individual column definition.
4644 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
4646 * @param {Object} config An Array of column config objects. See this class's
4647 * config objects for details.
4649 Roo.grid.ColumnModel = function(config){
4651 * The config passed into the constructor
4653 this.config = config;
4656 // if no id, create one
4657 // if the column does not have a dataIndex mapping,
4658 // map it to the order it is in the config
4659 for(var i = 0, len = config.length; i < len; i++){
4661 if(typeof c.dataIndex == "undefined"){
4664 if(typeof c.renderer == "string"){
4665 c.renderer = Roo.util.Format[c.renderer];
4667 if(typeof c.id == "undefined"){
4670 if(c.editor && c.editor.xtype){
4671 c.editor = Roo.factory(c.editor, Roo.grid);
4673 if(c.editor && c.editor.isFormField){
4674 c.editor = new Roo.grid.GridEditor(c.editor);
4676 this.lookup[c.id] = c;
4680 * The width of columns which have no width specified (defaults to 100)
4683 this.defaultWidth = 100;
4686 * Default sortable of columns which have no sortable specified (defaults to false)
4689 this.defaultSortable = false;
4693 * @event widthchange
4694 * Fires when the width of a column changes.
4695 * @param {ColumnModel} this
4696 * @param {Number} columnIndex The column index
4697 * @param {Number} newWidth The new width
4699 "widthchange": true,
4701 * @event headerchange
4702 * Fires when the text of a header changes.
4703 * @param {ColumnModel} this
4704 * @param {Number} columnIndex The column index
4705 * @param {Number} newText The new header text
4707 "headerchange": true,
4709 * @event hiddenchange
4710 * Fires when a column is hidden or "unhidden".
4711 * @param {ColumnModel} this
4712 * @param {Number} columnIndex The column index
4713 * @param {Boolean} hidden true if hidden, false otherwise
4715 "hiddenchange": true,
4717 * @event columnmoved
4718 * Fires when a column is moved.
4719 * @param {ColumnModel} this
4720 * @param {Number} oldIndex
4721 * @param {Number} newIndex
4723 "columnmoved" : true,
4725 * @event columlockchange
4726 * Fires when a column's locked state is changed
4727 * @param {ColumnModel} this
4728 * @param {Number} colIndex
4729 * @param {Boolean} locked true if locked
4731 "columnlockchange" : true
4733 Roo.grid.ColumnModel.superclass.constructor.call(this);
4735 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
4737 * @cfg {String} header The header text to display in the Grid view.
4740 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
4741 * {@link Roo.data.Record} definition from which to draw the column's value. If not
4742 * specified, the column's index is used as an index into the Record's data Array.
4745 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4746 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4749 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4750 * Defaults to the value of the {@link #defaultSortable} property.
4751 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4754 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4757 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4760 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4763 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4766 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4767 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4768 * default renderer uses the raw data value. If an object is returned (bootstrap only)
4769 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
4772 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4775 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4778 * @cfg {String} cursor (Optional)
4781 * @cfg {String} tooltip (Optional)
4784 * Returns the id of the column at the specified index.
4785 * @param {Number} index The column index
4786 * @return {String} the id
4788 getColumnId : function(index){
4789 return this.config[index].id;
4793 * Returns the column for a specified id.
4794 * @param {String} id The column id
4795 * @return {Object} the column
4797 getColumnById : function(id){
4798 return this.lookup[id];
4803 * Returns the column for a specified dataIndex.
4804 * @param {String} dataIndex The column dataIndex
4805 * @return {Object|Boolean} the column or false if not found
4807 getColumnByDataIndex: function(dataIndex){
4808 var index = this.findColumnIndex(dataIndex);
4809 return index > -1 ? this.config[index] : false;
4813 * Returns the index for a specified column id.
4814 * @param {String} id The column id
4815 * @return {Number} the index, or -1 if not found
4817 getIndexById : function(id){
4818 for(var i = 0, len = this.config.length; i < len; i++){
4819 if(this.config[i].id == id){
4827 * Returns the index for a specified column dataIndex.
4828 * @param {String} dataIndex The column dataIndex
4829 * @return {Number} the index, or -1 if not found
4832 findColumnIndex : function(dataIndex){
4833 for(var i = 0, len = this.config.length; i < len; i++){
4834 if(this.config[i].dataIndex == dataIndex){
4842 moveColumn : function(oldIndex, newIndex){
4843 var c = this.config[oldIndex];
4844 this.config.splice(oldIndex, 1);
4845 this.config.splice(newIndex, 0, c);
4846 this.dataMap = null;
4847 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4850 isLocked : function(colIndex){
4851 return this.config[colIndex].locked === true;
4854 setLocked : function(colIndex, value, suppressEvent){
4855 if(this.isLocked(colIndex) == value){
4858 this.config[colIndex].locked = value;
4860 this.fireEvent("columnlockchange", this, colIndex, value);
4864 getTotalLockedWidth : function(){
4866 for(var i = 0; i < this.config.length; i++){
4867 if(this.isLocked(i) && !this.isHidden(i)){
4868 this.totalWidth += this.getColumnWidth(i);
4874 getLockedCount : function(){
4875 for(var i = 0, len = this.config.length; i < len; i++){
4876 if(!this.isLocked(i)){
4883 * Returns the number of columns.
4886 getColumnCount : function(visibleOnly){
4887 if(visibleOnly === true){
4889 for(var i = 0, len = this.config.length; i < len; i++){
4890 if(!this.isHidden(i)){
4896 return this.config.length;
4900 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4901 * @param {Function} fn
4902 * @param {Object} scope (optional)
4903 * @return {Array} result
4905 getColumnsBy : function(fn, scope){
4907 for(var i = 0, len = this.config.length; i < len; i++){
4908 var c = this.config[i];
4909 if(fn.call(scope||this, c, i) === true){
4917 * Returns true if the specified column is sortable.
4918 * @param {Number} col The column index
4921 isSortable : function(col){
4922 if(typeof this.config[col].sortable == "undefined"){
4923 return this.defaultSortable;
4925 return this.config[col].sortable;
4929 * Returns the rendering (formatting) function defined for the column.
4930 * @param {Number} col The column index.
4931 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4933 getRenderer : function(col){
4934 if(!this.config[col].renderer){
4935 return Roo.grid.ColumnModel.defaultRenderer;
4937 return this.config[col].renderer;
4941 * Sets the rendering (formatting) function for a column.
4942 * @param {Number} col The column index
4943 * @param {Function} fn The function to use to process the cell's raw data
4944 * to return HTML markup for the grid view. The render function is called with
4945 * the following parameters:<ul>
4946 * <li>Data value.</li>
4947 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4948 * <li>css A CSS style string to apply to the table cell.</li>
4949 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4950 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4951 * <li>Row index</li>
4952 * <li>Column index</li>
4953 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4955 setRenderer : function(col, fn){
4956 this.config[col].renderer = fn;
4960 * Returns the width for the specified column.
4961 * @param {Number} col The column index
4964 getColumnWidth : function(col){
4965 return this.config[col].width * 1 || this.defaultWidth;
4969 * Sets the width for a column.
4970 * @param {Number} col The column index
4971 * @param {Number} width The new width
4973 setColumnWidth : function(col, width, suppressEvent){
4974 this.config[col].width = width;
4975 this.totalWidth = null;
4977 this.fireEvent("widthchange", this, col, width);
4982 * Returns the total width of all columns.
4983 * @param {Boolean} includeHidden True to include hidden column widths
4986 getTotalWidth : function(includeHidden){
4987 if(!this.totalWidth){
4988 this.totalWidth = 0;
4989 for(var i = 0, len = this.config.length; i < len; i++){
4990 if(includeHidden || !this.isHidden(i)){
4991 this.totalWidth += this.getColumnWidth(i);
4995 return this.totalWidth;
4999 * Returns the header for the specified column.
5000 * @param {Number} col The column index
5003 getColumnHeader : function(col){
5004 return this.config[col].header;
5008 * Sets the header for a column.
5009 * @param {Number} col The column index
5010 * @param {String} header The new header
5012 setColumnHeader : function(col, header){
5013 this.config[col].header = header;
5014 this.fireEvent("headerchange", this, col, header);
5018 * Returns the tooltip for the specified column.
5019 * @param {Number} col The column index
5022 getColumnTooltip : function(col){
5023 return this.config[col].tooltip;
5026 * Sets the tooltip for a column.
5027 * @param {Number} col The column index
5028 * @param {String} tooltip The new tooltip
5030 setColumnTooltip : function(col, tooltip){
5031 this.config[col].tooltip = tooltip;
5035 * Returns the dataIndex for the specified column.
5036 * @param {Number} col The column index
5039 getDataIndex : function(col){
5040 return this.config[col].dataIndex;
5044 * Sets the dataIndex for a column.
5045 * @param {Number} col The column index
5046 * @param {Number} dataIndex The new dataIndex
5048 setDataIndex : function(col, dataIndex){
5049 this.config[col].dataIndex = dataIndex;
5055 * Returns true if the cell is editable.
5056 * @param {Number} colIndex The column index
5057 * @param {Number} rowIndex The row index
5060 isCellEditable : function(colIndex, rowIndex){
5061 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5065 * Returns the editor defined for the cell/column.
5066 * return false or null to disable editing.
5067 * @param {Number} colIndex The column index
5068 * @param {Number} rowIndex The row index
5071 getCellEditor : function(colIndex, rowIndex){
5072 return this.config[colIndex].editor;
5076 * Sets if a column is editable.
5077 * @param {Number} col The column index
5078 * @param {Boolean} editable True if the column is editable
5080 setEditable : function(col, editable){
5081 this.config[col].editable = editable;
5086 * Returns true if the column is hidden.
5087 * @param {Number} colIndex The column index
5090 isHidden : function(colIndex){
5091 return this.config[colIndex].hidden;
5096 * Returns true if the column width cannot be changed
5098 isFixed : function(colIndex){
5099 return this.config[colIndex].fixed;
5103 * Returns true if the column can be resized
5106 isResizable : function(colIndex){
5107 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5110 * Sets if a column is hidden.
5111 * @param {Number} colIndex The column index
5112 * @param {Boolean} hidden True if the column is hidden
5114 setHidden : function(colIndex, hidden){
5115 this.config[colIndex].hidden = hidden;
5116 this.totalWidth = null;
5117 this.fireEvent("hiddenchange", this, colIndex, hidden);
5121 * Sets the editor for a column.
5122 * @param {Number} col The column index
5123 * @param {Object} editor The editor object
5125 setEditor : function(col, editor){
5126 this.config[col].editor = editor;
5130 Roo.grid.ColumnModel.defaultRenderer = function(value){
5131 if(typeof value == "string" && value.length < 1){
5137 // Alias for backwards compatibility
5138 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5141 * Ext JS Library 1.1.1
5142 * Copyright(c) 2006-2007, Ext JS, LLC.
5144 * Originally Released Under LGPL - original licence link has changed is not relivant.
5147 * <script type="text/javascript">
5151 * @class Roo.LoadMask
5152 * A simple utility class for generically masking elements while loading data. If the element being masked has
5153 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
5154 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
5155 * element's UpdateManager load indicator and will be destroyed after the initial load.
5157 * Create a new LoadMask
5158 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
5159 * @param {Object} config The config object
5161 Roo.LoadMask = function(el, config){
5162 this.el = Roo.get(el);
5163 Roo.apply(this, config);
5165 this.store.on('beforeload', this.onBeforeLoad, this);
5166 this.store.on('load', this.onLoad, this);
5167 this.store.on('loadexception', this.onLoadException, this);
5168 this.removeMask = false;
5170 var um = this.el.getUpdateManager();
5171 um.showLoadIndicator = false; // disable the default indicator
5172 um.on('beforeupdate', this.onBeforeLoad, this);
5173 um.on('update', this.onLoad, this);
5174 um.on('failure', this.onLoad, this);
5175 this.removeMask = true;
5179 Roo.LoadMask.prototype = {
5181 * @cfg {Boolean} removeMask
5182 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
5183 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
5187 * The text to display in a centered loading message box (defaults to 'Loading...')
5191 * @cfg {String} msgCls
5192 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
5194 msgCls : 'x-mask-loading',
5197 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
5203 * Disables the mask to prevent it from being displayed
5205 disable : function(){
5206 this.disabled = true;
5210 * Enables the mask so that it can be displayed
5212 enable : function(){
5213 this.disabled = false;
5216 onLoadException : function()
5220 if (typeof(arguments[3]) != 'undefined') {
5221 Roo.MessageBox.alert("Error loading",arguments[3]);
5225 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
5226 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
5235 this.el.unmask(this.removeMask);
5240 this.el.unmask(this.removeMask);
5244 onBeforeLoad : function(){
5246 this.el.mask(this.msg, this.msgCls);
5251 destroy : function(){
5253 this.store.un('beforeload', this.onBeforeLoad, this);
5254 this.store.un('load', this.onLoad, this);
5255 this.store.un('loadexception', this.onLoadException, this);
5257 var um = this.el.getUpdateManager();
5258 um.un('beforeupdate', this.onBeforeLoad, this);
5259 um.un('update', this.onLoad, this);
5260 um.un('failure', this.onLoad, this);
5271 * @class Roo.bootstrap.Table
5272 * @extends Roo.bootstrap.Component
5273 * Bootstrap Table class
5274 * @cfg {String} cls table class
5275 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
5276 * @cfg {String} bgcolor Specifies the background color for a table
5277 * @cfg {Number} border Specifies whether the table cells should have borders or not
5278 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
5279 * @cfg {Number} cellspacing Specifies the space between cells
5280 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
5281 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
5282 * @cfg {String} sortable Specifies that the table should be sortable
5283 * @cfg {String} summary Specifies a summary of the content of a table
5284 * @cfg {Number} width Specifies the width of a table
5285 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
5287 * @cfg {boolean} striped Should the rows be alternative striped
5288 * @cfg {boolean} bordered Add borders to the table
5289 * @cfg {boolean} hover Add hover highlighting
5290 * @cfg {boolean} condensed Format condensed
5291 * @cfg {boolean} responsive Format condensed
5292 * @cfg {Boolean} loadMask (true|false) default false
5293 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
5294 * @cfg {Boolean} thead (true|false) generate thead, default true
5295 * @cfg {Boolean} RowSelection (true|false) default false
5296 * @cfg {Boolean} CellSelection (true|false) default false
5297 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
5301 * Create a new Table
5302 * @param {Object} config The config object
5305 Roo.bootstrap.Table = function(config){
5306 Roo.bootstrap.Table.superclass.constructor.call(this, config);
5309 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
5310 this.sm = this.selModel;
5311 this.sm.xmodule = this.xmodule || false;
5313 if (this.cm && typeof(this.cm.config) == 'undefined') {
5314 this.colModel = new Roo.grid.ColumnModel(this.cm);
5315 this.cm = this.colModel;
5316 this.cm.xmodule = this.xmodule || false;
5319 this.store= Roo.factory(this.store, Roo.data);
5320 this.ds = this.store;
5321 this.ds.xmodule = this.xmodule || false;
5324 if (this.footer && this.store) {
5325 this.footer.dataSource = this.ds;
5326 this.footer = Roo.factory(this.footer);
5333 * Fires when a cell is clicked
5334 * @param {Roo.bootstrap.Table} this
5335 * @param {Roo.Element} el
5336 * @param {Number} rowIndex
5337 * @param {Number} columnIndex
5338 * @param {Roo.EventObject} e
5342 * @event celldblclick
5343 * Fires when a cell is double clicked
5344 * @param {Roo.bootstrap.Table} this
5345 * @param {Roo.Element} el
5346 * @param {Number} rowIndex
5347 * @param {Number} columnIndex
5348 * @param {Roo.EventObject} e
5350 "celldblclick" : true,
5353 * Fires when a row is clicked
5354 * @param {Roo.bootstrap.Table} this
5355 * @param {Roo.Element} el
5356 * @param {Number} rowIndex
5357 * @param {Roo.EventObject} e
5361 * @event rowdblclick
5362 * Fires when a row is double clicked
5363 * @param {Roo.bootstrap.Table} this
5364 * @param {Roo.Element} el
5365 * @param {Number} rowIndex
5366 * @param {Roo.EventObject} e
5368 "rowdblclick" : true,
5371 * Fires when a mouseover occur
5372 * @param {Roo.bootstrap.Table} this
5373 * @param {Roo.Element} el
5374 * @param {Number} rowIndex
5375 * @param {Number} columnIndex
5376 * @param {Roo.EventObject} e
5381 * Fires when a mouseout occur
5382 * @param {Roo.bootstrap.Table} this
5383 * @param {Roo.Element} el
5384 * @param {Number} rowIndex
5385 * @param {Number} columnIndex
5386 * @param {Roo.EventObject} e
5391 * Fires when a row is rendered, so you can change add a style to it.
5392 * @param {Roo.bootstrap.Table} this
5393 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
5397 * @event rowsrendered
5398 * Fires when all the rows have been rendered
5399 * @param {Roo.bootstrap.Table} this
5401 'rowsrendered' : true
5406 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
5430 RowSelection : false,
5431 CellSelection : false,
5434 // Roo.Element - the tbody
5437 getAutoCreate : function(){
5438 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
5447 cfg.cls += ' table-striped';
5451 cfg.cls += ' table-hover';
5453 if (this.bordered) {
5454 cfg.cls += ' table-bordered';
5456 if (this.condensed) {
5457 cfg.cls += ' table-condensed';
5459 if (this.responsive) {
5460 cfg.cls += ' table-responsive';
5464 cfg.cls+= ' ' +this.cls;
5467 // this lot should be simplifed...
5470 cfg.align=this.align;
5473 cfg.bgcolor=this.bgcolor;
5476 cfg.border=this.border;
5478 if (this.cellpadding) {
5479 cfg.cellpadding=this.cellpadding;
5481 if (this.cellspacing) {
5482 cfg.cellspacing=this.cellspacing;
5485 cfg.frame=this.frame;
5488 cfg.rules=this.rules;
5490 if (this.sortable) {
5491 cfg.sortable=this.sortable;
5494 cfg.summary=this.summary;
5497 cfg.width=this.width;
5500 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
5503 if(this.store || this.cm){
5505 cfg.cn.push(this.renderHeader());
5508 cfg.cn.push(this.renderBody());
5511 cfg.cn.push(this.renderFooter());
5514 cfg.cls+= ' TableGrid';
5517 return { cn : [ cfg ] };
5520 initEvents : function()
5522 if(!this.store || !this.cm){
5526 //Roo.log('initEvents with ds!!!!');
5528 this.mainBody = this.el.select('tbody', true).first();
5533 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5534 e.on('click', _this.sort, _this);
5537 this.el.on("click", this.onClick, this);
5538 this.el.on("dblclick", this.onDblClick, this);
5540 // why is this done????? = it breaks dialogs??
5541 //this.parent().el.setStyle('position', 'relative');
5545 this.footer.parentId = this.id;
5546 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
5549 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
5551 this.store.on('load', this.onLoad, this);
5552 this.store.on('beforeload', this.onBeforeLoad, this);
5553 this.store.on('update', this.onUpdate, this);
5554 this.store.on('add', this.onAdd, this);
5558 onMouseover : 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('mouseover', this, cell, rowIndex, cellIndex, e);
5578 onMouseout : function(e, el)
5580 var cell = Roo.get(el);
5586 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5587 cell = cell.findParent('td', false, true);
5590 var row = cell.findParent('tr', false, true);
5591 var cellIndex = cell.dom.cellIndex;
5592 var rowIndex = row.dom.rowIndex - 1; // start from 0
5594 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
5598 onClick : function(e, el)
5600 var cell = Roo.get(el);
5602 if(!cell || (!this.CellSelection && !this.RowSelection)){
5606 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5607 cell = cell.findParent('td', false, true);
5610 if(!cell || typeof(cell) == 'undefined'){
5614 var row = cell.findParent('tr', false, true);
5616 if(!row || typeof(row) == 'undefined'){
5620 var cellIndex = cell.dom.cellIndex;
5621 var rowIndex = this.getRowIndex(row);
5623 if(this.CellSelection){
5624 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
5627 if(this.RowSelection){
5628 this.fireEvent('rowclick', this, row, rowIndex, e);
5634 onDblClick : function(e,el)
5636 var cell = Roo.get(el);
5638 if(!cell || (!this.CellSelection && !this.RowSelection)){
5642 if(e.getTarget().nodeName.toLowerCase() != 'td'){
5643 cell = cell.findParent('td', false, true);
5646 if(!cell || typeof(cell) == 'undefined'){
5650 var row = cell.findParent('tr', false, true);
5652 if(!row || typeof(row) == 'undefined'){
5656 var cellIndex = cell.dom.cellIndex;
5657 var rowIndex = this.getRowIndex(row);
5659 if(this.CellSelection){
5660 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
5663 if(this.RowSelection){
5664 this.fireEvent('rowdblclick', this, row, rowIndex, e);
5668 sort : function(e,el)
5670 var col = Roo.get(el);
5672 if(!col.hasClass('sortable')){
5676 var sort = col.attr('sort');
5679 if(col.hasClass('glyphicon-arrow-up')){
5683 this.store.sortInfo = {field : sort, direction : dir};
5686 Roo.log("calling footer first");
5687 this.footer.onClick('first');
5690 this.store.load({ params : { start : 0 } });
5694 renderHeader : function()
5703 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5705 var config = cm.config[i];
5710 html: cm.getColumnHeader(i)
5713 if(typeof(config.tooltip) != 'undefined'){
5714 c.tooltip = config.tooltip;
5717 if(typeof(config.colspan) != 'undefined'){
5718 c.colspan = config.colspan;
5721 if(typeof(config.hidden) != 'undefined' && config.hidden){
5722 c.style += ' display:none;';
5725 if(typeof(config.dataIndex) != 'undefined'){
5726 c.sort = config.dataIndex;
5729 if(typeof(config.sortable) != 'undefined' && config.sortable){
5733 if(typeof(config.align) != 'undefined' && config.align.length){
5734 c.style += ' text-align:' + config.align + ';';
5737 if(typeof(config.width) != 'undefined'){
5738 c.style += ' width:' + config.width + 'px;';
5741 if(typeof(config.cls) != 'undefined'){
5742 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
5751 renderBody : function()
5761 colspan : this.cm.getColumnCount()
5771 renderFooter : function()
5781 colspan : this.cm.getColumnCount()
5795 Roo.log('ds onload');
5800 var ds = this.store;
5802 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
5803 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
5805 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
5806 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
5809 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
5810 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
5814 var tbody = this.mainBody;
5816 if(ds.getCount() > 0){
5817 ds.data.each(function(d,rowIndex){
5818 var row = this.renderRow(cm, ds, rowIndex);
5820 tbody.createChild(row);
5824 if(row.cellObjects.length){
5825 Roo.each(row.cellObjects, function(r){
5826 _this.renderCellObject(r);
5833 Roo.each(this.el.select('tbody td', true).elements, function(e){
5834 e.on('mouseover', _this.onMouseover, _this);
5837 Roo.each(this.el.select('tbody td', true).elements, function(e){
5838 e.on('mouseout', _this.onMouseout, _this);
5840 this.fireEvent('rowsrendered', this);
5841 //if(this.loadMask){
5842 // this.maskEl.hide();
5847 onUpdate : function(ds,record)
5849 this.refreshRow(record);
5852 onRemove : function(ds, record, index, isUpdate){
5853 if(isUpdate !== true){
5854 this.fireEvent("beforerowremoved", this, index, record);
5856 var bt = this.mainBody.dom;
5858 var rows = this.el.select('tbody > tr', true).elements;
5860 if(typeof(rows[index]) != 'undefined'){
5861 bt.removeChild(rows[index].dom);
5864 // if(bt.rows[index]){
5865 // bt.removeChild(bt.rows[index]);
5868 if(isUpdate !== true){
5869 //this.stripeRows(index);
5870 //this.syncRowHeights(index, index);
5872 this.fireEvent("rowremoved", this, index, record);
5876 onAdd : function(ds, records, rowIndex)
5878 //Roo.log('on Add called');
5879 // - note this does not handle multiple adding very well..
5880 var bt = this.mainBody.dom;
5881 for (var i =0 ; i < records.length;i++) {
5882 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
5883 //Roo.log(records[i]);
5884 //Roo.log(this.store.getAt(rowIndex+i));
5885 this.insertRow(this.store, rowIndex + i, false);
5892 refreshRow : function(record){
5893 var ds = this.store, index;
5894 if(typeof record == 'number'){
5896 record = ds.getAt(index);
5898 index = ds.indexOf(record);
5900 this.insertRow(ds, index, true);
5901 this.onRemove(ds, record, index+1, true);
5902 //this.syncRowHeights(index, index);
5904 this.fireEvent("rowupdated", this, index, record);
5907 insertRow : function(dm, rowIndex, isUpdate){
5910 this.fireEvent("beforerowsinserted", this, rowIndex);
5912 //var s = this.getScrollState();
5913 var row = this.renderRow(this.cm, this.store, rowIndex);
5914 // insert before rowIndex..
5915 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
5919 if(row.cellObjects.length){
5920 Roo.each(row.cellObjects, function(r){
5921 _this.renderCellObject(r);
5926 this.fireEvent("rowsinserted", this, rowIndex);
5927 //this.syncRowHeights(firstRow, lastRow);
5928 //this.stripeRows(firstRow);
5935 getRowDom : function(rowIndex)
5937 var rows = this.el.select('tbody > tr', true).elements;
5939 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
5942 // returns the object tree for a tr..
5945 renderRow : function(cm, ds, rowIndex)
5948 var d = ds.getAt(rowIndex);
5955 var cellObjects = [];
5957 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
5958 var config = cm.config[i];
5960 var renderer = cm.getRenderer(i);
5964 if(typeof(renderer) !== 'undefined'){
5965 value = renderer(d.data[cm.getDataIndex(i)], false, d);
5967 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
5968 // and are rendered into the cells after the row is rendered - using the id for the element.
5970 if(typeof(value) === 'object'){
5980 rowIndex : rowIndex,
5985 this.fireEvent('rowclass', this, rowcfg);
5989 cls : rowcfg.rowClass,
5991 html: (typeof(value) === 'object') ? '' : value
5998 if(typeof(config.colspan) != 'undefined'){
5999 td.colspan = config.colspan;
6002 if(typeof(config.hidden) != 'undefined' && config.hidden){
6003 td.style += ' display:none;';
6006 if(typeof(config.align) != 'undefined' && config.align.length){
6007 td.style += ' text-align:' + config.align + ';';
6010 if(typeof(config.width) != 'undefined'){
6011 td.style += ' width:' + config.width + 'px;';
6014 if(typeof(config.cursor) != 'undefined'){
6015 td.style += ' cursor:' + config.cursor + ';';
6018 if(typeof(config.cls) != 'undefined'){
6019 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
6026 row.cellObjects = cellObjects;
6034 onBeforeLoad : function()
6036 //Roo.log('ds onBeforeLoad');
6040 //if(this.loadMask){
6041 // this.maskEl.show();
6049 this.el.select('tbody', true).first().dom.innerHTML = '';
6052 * Show or hide a row.
6053 * @param {Number} rowIndex to show or hide
6054 * @param {Boolean} state hide
6056 setRowVisibility : function(rowIndex, state)
6058 var bt = this.mainBody.dom;
6060 var rows = this.el.select('tbody > tr', true).elements;
6062 if(typeof(rows[rowIndex]) == 'undefined'){
6065 rows[rowIndex].dom.style.display = state ? '' : 'none';
6069 getSelectionModel : function(){
6071 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
6073 return this.selModel;
6076 * Render the Roo.bootstrap object from renderder
6078 renderCellObject : function(r)
6082 var t = r.cfg.render(r.container);
6085 Roo.each(r.cfg.cn, function(c){
6087 container: t.getChildContainer(),
6090 _this.renderCellObject(child);
6095 getRowIndex : function(row)
6099 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
6122 * @class Roo.bootstrap.TableCell
6123 * @extends Roo.bootstrap.Component
6124 * Bootstrap TableCell class
6125 * @cfg {String} html cell contain text
6126 * @cfg {String} cls cell class
6127 * @cfg {String} tag cell tag (td|th) default td
6128 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
6129 * @cfg {String} align Aligns the content in a cell
6130 * @cfg {String} axis Categorizes cells
6131 * @cfg {String} bgcolor Specifies the background color of a cell
6132 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6133 * @cfg {Number} colspan Specifies the number of columns a cell should span
6134 * @cfg {String} headers Specifies one or more header cells a cell is related to
6135 * @cfg {Number} height Sets the height of a cell
6136 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
6137 * @cfg {Number} rowspan Sets the number of rows a cell should span
6138 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
6139 * @cfg {String} valign Vertical aligns the content in a cell
6140 * @cfg {Number} width Specifies the width of a cell
6143 * Create a new TableCell
6144 * @param {Object} config The config object
6147 Roo.bootstrap.TableCell = function(config){
6148 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
6151 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
6171 getAutoCreate : function(){
6172 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
6192 cfg.align=this.align
6198 cfg.bgcolor=this.bgcolor
6201 cfg.charoff=this.charoff
6204 cfg.colspan=this.colspan
6207 cfg.headers=this.headers
6210 cfg.height=this.height
6213 cfg.nowrap=this.nowrap
6216 cfg.rowspan=this.rowspan
6219 cfg.scope=this.scope
6222 cfg.valign=this.valign
6225 cfg.width=this.width
6244 * @class Roo.bootstrap.TableRow
6245 * @extends Roo.bootstrap.Component
6246 * Bootstrap TableRow class
6247 * @cfg {String} cls row class
6248 * @cfg {String} align Aligns the content in a table row
6249 * @cfg {String} bgcolor Specifies a background color for a table row
6250 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
6251 * @cfg {String} valign Vertical aligns the content in a table row
6254 * Create a new TableRow
6255 * @param {Object} config The config object
6258 Roo.bootstrap.TableRow = function(config){
6259 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
6262 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
6270 getAutoCreate : function(){
6271 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
6281 cfg.align = this.align;
6284 cfg.bgcolor = this.bgcolor;
6287 cfg.charoff = this.charoff;
6290 cfg.valign = this.valign;
6308 * @class Roo.bootstrap.TableBody
6309 * @extends Roo.bootstrap.Component
6310 * Bootstrap TableBody class
6311 * @cfg {String} cls element class
6312 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
6313 * @cfg {String} align Aligns the content inside the element
6314 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
6315 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
6318 * Create a new TableBody
6319 * @param {Object} config The config object
6322 Roo.bootstrap.TableBody = function(config){
6323 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
6326 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
6334 getAutoCreate : function(){
6335 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
6349 cfg.align = this.align;
6352 cfg.charoff = this.charoff;
6355 cfg.valign = this.valign;
6362 // initEvents : function()
6369 // this.store = Roo.factory(this.store, Roo.data);
6370 // this.store.on('load', this.onLoad, this);
6372 // this.store.load();
6376 // onLoad: function ()
6378 // this.fireEvent('load', this);
6388 * Ext JS Library 1.1.1
6389 * Copyright(c) 2006-2007, Ext JS, LLC.
6391 * Originally Released Under LGPL - original licence link has changed is not relivant.
6394 * <script type="text/javascript">
6397 // as we use this in bootstrap.
6398 Roo.namespace('Roo.form');
6400 * @class Roo.form.Action
6401 * Internal Class used to handle form actions
6403 * @param {Roo.form.BasicForm} el The form element or its id
6404 * @param {Object} config Configuration options
6409 // define the action interface
6410 Roo.form.Action = function(form, options){
6412 this.options = options || {};
6415 * Client Validation Failed
6418 Roo.form.Action.CLIENT_INVALID = 'client';
6420 * Server Validation Failed
6423 Roo.form.Action.SERVER_INVALID = 'server';
6425 * Connect to Server Failed
6428 Roo.form.Action.CONNECT_FAILURE = 'connect';
6430 * Reading Data from Server Failed
6433 Roo.form.Action.LOAD_FAILURE = 'load';
6435 Roo.form.Action.prototype = {
6437 failureType : undefined,
6438 response : undefined,
6442 run : function(options){
6447 success : function(response){
6452 handleResponse : function(response){
6456 // default connection failure
6457 failure : function(response){
6459 this.response = response;
6460 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6461 this.form.afterAction(this, false);
6464 processResponse : function(response){
6465 this.response = response;
6466 if(!response.responseText){
6469 this.result = this.handleResponse(response);
6473 // utility functions used internally
6474 getUrl : function(appendParams){
6475 var url = this.options.url || this.form.url || this.form.el.dom.action;
6477 var p = this.getParams();
6479 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
6485 getMethod : function(){
6486 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
6489 getParams : function(){
6490 var bp = this.form.baseParams;
6491 var p = this.options.params;
6493 if(typeof p == "object"){
6494 p = Roo.urlEncode(Roo.applyIf(p, bp));
6495 }else if(typeof p == 'string' && bp){
6496 p += '&' + Roo.urlEncode(bp);
6499 p = Roo.urlEncode(bp);
6504 createCallback : function(){
6506 success: this.success,
6507 failure: this.failure,
6509 timeout: (this.form.timeout*1000),
6510 upload: this.form.fileUpload ? this.success : undefined
6515 Roo.form.Action.Submit = function(form, options){
6516 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
6519 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
6522 haveProgress : false,
6523 uploadComplete : false,
6525 // uploadProgress indicator.
6526 uploadProgress : function()
6528 if (!this.form.progressUrl) {
6532 if (!this.haveProgress) {
6533 Roo.MessageBox.progress("Uploading", "Uploading");
6535 if (this.uploadComplete) {
6536 Roo.MessageBox.hide();
6540 this.haveProgress = true;
6542 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
6544 var c = new Roo.data.Connection();
6546 url : this.form.progressUrl,
6551 success : function(req){
6552 //console.log(data);
6556 rdata = Roo.decode(req.responseText)
6558 Roo.log("Invalid data from server..");
6562 if (!rdata || !rdata.success) {
6564 Roo.MessageBox.alert(Roo.encode(rdata));
6567 var data = rdata.data;
6569 if (this.uploadComplete) {
6570 Roo.MessageBox.hide();
6575 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
6576 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
6579 this.uploadProgress.defer(2000,this);
6582 failure: function(data) {
6583 Roo.log('progress url failed ');
6594 // run get Values on the form, so it syncs any secondary forms.
6595 this.form.getValues();
6597 var o = this.options;
6598 var method = this.getMethod();
6599 var isPost = method == 'POST';
6600 if(o.clientValidation === false || this.form.isValid()){
6602 if (this.form.progressUrl) {
6603 this.form.findField('UPLOAD_IDENTIFIER').setValue(
6604 (new Date() * 1) + '' + Math.random());
6609 Roo.Ajax.request(Roo.apply(this.createCallback(), {
6610 form:this.form.el.dom,
6611 url:this.getUrl(!isPost),
6613 params:isPost ? this.getParams() : null,
6614 isUpload: this.form.fileUpload
6617 this.uploadProgress();
6619 }else if (o.clientValidation !== false){ // client validation failed
6620 this.failureType = Roo.form.Action.CLIENT_INVALID;
6621 this.form.afterAction(this, false);
6625 success : function(response)
6627 this.uploadComplete= true;
6628 if (this.haveProgress) {
6629 Roo.MessageBox.hide();
6633 var result = this.processResponse(response);
6634 if(result === true || result.success){
6635 this.form.afterAction(this, true);
6639 this.form.markInvalid(result.errors);
6640 this.failureType = Roo.form.Action.SERVER_INVALID;
6642 this.form.afterAction(this, false);
6644 failure : function(response)
6646 this.uploadComplete= true;
6647 if (this.haveProgress) {
6648 Roo.MessageBox.hide();
6651 this.response = response;
6652 this.failureType = Roo.form.Action.CONNECT_FAILURE;
6653 this.form.afterAction(this, false);
6656 handleResponse : function(response){
6657 if(this.form.errorReader){
6658 var rs = this.form.errorReader.read(response);
6661 for(var i = 0, len = rs.records.length; i < len; i++) {
6662 var r = rs.records[i];
6666 if(errors.length < 1){
6670 success : rs.success,
6676 ret = Roo.decode(response.responseText);
6680 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
6690 Roo.form.Action.Load = function(form, options){
6691 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
6692 this.reader = this.form.reader;
6695 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
6700 Roo.Ajax.request(Roo.apply(
6701 this.createCallback(), {
6702 method:this.getMethod(),
6703 url:this.getUrl(false),
6704 params:this.getParams()
6708 success : function(response){
6710 var result = this.processResponse(response);
6711 if(result === true || !result.success || !result.data){
6712 this.failureType = Roo.form.Action.LOAD_FAILURE;
6713 this.form.afterAction(this, false);
6716 this.form.clearInvalid();
6717 this.form.setValues(result.data);
6718 this.form.afterAction(this, true);
6721 handleResponse : function(response){
6722 if(this.form.reader){
6723 var rs = this.form.reader.read(response);
6724 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
6726 success : rs.success,
6730 return Roo.decode(response.responseText);
6734 Roo.form.Action.ACTION_TYPES = {
6735 'load' : Roo.form.Action.Load,
6736 'submit' : Roo.form.Action.Submit
6745 * @class Roo.bootstrap.Form
6746 * @extends Roo.bootstrap.Component
6747 * Bootstrap Form class
6748 * @cfg {String} method GET | POST (default POST)
6749 * @cfg {String} labelAlign top | left (default top)
6750 * @cfg {String} align left | right - for navbars
6751 * @cfg {Boolean} loadMask load mask when submit (default true)
6756 * @param {Object} config The config object
6760 Roo.bootstrap.Form = function(config){
6761 Roo.bootstrap.Form.superclass.constructor.call(this, config);
6764 * @event clientvalidation
6765 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
6766 * @param {Form} this
6767 * @param {Boolean} valid true if the form has passed client-side validation
6769 clientvalidation: true,
6771 * @event beforeaction
6772 * Fires before any action is performed. Return false to cancel the action.
6773 * @param {Form} this
6774 * @param {Action} action The action to be performed
6778 * @event actionfailed
6779 * Fires when an action fails.
6780 * @param {Form} this
6781 * @param {Action} action The action that failed
6783 actionfailed : true,
6785 * @event actioncomplete
6786 * Fires when an action is completed.
6787 * @param {Form} this
6788 * @param {Action} action The action that completed
6790 actioncomplete : true
6795 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
6798 * @cfg {String} method
6799 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
6804 * The URL to use for form actions if one isn't supplied in the action options.
6807 * @cfg {Boolean} fileUpload
6808 * Set to true if this form is a file upload.
6812 * @cfg {Object} baseParams
6813 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
6817 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
6821 * @cfg {Sting} align (left|right) for navbar forms
6826 activeAction : null,
6829 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
6830 * element by passing it or its id or mask the form itself by passing in true.
6833 waitMsgTarget : false,
6837 getAutoCreate : function(){
6841 method : this.method || 'POST',
6842 id : this.id || Roo.id(),
6845 if (this.parent().xtype.match(/^Nav/)) {
6846 cfg.cls = 'navbar-form navbar-' + this.align;
6850 if (this.labelAlign == 'left' ) {
6851 cfg.cls += ' form-horizontal';
6857 initEvents : function()
6859 this.el.on('submit', this.onSubmit, this);
6860 // this was added as random key presses on the form where triggering form submit.
6861 this.el.on('keypress', function(e) {
6862 if (e.getCharCode() != 13) {
6865 // we might need to allow it for textareas.. and some other items.
6866 // check e.getTarget().
6868 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
6872 Roo.log("keypress blocked");
6880 onSubmit : function(e){
6885 * Returns true if client-side validation on the form is successful.
6888 isValid : function(){
6889 var items = this.getItems();
6891 items.each(function(f){
6900 * Returns true if any fields in this form have changed since their original load.
6903 isDirty : function(){
6905 var items = this.getItems();
6906 items.each(function(f){
6916 * Performs a predefined action (submit or load) or custom actions you define on this form.
6917 * @param {String} actionName The name of the action type
6918 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
6919 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
6920 * accept other config options):
6922 Property Type Description
6923 ---------------- --------------- ----------------------------------------------------------------------------------
6924 url String The url for the action (defaults to the form's url)
6925 method String The form method to use (defaults to the form's method, or POST if not defined)
6926 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
6927 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
6928 validate the form on the client (defaults to false)
6930 * @return {BasicForm} this
6932 doAction : function(action, options){
6933 if(typeof action == 'string'){
6934 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
6936 if(this.fireEvent('beforeaction', this, action) !== false){
6937 this.beforeAction(action);
6938 action.run.defer(100, action);
6944 beforeAction : function(action){
6945 var o = action.options;
6948 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6950 // not really supported yet.. ??
6952 //if(this.waitMsgTarget === true){
6953 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
6954 //}else if(this.waitMsgTarget){
6955 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
6956 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
6958 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
6964 afterAction : function(action, success){
6965 this.activeAction = null;
6966 var o = action.options;
6968 //if(this.waitMsgTarget === true){
6970 //}else if(this.waitMsgTarget){
6971 // this.waitMsgTarget.unmask();
6973 // Roo.MessageBox.updateProgress(1);
6974 // Roo.MessageBox.hide();
6981 Roo.callback(o.success, o.scope, [this, action]);
6982 this.fireEvent('actioncomplete', this, action);
6986 // failure condition..
6987 // we have a scenario where updates need confirming.
6988 // eg. if a locking scenario exists..
6989 // we look for { errors : { needs_confirm : true }} in the response.
6991 (typeof(action.result) != 'undefined') &&
6992 (typeof(action.result.errors) != 'undefined') &&
6993 (typeof(action.result.errors.needs_confirm) != 'undefined')
6996 Roo.log("not supported yet");
6999 Roo.MessageBox.confirm(
7000 "Change requires confirmation",
7001 action.result.errorMsg,
7006 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
7016 Roo.callback(o.failure, o.scope, [this, action]);
7017 // show an error message if no failed handler is set..
7018 if (!this.hasListener('actionfailed')) {
7019 Roo.log("need to add dialog support");
7021 Roo.MessageBox.alert("Error",
7022 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
7023 action.result.errorMsg :
7024 "Saving Failed, please check your entries or try again"
7029 this.fireEvent('actionfailed', this, action);
7034 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
7035 * @param {String} id The value to search for
7038 findField : function(id){
7039 var items = this.getItems();
7040 var field = items.get(id);
7042 items.each(function(f){
7043 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
7050 return field || null;
7053 * Mark fields in this form invalid in bulk.
7054 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
7055 * @return {BasicForm} this
7057 markInvalid : function(errors){
7058 if(errors instanceof Array){
7059 for(var i = 0, len = errors.length; i < len; i++){
7060 var fieldError = errors[i];
7061 var f = this.findField(fieldError.id);
7063 f.markInvalid(fieldError.msg);
7069 if(typeof errors[id] != 'function' && (field = this.findField(id))){
7070 field.markInvalid(errors[id]);
7074 //Roo.each(this.childForms || [], function (f) {
7075 // f.markInvalid(errors);
7082 * Set values for fields in this form in bulk.
7083 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
7084 * @return {BasicForm} this
7086 setValues : function(values){
7087 if(values instanceof Array){ // array of objects
7088 for(var i = 0, len = values.length; i < len; i++){
7090 var f = this.findField(v.id);
7092 f.setValue(v.value);
7093 if(this.trackResetOnLoad){
7094 f.originalValue = f.getValue();
7098 }else{ // object hash
7101 if(typeof values[id] != 'function' && (field = this.findField(id))){
7103 if (field.setFromData &&
7105 field.displayField &&
7106 // combos' with local stores can
7107 // be queried via setValue()
7108 // to set their value..
7109 (field.store && !field.store.isLocal)
7113 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
7114 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
7115 field.setFromData(sd);
7118 field.setValue(values[id]);
7122 if(this.trackResetOnLoad){
7123 field.originalValue = field.getValue();
7129 //Roo.each(this.childForms || [], function (f) {
7130 // f.setValues(values);
7137 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
7138 * they are returned as an array.
7139 * @param {Boolean} asString
7142 getValues : function(asString){
7143 //if (this.childForms) {
7144 // copy values from the child forms
7145 // Roo.each(this.childForms, function (f) {
7146 // this.setValues(f.getValues());
7152 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
7153 if(asString === true){
7156 return Roo.urlDecode(fs);
7160 * Returns the fields in this form as an object with key/value pairs.
7161 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
7164 getFieldValues : function(with_hidden)
7166 var items = this.getItems();
7168 items.each(function(f){
7172 var v = f.getValue();
7173 if (f.inputType =='radio') {
7174 if (typeof(ret[f.getName()]) == 'undefined') {
7175 ret[f.getName()] = ''; // empty..
7178 if (!f.el.dom.checked) {
7186 // not sure if this supported any more..
7187 if ((typeof(v) == 'object') && f.getRawValue) {
7188 v = f.getRawValue() ; // dates..
7190 // combo boxes where name != hiddenName...
7191 if (f.name != f.getName()) {
7192 ret[f.name] = f.getRawValue();
7194 ret[f.getName()] = v;
7201 * Clears all invalid messages in this form.
7202 * @return {BasicForm} this
7204 clearInvalid : function(){
7205 var items = this.getItems();
7207 items.each(function(f){
7218 * @return {BasicForm} this
7221 var items = this.getItems();
7222 items.each(function(f){
7226 Roo.each(this.childForms || [], function (f) {
7233 getItems : function()
7235 var r=new Roo.util.MixedCollection(false, function(o){
7236 return o.id || (o.id = Roo.id());
7238 var iter = function(el) {
7245 Roo.each(el.items,function(e) {
7265 * Ext JS Library 1.1.1
7266 * Copyright(c) 2006-2007, Ext JS, LLC.
7268 * Originally Released Under LGPL - original licence link has changed is not relivant.
7271 * <script type="text/javascript">
7274 * @class Roo.form.VTypes
7275 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
7278 Roo.form.VTypes = function(){
7279 // closure these in so they are only created once.
7280 var alpha = /^[a-zA-Z_]+$/;
7281 var alphanum = /^[a-zA-Z0-9_]+$/;
7282 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
7283 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
7285 // All these messages and functions are configurable
7288 * The function used to validate email addresses
7289 * @param {String} value The email address
7291 'email' : function(v){
7292 return email.test(v);
7295 * The error text to display when the email validation function returns false
7298 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
7300 * The keystroke filter mask to be applied on email input
7303 'emailMask' : /[a-z0-9_\.\-@]/i,
7306 * The function used to validate URLs
7307 * @param {String} value The URL
7309 'url' : function(v){
7313 * The error text to display when the url validation function returns false
7316 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
7319 * The function used to validate alpha values
7320 * @param {String} value The value
7322 'alpha' : function(v){
7323 return alpha.test(v);
7326 * The error text to display when the alpha validation function returns false
7329 'alphaText' : 'This field should only contain letters and _',
7331 * The keystroke filter mask to be applied on alpha input
7334 'alphaMask' : /[a-z_]/i,
7337 * The function used to validate alphanumeric values
7338 * @param {String} value The value
7340 'alphanum' : function(v){
7341 return alphanum.test(v);
7344 * The error text to display when the alphanumeric validation function returns false
7347 'alphanumText' : 'This field should only contain letters, numbers and _',
7349 * The keystroke filter mask to be applied on alphanumeric input
7352 'alphanumMask' : /[a-z0-9_]/i
7362 * @class Roo.bootstrap.Input
7363 * @extends Roo.bootstrap.Component
7364 * Bootstrap Input class
7365 * @cfg {Boolean} disabled is it disabled
7366 * @cfg {String} fieldLabel - the label associated
7367 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
7368 * @cfg {String} name name of the input
7369 * @cfg {string} fieldLabel - the label associated
7370 * @cfg {string} inputType - input / file submit ...
7371 * @cfg {string} placeholder - placeholder to put in text.
7372 * @cfg {string} before - input group add on before
7373 * @cfg {string} after - input group add on after
7374 * @cfg {string} size - (lg|sm) or leave empty..
7375 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
7376 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
7377 * @cfg {Number} md colspan out of 12 for computer-sized screens
7378 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
7379 * @cfg {string} value default value of the input
7380 * @cfg {Number} labelWidth set the width of label (0-12)
7381 * @cfg {String} labelAlign (top|left)
7382 * @cfg {Boolean} readOnly Specifies that the field should be read-only
7383 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
7385 * @cfg {String} align (left|center|right) Default left
7390 * Create a new Input
7391 * @param {Object} config The config object
7394 Roo.bootstrap.Input = function(config){
7395 Roo.bootstrap.Input.superclass.constructor.call(this, config);
7400 * Fires when this field receives input focus.
7401 * @param {Roo.form.Field} this
7406 * Fires when this field loses input focus.
7407 * @param {Roo.form.Field} this
7412 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
7413 * {@link Roo.EventObject#getKey} to determine which key was pressed.
7414 * @param {Roo.form.Field} this
7415 * @param {Roo.EventObject} e The event object
7420 * Fires just before the field blurs if the field value has changed.
7421 * @param {Roo.form.Field} this
7422 * @param {Mixed} newValue The new value
7423 * @param {Mixed} oldValue The original value
7428 * Fires after the field has been marked as invalid.
7429 * @param {Roo.form.Field} this
7430 * @param {String} msg The validation message
7435 * Fires after the field has been validated with no errors.
7436 * @param {Roo.form.Field} this
7441 * Fires after the key up
7442 * @param {Roo.form.Field} this
7443 * @param {Roo.EventObject} e The event Object
7449 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
7451 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
7452 automatic validation (defaults to "keyup").
7454 validationEvent : "keyup",
7456 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
7458 validateOnBlur : true,
7460 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
7462 validationDelay : 250,
7464 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
7466 focusClass : "x-form-focus", // not needed???
7470 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
7472 invalidClass : "has-warning",
7475 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
7477 validClass : "has-success",
7480 * @cfg {Boolean} hasFeedback (true|false) default true
7485 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7487 invalidFeedbackClass : "glyphicon-warning-sign",
7490 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
7492 validFeedbackClass : "glyphicon-ok",
7495 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
7497 selectOnFocus : false,
7500 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
7504 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
7509 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
7511 disableKeyFilter : false,
7514 * @cfg {Boolean} disabled True to disable the field (defaults to false).
7518 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
7522 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
7524 blankText : "This field is required",
7527 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
7531 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
7533 maxLength : Number.MAX_VALUE,
7535 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
7537 minLengthText : "The minimum length for this field is {0}",
7539 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
7541 maxLengthText : "The maximum length for this field is {0}",
7545 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
7546 * If available, this function will be called only after the basic validators all return true, and will be passed the
7547 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
7551 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
7552 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
7553 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
7557 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
7561 autocomplete: false,
7580 formatedValue : false,
7582 parentLabelAlign : function()
7585 while (parent.parent()) {
7586 parent = parent.parent();
7587 if (typeof(parent.labelAlign) !='undefined') {
7588 return parent.labelAlign;
7595 getAutoCreate : function(){
7597 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7603 if(this.inputType != 'hidden'){
7604 cfg.cls = 'form-group' //input-group
7610 type : this.inputType,
7612 cls : 'form-control',
7613 placeholder : this.placeholder || '',
7614 autocomplete : this.autocomplete || 'new-password'
7619 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
7622 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7623 input.maxLength = this.maxLength;
7626 if (this.disabled) {
7627 input.disabled=true;
7630 if (this.readOnly) {
7631 input.readonly=true;
7635 input.name = this.name;
7638 input.cls += ' input-' + this.size;
7641 ['xs','sm','md','lg'].map(function(size){
7642 if (settings[size]) {
7643 cfg.cls += ' col-' + size + '-' + settings[size];
7647 var inputblock = input;
7651 cls: 'glyphicon form-control-feedback'
7654 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7657 cls : 'has-feedback',
7665 if (this.before || this.after) {
7668 cls : 'input-group',
7672 if (this.before && typeof(this.before) == 'string') {
7674 inputblock.cn.push({
7676 cls : 'roo-input-before input-group-addon',
7680 if (this.before && typeof(this.before) == 'object') {
7681 this.before = Roo.factory(this.before);
7682 Roo.log(this.before);
7683 inputblock.cn.push({
7685 cls : 'roo-input-before input-group-' +
7686 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7690 inputblock.cn.push(input);
7692 if (this.after && typeof(this.after) == 'string') {
7693 inputblock.cn.push({
7695 cls : 'roo-input-after input-group-addon',
7699 if (this.after && typeof(this.after) == 'object') {
7700 this.after = Roo.factory(this.after);
7701 Roo.log(this.after);
7702 inputblock.cn.push({
7704 cls : 'roo-input-after input-group-' +
7705 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
7709 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
7710 inputblock.cls += ' has-feedback';
7711 inputblock.cn.push(feedback);
7715 if (align ==='left' && this.fieldLabel.length) {
7716 Roo.log("left and has label");
7722 cls : 'control-label col-sm-' + this.labelWidth,
7723 html : this.fieldLabel
7727 cls : "col-sm-" + (12 - this.labelWidth),
7734 } else if ( this.fieldLabel.length) {
7740 //cls : 'input-group-addon',
7741 html : this.fieldLabel
7751 Roo.log(" no label && no align");
7760 Roo.log('input-parentType: ' + this.parentType);
7762 if (this.parentType === 'Navbar' && this.parent().bar) {
7763 cfg.cls += ' navbar-form';
7771 * return the real input element.
7773 inputEl: function ()
7775 return this.el.select('input.form-control',true).first();
7778 tooltipEl : function()
7780 return this.inputEl();
7783 setDisabled : function(v)
7785 var i = this.inputEl().dom;
7787 i.removeAttribute('disabled');
7791 i.setAttribute('disabled','true');
7793 initEvents : function()
7796 this.inputEl().on("keydown" , this.fireKey, this);
7797 this.inputEl().on("focus", this.onFocus, this);
7798 this.inputEl().on("blur", this.onBlur, this);
7800 this.inputEl().relayEvent('keyup', this);
7802 // reference to original value for reset
7803 this.originalValue = this.getValue();
7804 //Roo.form.TextField.superclass.initEvents.call(this);
7805 if(this.validationEvent == 'keyup'){
7806 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
7807 this.inputEl().on('keyup', this.filterValidation, this);
7809 else if(this.validationEvent !== false){
7810 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
7813 if(this.selectOnFocus){
7814 this.on("focus", this.preFocus, this);
7817 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
7818 this.inputEl().on("keypress", this.filterKeys, this);
7821 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
7822 this.el.on("click", this.autoSize, this);
7825 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
7826 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
7829 if (typeof(this.before) == 'object') {
7830 this.before.render(this.el.select('.roo-input-before',true).first());
7832 if (typeof(this.after) == 'object') {
7833 this.after.render(this.el.select('.roo-input-after',true).first());
7838 filterValidation : function(e){
7839 if(!e.isNavKeyPress()){
7840 this.validationTask.delay(this.validationDelay);
7844 * Validates the field value
7845 * @return {Boolean} True if the value is valid, else false
7847 validate : function(){
7848 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
7849 if(this.disabled || this.validateValue(this.getRawValue())){
7860 * Validates a value according to the field's validation rules and marks the field as invalid
7861 * if the validation fails
7862 * @param {Mixed} value The value to validate
7863 * @return {Boolean} True if the value is valid, else false
7865 validateValue : function(value){
7866 if(value.length < 1) { // if it's blank
7867 if(this.allowBlank){
7873 if(value.length < this.minLength){
7876 if(value.length > this.maxLength){
7880 var vt = Roo.form.VTypes;
7881 if(!vt[this.vtype](value, this)){
7885 if(typeof this.validator == "function"){
7886 var msg = this.validator(value);
7892 if(this.regex && !this.regex.test(value)){
7902 fireKey : function(e){
7903 //Roo.log('field ' + e.getKey());
7904 if(e.isNavKeyPress()){
7905 this.fireEvent("specialkey", this, e);
7908 focus : function (selectText){
7910 this.inputEl().focus();
7911 if(selectText === true){
7912 this.inputEl().dom.select();
7918 onFocus : function(){
7919 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7920 // this.el.addClass(this.focusClass);
7923 this.hasFocus = true;
7924 this.startValue = this.getValue();
7925 this.fireEvent("focus", this);
7929 beforeBlur : Roo.emptyFn,
7933 onBlur : function(){
7935 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
7936 //this.el.removeClass(this.focusClass);
7938 this.hasFocus = false;
7939 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
7942 var v = this.getValue();
7943 if(String(v) !== String(this.startValue)){
7944 this.fireEvent('change', this, v, this.startValue);
7946 this.fireEvent("blur", this);
7950 * Resets the current field value to the originally loaded value and clears any validation messages
7953 this.setValue(this.originalValue);
7957 * Returns the name of the field
7958 * @return {Mixed} name The name field
7960 getName: function(){
7964 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
7965 * @return {Mixed} value The field value
7967 getValue : function(){
7969 var v = this.inputEl().getValue();
7974 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
7975 * @return {Mixed} value The field value
7977 getRawValue : function(){
7978 var v = this.inputEl().getValue();
7984 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
7985 * @param {Mixed} value The value to set
7987 setRawValue : function(v){
7988 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
7991 selectText : function(start, end){
7992 var v = this.getRawValue();
7994 start = start === undefined ? 0 : start;
7995 end = end === undefined ? v.length : end;
7996 var d = this.inputEl().dom;
7997 if(d.setSelectionRange){
7998 d.setSelectionRange(start, end);
7999 }else if(d.createTextRange){
8000 var range = d.createTextRange();
8001 range.moveStart("character", start);
8002 range.moveEnd("character", v.length-end);
8009 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
8010 * @param {Mixed} value The value to set
8012 setValue : function(v){
8015 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
8021 processValue : function(value){
8022 if(this.stripCharsRe){
8023 var newValue = value.replace(this.stripCharsRe, '');
8024 if(newValue !== value){
8025 this.setRawValue(newValue);
8032 preFocus : function(){
8034 if(this.selectOnFocus){
8035 this.inputEl().dom.select();
8038 filterKeys : function(e){
8040 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
8043 var c = e.getCharCode(), cc = String.fromCharCode(c);
8044 if(Roo.isIE && (e.isSpecialKey() || !cc)){
8047 if(!this.maskRe.test(cc)){
8052 * Clear any invalid styles/messages for this field
8054 clearInvalid : function(){
8056 if(!this.el || this.preventMark){ // not rendered
8059 this.el.removeClass(this.invalidClass);
8061 this.fireEvent('valid', this);
8065 * Mark this field as valid
8067 markValid : function(){
8068 if(!this.el || this.preventMark){ // not rendered
8072 this.el.removeClass([this.invalidClass, this.validClass]);
8074 if(this.disabled || this.allowBlank){
8078 this.el.addClass(this.validClass);
8080 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && this.getValue().length){
8082 var feedback = this.el.select('.form-control-feedback', true).first();
8085 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8086 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
8091 this.fireEvent('valid', this);
8095 * Mark this field as invalid
8096 * @param {String} msg The validation message
8098 markInvalid : function(msg){
8099 if(!this.el || this.preventMark){ // not rendered
8103 this.el.removeClass([this.invalidClass, this.validClass]);
8105 if(this.disabled || this.allowBlank){
8109 this.el.addClass(this.invalidClass);
8111 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
8113 var feedback = this.el.select('.form-control-feedback', true).first();
8116 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
8118 if(this.getValue().length){
8119 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
8126 this.fireEvent('invalid', this, msg);
8129 SafariOnKeyDown : function(event)
8131 // this is a workaround for a password hang bug on chrome/ webkit.
8133 var isSelectAll = false;
8135 if(this.inputEl().dom.selectionEnd > 0){
8136 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
8138 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
8139 event.preventDefault();
8144 if(isSelectAll && event.getCharCode() > 31){ // not backspace and delete key
8146 event.preventDefault();
8147 // this is very hacky as keydown always get's upper case.
8149 var cc = String.fromCharCode(event.getCharCode());
8150 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
8154 adjustWidth : function(tag, w){
8155 tag = tag.toLowerCase();
8156 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
8157 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
8161 if(tag == 'textarea'){
8164 }else if(Roo.isOpera){
8168 if(tag == 'textarea'){
8187 * @class Roo.bootstrap.TextArea
8188 * @extends Roo.bootstrap.Input
8189 * Bootstrap TextArea class
8190 * @cfg {Number} cols Specifies the visible width of a text area
8191 * @cfg {Number} rows Specifies the visible number of lines in a text area
8192 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
8193 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
8194 * @cfg {string} html text
8197 * Create a new TextArea
8198 * @param {Object} config The config object
8201 Roo.bootstrap.TextArea = function(config){
8202 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
8206 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
8216 getAutoCreate : function(){
8218 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
8229 value : this.value || '',
8230 html: this.html || '',
8231 cls : 'form-control',
8232 placeholder : this.placeholder || ''
8236 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
8237 input.maxLength = this.maxLength;
8241 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
8245 input.cols = this.cols;
8248 if (this.readOnly) {
8249 input.readonly = true;
8253 input.name = this.name;
8257 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
8261 ['xs','sm','md','lg'].map(function(size){
8262 if (settings[size]) {
8263 cfg.cls += ' col-' + size + '-' + settings[size];
8267 var inputblock = input;
8269 if(this.hasFeedback && !this.allowBlank){
8273 cls: 'glyphicon form-control-feedback'
8277 cls : 'has-feedback',
8286 if (this.before || this.after) {
8289 cls : 'input-group',
8293 inputblock.cn.push({
8295 cls : 'input-group-addon',
8300 inputblock.cn.push(input);
8302 if(this.hasFeedback && !this.allowBlank){
8303 inputblock.cls += ' has-feedback';
8304 inputblock.cn.push(feedback);
8308 inputblock.cn.push({
8310 cls : 'input-group-addon',
8317 if (align ==='left' && this.fieldLabel.length) {
8318 Roo.log("left and has label");
8324 cls : 'control-label col-sm-' + this.labelWidth,
8325 html : this.fieldLabel
8329 cls : "col-sm-" + (12 - this.labelWidth),
8336 } else if ( this.fieldLabel.length) {
8342 //cls : 'input-group-addon',
8343 html : this.fieldLabel
8353 Roo.log(" no label && no align");
8363 if (this.disabled) {
8364 input.disabled=true;
8371 * return the real textarea element.
8373 inputEl: function ()
8375 return this.el.select('textarea.form-control',true).first();
8383 * trigger field - base class for combo..
8388 * @class Roo.bootstrap.TriggerField
8389 * @extends Roo.bootstrap.Input
8390 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
8391 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
8392 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
8393 * for which you can provide a custom implementation. For example:
8395 var trigger = new Roo.bootstrap.TriggerField();
8396 trigger.onTriggerClick = myTriggerFn;
8397 trigger.applyTo('my-field');
8400 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
8401 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
8402 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
8403 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
8404 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
8407 * Create a new TriggerField.
8408 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
8409 * to the base TextField)
8411 Roo.bootstrap.TriggerField = function(config){
8412 this.mimicing = false;
8413 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
8416 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
8418 * @cfg {String} triggerClass A CSS class to apply to the trigger
8421 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
8425 /** @cfg {Boolean} grow @hide */
8426 /** @cfg {Number} growMin @hide */
8427 /** @cfg {Number} growMax @hide */
8433 autoSize: Roo.emptyFn,
8440 actionMode : 'wrap',
8445 getAutoCreate : function(){
8447 var align = this.labelAlign || this.parentLabelAlign();
8452 cls: 'form-group' //input-group
8459 type : this.inputType,
8460 cls : 'form-control',
8461 autocomplete: 'new-password',
8462 placeholder : this.placeholder || ''
8466 input.name = this.name;
8469 input.cls += ' input-' + this.size;
8472 if (this.disabled) {
8473 input.disabled=true;
8476 var inputblock = input;
8478 if(this.hasFeedback && !this.allowBlank){
8482 cls: 'glyphicon form-control-feedback'
8486 cls : 'has-feedback',
8494 if (this.before || this.after) {
8497 cls : 'input-group',
8501 inputblock.cn.push({
8503 cls : 'input-group-addon',
8508 inputblock.cn.push(input);
8510 if(this.hasFeedback && !this.allowBlank){
8511 inputblock.cls += ' has-feedback';
8512 inputblock.cn.push(feedback);
8516 inputblock.cn.push({
8518 cls : 'input-group-addon',
8531 cls: 'form-hidden-field'
8539 Roo.log('multiple');
8547 cls: 'form-hidden-field'
8551 cls: 'select2-choices',
8555 cls: 'select2-search-field',
8568 cls: 'select2-container input-group',
8573 // cls: 'typeahead typeahead-long dropdown-menu',
8574 // style: 'display:none'
8579 if(!this.multiple && this.showToggleBtn){
8585 if (this.caret != false) {
8588 cls: 'fa fa-' + this.caret
8595 cls : 'input-group-addon btn dropdown-toggle',
8600 cls: 'combobox-clear',
8614 combobox.cls += ' select2-container-multi';
8617 if (align ==='left' && this.fieldLabel.length) {
8619 Roo.log("left and has label");
8625 cls : 'control-label col-sm-' + this.labelWidth,
8626 html : this.fieldLabel
8630 cls : "col-sm-" + (12 - this.labelWidth),
8637 } else if ( this.fieldLabel.length) {
8643 //cls : 'input-group-addon',
8644 html : this.fieldLabel
8654 Roo.log(" no label && no align");
8661 ['xs','sm','md','lg'].map(function(size){
8662 if (settings[size]) {
8663 cfg.cls += ' col-' + size + '-' + settings[size];
8674 onResize : function(w, h){
8675 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
8676 // if(typeof w == 'number'){
8677 // var x = w - this.trigger.getWidth();
8678 // this.inputEl().setWidth(this.adjustWidth('input', x));
8679 // this.trigger.setStyle('left', x+'px');
8684 adjustSize : Roo.BoxComponent.prototype.adjustSize,
8687 getResizeEl : function(){
8688 return this.inputEl();
8692 getPositionEl : function(){
8693 return this.inputEl();
8697 alignErrorIcon : function(){
8698 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
8702 initEvents : function(){
8706 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
8707 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
8708 if(!this.multiple && this.showToggleBtn){
8709 this.trigger = this.el.select('span.dropdown-toggle',true).first();
8710 if(this.hideTrigger){
8711 this.trigger.setDisplayed(false);
8713 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
8717 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
8720 //this.trigger.addClassOnOver('x-form-trigger-over');
8721 //this.trigger.addClassOnClick('x-form-trigger-click');
8724 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
8728 createList : function()
8730 this.list = Roo.get(document.body).createChild({
8732 cls: 'typeahead typeahead-long dropdown-menu',
8733 style: 'display:none'
8736 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
8741 initTrigger : function(){
8746 onDestroy : function(){
8748 this.trigger.removeAllListeners();
8749 // this.trigger.remove();
8752 // this.wrap.remove();
8754 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
8758 onFocus : function(){
8759 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
8762 this.wrap.addClass('x-trigger-wrap-focus');
8763 this.mimicing = true;
8764 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
8765 if(this.monitorTab){
8766 this.el.on("keydown", this.checkTab, this);
8773 checkTab : function(e){
8774 if(e.getKey() == e.TAB){
8780 onBlur : function(){
8785 mimicBlur : function(e, t){
8787 if(!this.wrap.contains(t) && this.validateBlur()){
8794 triggerBlur : function(){
8795 this.mimicing = false;
8796 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
8797 if(this.monitorTab){
8798 this.el.un("keydown", this.checkTab, this);
8800 //this.wrap.removeClass('x-trigger-wrap-focus');
8801 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
8805 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
8806 validateBlur : function(e, t){
8811 onDisable : function(){
8812 this.inputEl().dom.disabled = true;
8813 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
8815 // this.wrap.addClass('x-item-disabled');
8820 onEnable : function(){
8821 this.inputEl().dom.disabled = false;
8822 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
8824 // this.el.removeClass('x-item-disabled');
8829 onShow : function(){
8830 var ae = this.getActionEl();
8833 ae.dom.style.display = '';
8834 ae.dom.style.visibility = 'visible';
8840 onHide : function(){
8841 var ae = this.getActionEl();
8842 ae.dom.style.display = 'none';
8846 * The function that should handle the trigger's click event. This method does nothing by default until overridden
8847 * by an implementing function.
8849 * @param {EventObject} e
8851 onTriggerClick : Roo.emptyFn
8855 * Ext JS Library 1.1.1
8856 * Copyright(c) 2006-2007, Ext JS, LLC.
8858 * Originally Released Under LGPL - original licence link has changed is not relivant.
8861 * <script type="text/javascript">
8866 * @class Roo.data.SortTypes
8868 * Defines the default sorting (casting?) comparison functions used when sorting data.
8870 Roo.data.SortTypes = {
8872 * Default sort that does nothing
8873 * @param {Mixed} s The value being converted
8874 * @return {Mixed} The comparison value
8881 * The regular expression used to strip tags
8885 stripTagsRE : /<\/?[^>]+>/gi,
8888 * Strips all HTML tags to sort on text only
8889 * @param {Mixed} s The value being converted
8890 * @return {String} The comparison value
8892 asText : function(s){
8893 return String(s).replace(this.stripTagsRE, "");
8897 * Strips all HTML tags to sort on text only - Case insensitive
8898 * @param {Mixed} s The value being converted
8899 * @return {String} The comparison value
8901 asUCText : function(s){
8902 return String(s).toUpperCase().replace(this.stripTagsRE, "");
8906 * Case insensitive string
8907 * @param {Mixed} s The value being converted
8908 * @return {String} The comparison value
8910 asUCString : function(s) {
8911 return String(s).toUpperCase();
8916 * @param {Mixed} s The value being converted
8917 * @return {Number} The comparison value
8919 asDate : function(s) {
8923 if(s instanceof Date){
8926 return Date.parse(String(s));
8931 * @param {Mixed} s The value being converted
8932 * @return {Float} The comparison value
8934 asFloat : function(s) {
8935 var val = parseFloat(String(s).replace(/,/g, ""));
8936 if(isNaN(val)) val = 0;
8942 * @param {Mixed} s The value being converted
8943 * @return {Number} The comparison value
8945 asInt : function(s) {
8946 var val = parseInt(String(s).replace(/,/g, ""));
8947 if(isNaN(val)) val = 0;
8952 * Ext JS Library 1.1.1
8953 * Copyright(c) 2006-2007, Ext JS, LLC.
8955 * Originally Released Under LGPL - original licence link has changed is not relivant.
8958 * <script type="text/javascript">
8962 * @class Roo.data.Record
8963 * Instances of this class encapsulate both record <em>definition</em> information, and record
8964 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
8965 * to access Records cached in an {@link Roo.data.Store} object.<br>
8967 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
8968 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
8971 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
8973 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
8974 * {@link #create}. The parameters are the same.
8975 * @param {Array} data An associative Array of data values keyed by the field name.
8976 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
8977 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
8978 * not specified an integer id is generated.
8980 Roo.data.Record = function(data, id){
8981 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
8986 * Generate a constructor for a specific record layout.
8987 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
8988 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
8989 * Each field definition object may contain the following properties: <ul>
8990 * <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,
8991 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
8992 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
8993 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
8994 * is being used, then this is a string containing the javascript expression to reference the data relative to
8995 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
8996 * to the data item relative to the record element. If the mapping expression is the same as the field name,
8997 * this may be omitted.</p></li>
8998 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
8999 * <ul><li>auto (Default, implies no conversion)</li>
9004 * <li>date</li></ul></p></li>
9005 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
9006 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
9007 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
9008 * by the Reader into an object that will be stored in the Record. It is passed the
9009 * following parameters:<ul>
9010 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
9012 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
9014 * <br>usage:<br><pre><code>
9015 var TopicRecord = Roo.data.Record.create(
9016 {name: 'title', mapping: 'topic_title'},
9017 {name: 'author', mapping: 'username'},
9018 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
9019 {name: 'lastPost', mapping: 'post_time', type: 'date'},
9020 {name: 'lastPoster', mapping: 'user2'},
9021 {name: 'excerpt', mapping: 'post_text'}
9024 var myNewRecord = new TopicRecord({
9025 title: 'Do my job please',
9028 lastPost: new Date(),
9029 lastPoster: 'Animal',
9030 excerpt: 'No way dude!'
9032 myStore.add(myNewRecord);
9037 Roo.data.Record.create = function(o){
9039 f.superclass.constructor.apply(this, arguments);
9041 Roo.extend(f, Roo.data.Record);
9042 var p = f.prototype;
9043 p.fields = new Roo.util.MixedCollection(false, function(field){
9046 for(var i = 0, len = o.length; i < len; i++){
9047 p.fields.add(new Roo.data.Field(o[i]));
9049 f.getField = function(name){
9050 return p.fields.get(name);
9055 Roo.data.Record.AUTO_ID = 1000;
9056 Roo.data.Record.EDIT = 'edit';
9057 Roo.data.Record.REJECT = 'reject';
9058 Roo.data.Record.COMMIT = 'commit';
9060 Roo.data.Record.prototype = {
9062 * Readonly flag - true if this record has been modified.
9071 join : function(store){
9076 * Set the named field to the specified value.
9077 * @param {String} name The name of the field to set.
9078 * @param {Object} value The value to set the field to.
9080 set : function(name, value){
9081 if(this.data[name] == value){
9088 if(typeof this.modified[name] == 'undefined'){
9089 this.modified[name] = this.data[name];
9091 this.data[name] = value;
9092 if(!this.editing && this.store){
9093 this.store.afterEdit(this);
9098 * Get the value of the named field.
9099 * @param {String} name The name of the field to get the value of.
9100 * @return {Object} The value of the field.
9102 get : function(name){
9103 return this.data[name];
9107 beginEdit : function(){
9108 this.editing = true;
9113 cancelEdit : function(){
9114 this.editing = false;
9115 delete this.modified;
9119 endEdit : function(){
9120 this.editing = false;
9121 if(this.dirty && this.store){
9122 this.store.afterEdit(this);
9127 * Usually called by the {@link Roo.data.Store} which owns the Record.
9128 * Rejects all changes made to the Record since either creation, or the last commit operation.
9129 * Modified fields are reverted to their original values.
9131 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9132 * of reject operations.
9134 reject : function(){
9135 var m = this.modified;
9137 if(typeof m[n] != "function"){
9138 this.data[n] = m[n];
9142 delete this.modified;
9143 this.editing = false;
9145 this.store.afterReject(this);
9150 * Usually called by the {@link Roo.data.Store} which owns the Record.
9151 * Commits all changes made to the Record since either creation, or the last commit operation.
9153 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
9154 * of commit operations.
9156 commit : function(){
9158 delete this.modified;
9159 this.editing = false;
9161 this.store.afterCommit(this);
9166 hasError : function(){
9167 return this.error != null;
9171 clearError : function(){
9176 * Creates a copy of this record.
9177 * @param {String} id (optional) A new record id if you don't want to use this record's id
9180 copy : function(newId) {
9181 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
9185 * Ext JS Library 1.1.1
9186 * Copyright(c) 2006-2007, Ext JS, LLC.
9188 * Originally Released Under LGPL - original licence link has changed is not relivant.
9191 * <script type="text/javascript">
9197 * @class Roo.data.Store
9198 * @extends Roo.util.Observable
9199 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
9200 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
9202 * 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
9203 * has no knowledge of the format of the data returned by the Proxy.<br>
9205 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
9206 * instances from the data object. These records are cached and made available through accessor functions.
9208 * Creates a new Store.
9209 * @param {Object} config A config object containing the objects needed for the Store to access data,
9210 * and read the data into Records.
9212 Roo.data.Store = function(config){
9213 this.data = new Roo.util.MixedCollection(false);
9214 this.data.getKey = function(o){
9217 this.baseParams = {};
9224 "multisort" : "_multisort"
9227 if(config && config.data){
9228 this.inlineData = config.data;
9232 Roo.apply(this, config);
9234 if(this.reader){ // reader passed
9235 this.reader = Roo.factory(this.reader, Roo.data);
9236 this.reader.xmodule = this.xmodule || false;
9237 if(!this.recordType){
9238 this.recordType = this.reader.recordType;
9240 if(this.reader.onMetaChange){
9241 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
9245 if(this.recordType){
9246 this.fields = this.recordType.prototype.fields;
9252 * @event datachanged
9253 * Fires when the data cache has changed, and a widget which is using this Store
9254 * as a Record cache should refresh its view.
9255 * @param {Store} this
9260 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
9261 * @param {Store} this
9262 * @param {Object} meta The JSON metadata
9267 * Fires when Records have been added to the Store
9268 * @param {Store} this
9269 * @param {Roo.data.Record[]} records The array of Records added
9270 * @param {Number} index The index at which the record(s) were added
9275 * Fires when a Record has been removed from the Store
9276 * @param {Store} this
9277 * @param {Roo.data.Record} record The Record that was removed
9278 * @param {Number} index The index at which the record was removed
9283 * Fires when a Record has been updated
9284 * @param {Store} this
9285 * @param {Roo.data.Record} record The Record that was updated
9286 * @param {String} operation The update operation being performed. Value may be one of:
9288 Roo.data.Record.EDIT
9289 Roo.data.Record.REJECT
9290 Roo.data.Record.COMMIT
9296 * Fires when the data cache has been cleared.
9297 * @param {Store} this
9302 * Fires before a request is made for a new data object. If the beforeload handler returns false
9303 * the load action will be canceled.
9304 * @param {Store} this
9305 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9309 * @event beforeloadadd
9310 * Fires after a new set of Records has been loaded.
9311 * @param {Store} this
9312 * @param {Roo.data.Record[]} records The Records that were loaded
9313 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9315 beforeloadadd : true,
9318 * Fires after a new set of Records has been loaded, before they are added to the store.
9319 * @param {Store} this
9320 * @param {Roo.data.Record[]} records The Records that were loaded
9321 * @param {Object} options The loading options that were specified (see {@link #load} for details)
9322 * @params {Object} return from reader
9326 * @event loadexception
9327 * Fires if an exception occurs in the Proxy during loading.
9328 * Called with the signature of the Proxy's "loadexception" event.
9329 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
9332 * @param {Object} return from JsonData.reader() - success, totalRecords, records
9333 * @param {Object} load options
9334 * @param {Object} jsonData from your request (normally this contains the Exception)
9336 loadexception : true
9340 this.proxy = Roo.factory(this.proxy, Roo.data);
9341 this.proxy.xmodule = this.xmodule || false;
9342 this.relayEvents(this.proxy, ["loadexception"]);
9344 this.sortToggle = {};
9345 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
9347 Roo.data.Store.superclass.constructor.call(this);
9349 if(this.inlineData){
9350 this.loadData(this.inlineData);
9351 delete this.inlineData;
9355 Roo.extend(Roo.data.Store, Roo.util.Observable, {
9357 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
9358 * without a remote query - used by combo/forms at present.
9362 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
9365 * @cfg {Array} data Inline data to be loaded when the store is initialized.
9368 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
9369 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
9372 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
9373 * on any HTTP request
9376 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
9379 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
9383 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
9384 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
9389 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
9390 * loaded or when a record is removed. (defaults to false).
9392 pruneModifiedRecords : false,
9398 * Add Records to the Store and fires the add event.
9399 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9401 add : function(records){
9402 records = [].concat(records);
9403 for(var i = 0, len = records.length; i < len; i++){
9404 records[i].join(this);
9406 var index = this.data.length;
9407 this.data.addAll(records);
9408 this.fireEvent("add", this, records, index);
9412 * Remove a Record from the Store and fires the remove event.
9413 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
9415 remove : function(record){
9416 var index = this.data.indexOf(record);
9417 this.data.removeAt(index);
9418 if(this.pruneModifiedRecords){
9419 this.modified.remove(record);
9421 this.fireEvent("remove", this, record, index);
9425 * Remove all Records from the Store and fires the clear event.
9427 removeAll : function(){
9429 if(this.pruneModifiedRecords){
9432 this.fireEvent("clear", this);
9436 * Inserts Records to the Store at the given index and fires the add event.
9437 * @param {Number} index The start index at which to insert the passed Records.
9438 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
9440 insert : function(index, records){
9441 records = [].concat(records);
9442 for(var i = 0, len = records.length; i < len; i++){
9443 this.data.insert(index, records[i]);
9444 records[i].join(this);
9446 this.fireEvent("add", this, records, index);
9450 * Get the index within the cache of the passed Record.
9451 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
9452 * @return {Number} The index of the passed Record. Returns -1 if not found.
9454 indexOf : function(record){
9455 return this.data.indexOf(record);
9459 * Get the index within the cache of the Record with the passed id.
9460 * @param {String} id The id of the Record to find.
9461 * @return {Number} The index of the Record. Returns -1 if not found.
9463 indexOfId : function(id){
9464 return this.data.indexOfKey(id);
9468 * Get the Record with the specified id.
9469 * @param {String} id The id of the Record to find.
9470 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
9472 getById : function(id){
9473 return this.data.key(id);
9477 * Get the Record at the specified index.
9478 * @param {Number} index The index of the Record to find.
9479 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
9481 getAt : function(index){
9482 return this.data.itemAt(index);
9486 * Returns a range of Records between specified indices.
9487 * @param {Number} startIndex (optional) The starting index (defaults to 0)
9488 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
9489 * @return {Roo.data.Record[]} An array of Records
9491 getRange : function(start, end){
9492 return this.data.getRange(start, end);
9496 storeOptions : function(o){
9497 o = Roo.apply({}, o);
9500 this.lastOptions = o;
9504 * Loads the Record cache from the configured Proxy using the configured Reader.
9506 * If using remote paging, then the first load call must specify the <em>start</em>
9507 * and <em>limit</em> properties in the options.params property to establish the initial
9508 * position within the dataset, and the number of Records to cache on each read from the Proxy.
9510 * <strong>It is important to note that for remote data sources, loading is asynchronous,
9511 * and this call will return before the new data has been loaded. Perform any post-processing
9512 * in a callback function, or in a "load" event handler.</strong>
9514 * @param {Object} options An object containing properties which control loading options:<ul>
9515 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
9516 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
9517 * passed the following arguments:<ul>
9518 * <li>r : Roo.data.Record[]</li>
9519 * <li>options: Options object from the load call</li>
9520 * <li>success: Boolean success indicator</li></ul></li>
9521 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
9522 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
9525 load : function(options){
9526 options = options || {};
9527 if(this.fireEvent("beforeload", this, options) !== false){
9528 this.storeOptions(options);
9529 var p = Roo.apply(options.params || {}, this.baseParams);
9530 // if meta was not loaded from remote source.. try requesting it.
9531 if (!this.reader.metaFromRemote) {
9534 if(this.sortInfo && this.remoteSort){
9535 var pn = this.paramNames;
9536 p[pn["sort"]] = this.sortInfo.field;
9537 p[pn["dir"]] = this.sortInfo.direction;
9539 if (this.multiSort) {
9540 var pn = this.paramNames;
9541 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
9544 this.proxy.load(p, this.reader, this.loadRecords, this, options);
9549 * Reloads the Record cache from the configured Proxy using the configured Reader and
9550 * the options from the last load operation performed.
9551 * @param {Object} options (optional) An object containing properties which may override the options
9552 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
9553 * the most recently used options are reused).
9555 reload : function(options){
9556 this.load(Roo.applyIf(options||{}, this.lastOptions));
9560 // Called as a callback by the Reader during a load operation.
9561 loadRecords : function(o, options, success){
9562 if(!o || success === false){
9563 if(success !== false){
9564 this.fireEvent("load", this, [], options, o);
9566 if(options.callback){
9567 options.callback.call(options.scope || this, [], options, false);
9571 // if data returned failure - throw an exception.
9572 if (o.success === false) {
9573 // show a message if no listener is registered.
9574 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
9575 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
9577 // loadmask wil be hooked into this..
9578 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
9581 var r = o.records, t = o.totalRecords || r.length;
9583 this.fireEvent("beforeloadadd", this, r, options, o);
9585 if(!options || options.add !== true){
9586 if(this.pruneModifiedRecords){
9589 for(var i = 0, len = r.length; i < len; i++){
9593 this.data = this.snapshot;
9594 delete this.snapshot;
9597 this.data.addAll(r);
9598 this.totalLength = t;
9600 this.fireEvent("datachanged", this);
9602 this.totalLength = Math.max(t, this.data.length+r.length);
9605 this.fireEvent("load", this, r, options, o);
9606 if(options.callback){
9607 options.callback.call(options.scope || this, r, options, true);
9613 * Loads data from a passed data block. A Reader which understands the format of the data
9614 * must have been configured in the constructor.
9615 * @param {Object} data The data block from which to read the Records. The format of the data expected
9616 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
9617 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
9619 loadData : function(o, append){
9620 var r = this.reader.readRecords(o);
9621 this.loadRecords(r, {add: append}, true);
9625 * Gets the number of cached records.
9627 * <em>If using paging, this may not be the total size of the dataset. If the data object
9628 * used by the Reader contains the dataset size, then the getTotalCount() function returns
9629 * the data set size</em>
9631 getCount : function(){
9632 return this.data.length || 0;
9636 * Gets the total number of records in the dataset as returned by the server.
9638 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
9639 * the dataset size</em>
9641 getTotalCount : function(){
9642 return this.totalLength || 0;
9646 * Returns the sort state of the Store as an object with two properties:
9648 field {String} The name of the field by which the Records are sorted
9649 direction {String} The sort order, "ASC" or "DESC"
9652 getSortState : function(){
9653 return this.sortInfo;
9657 applySort : function(){
9658 if(this.sortInfo && !this.remoteSort){
9659 var s = this.sortInfo, f = s.field;
9660 var st = this.fields.get(f).sortType;
9661 var fn = function(r1, r2){
9662 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
9663 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
9665 this.data.sort(s.direction, fn);
9666 if(this.snapshot && this.snapshot != this.data){
9667 this.snapshot.sort(s.direction, fn);
9673 * Sets the default sort column and order to be used by the next load operation.
9674 * @param {String} fieldName The name of the field to sort by.
9675 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9677 setDefaultSort : function(field, dir){
9678 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
9683 * If remote sorting is used, the sort is performed on the server, and the cache is
9684 * reloaded. If local sorting is used, the cache is sorted internally.
9685 * @param {String} fieldName The name of the field to sort by.
9686 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
9688 sort : function(fieldName, dir){
9689 var f = this.fields.get(fieldName);
9691 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
9693 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
9694 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
9699 this.sortToggle[f.name] = dir;
9700 this.sortInfo = {field: f.name, direction: dir};
9701 if(!this.remoteSort){
9703 this.fireEvent("datachanged", this);
9705 this.load(this.lastOptions);
9710 * Calls the specified function for each of the Records in the cache.
9711 * @param {Function} fn The function to call. The Record is passed as the first parameter.
9712 * Returning <em>false</em> aborts and exits the iteration.
9713 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
9715 each : function(fn, scope){
9716 this.data.each(fn, scope);
9720 * Gets all records modified since the last commit. Modified records are persisted across load operations
9721 * (e.g., during paging).
9722 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
9724 getModifiedRecords : function(){
9725 return this.modified;
9729 createFilterFn : function(property, value, anyMatch){
9730 if(!value.exec){ // not a regex
9731 value = String(value);
9732 if(value.length == 0){
9735 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
9738 return value.test(r.data[property]);
9743 * Sums the value of <i>property</i> for each record between start and end and returns the result.
9744 * @param {String} property A field on your records
9745 * @param {Number} start The record index to start at (defaults to 0)
9746 * @param {Number} end The last record index to include (defaults to length - 1)
9747 * @return {Number} The sum
9749 sum : function(property, start, end){
9750 var rs = this.data.items, v = 0;
9752 end = (end || end === 0) ? end : rs.length-1;
9754 for(var i = start; i <= end; i++){
9755 v += (rs[i].data[property] || 0);
9761 * Filter the records by a specified property.
9762 * @param {String} field A field on your records
9763 * @param {String/RegExp} value Either a string that the field
9764 * should start with or a RegExp to test against the field
9765 * @param {Boolean} anyMatch True to match any part not just the beginning
9767 filter : function(property, value, anyMatch){
9768 var fn = this.createFilterFn(property, value, anyMatch);
9769 return fn ? this.filterBy(fn) : this.clearFilter();
9773 * Filter by a function. The specified function will be called with each
9774 * record in this data source. If the function returns true the record is included,
9775 * otherwise it is filtered.
9776 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9777 * @param {Object} scope (optional) The scope of the function (defaults to this)
9779 filterBy : function(fn, scope){
9780 this.snapshot = this.snapshot || this.data;
9781 this.data = this.queryBy(fn, scope||this);
9782 this.fireEvent("datachanged", this);
9786 * Query the records by a specified property.
9787 * @param {String} field A field on your records
9788 * @param {String/RegExp} value Either a string that the field
9789 * should start with or a RegExp to test against the field
9790 * @param {Boolean} anyMatch True to match any part not just the beginning
9791 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9793 query : function(property, value, anyMatch){
9794 var fn = this.createFilterFn(property, value, anyMatch);
9795 return fn ? this.queryBy(fn) : this.data.clone();
9799 * Query by a function. The specified function will be called with each
9800 * record in this data source. If the function returns true the record is included
9802 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
9803 * @param {Object} scope (optional) The scope of the function (defaults to this)
9804 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
9806 queryBy : function(fn, scope){
9807 var data = this.snapshot || this.data;
9808 return data.filterBy(fn, scope||this);
9812 * Collects unique values for a particular dataIndex from this store.
9813 * @param {String} dataIndex The property to collect
9814 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
9815 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
9816 * @return {Array} An array of the unique values
9818 collect : function(dataIndex, allowNull, bypassFilter){
9819 var d = (bypassFilter === true && this.snapshot) ?
9820 this.snapshot.items : this.data.items;
9821 var v, sv, r = [], l = {};
9822 for(var i = 0, len = d.length; i < len; i++){
9823 v = d[i].data[dataIndex];
9825 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
9834 * Revert to a view of the Record cache with no filtering applied.
9835 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
9837 clearFilter : function(suppressEvent){
9838 if(this.snapshot && this.snapshot != this.data){
9839 this.data = this.snapshot;
9840 delete this.snapshot;
9841 if(suppressEvent !== true){
9842 this.fireEvent("datachanged", this);
9848 afterEdit : function(record){
9849 if(this.modified.indexOf(record) == -1){
9850 this.modified.push(record);
9852 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
9856 afterReject : function(record){
9857 this.modified.remove(record);
9858 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
9862 afterCommit : function(record){
9863 this.modified.remove(record);
9864 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
9868 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
9869 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
9871 commitChanges : function(){
9872 var m = this.modified.slice(0);
9874 for(var i = 0, len = m.length; i < len; i++){
9880 * Cancel outstanding changes on all changed records.
9882 rejectChanges : function(){
9883 var m = this.modified.slice(0);
9885 for(var i = 0, len = m.length; i < len; i++){
9890 onMetaChange : function(meta, rtype, o){
9891 this.recordType = rtype;
9892 this.fields = rtype.prototype.fields;
9893 delete this.snapshot;
9894 this.sortInfo = meta.sortInfo || this.sortInfo;
9896 this.fireEvent('metachange', this, this.reader.meta);
9899 moveIndex : function(data, type)
9901 var index = this.indexOf(data);
9903 var newIndex = index + type;
9907 this.insert(newIndex, data);
9912 * Ext JS Library 1.1.1
9913 * Copyright(c) 2006-2007, Ext JS, LLC.
9915 * Originally Released Under LGPL - original licence link has changed is not relivant.
9918 * <script type="text/javascript">
9922 * @class Roo.data.SimpleStore
9923 * @extends Roo.data.Store
9924 * Small helper class to make creating Stores from Array data easier.
9925 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
9926 * @cfg {Array} fields An array of field definition objects, or field name strings.
9927 * @cfg {Array} data The multi-dimensional array of data
9929 * @param {Object} config
9931 Roo.data.SimpleStore = function(config){
9932 Roo.data.SimpleStore.superclass.constructor.call(this, {
9934 reader: new Roo.data.ArrayReader({
9937 Roo.data.Record.create(config.fields)
9939 proxy : new Roo.data.MemoryProxy(config.data)
9943 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
9945 * Ext JS Library 1.1.1
9946 * Copyright(c) 2006-2007, Ext JS, LLC.
9948 * Originally Released Under LGPL - original licence link has changed is not relivant.
9951 * <script type="text/javascript">
9956 * @extends Roo.data.Store
9957 * @class Roo.data.JsonStore
9958 * Small helper class to make creating Stores for JSON data easier. <br/>
9960 var store = new Roo.data.JsonStore({
9961 url: 'get-images.php',
9963 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
9966 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
9967 * JsonReader and HttpProxy (unless inline data is provided).</b>
9968 * @cfg {Array} fields An array of field definition objects, or field name strings.
9970 * @param {Object} config
9972 Roo.data.JsonStore = function(c){
9973 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
9974 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
9975 reader: new Roo.data.JsonReader(c, c.fields)
9978 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
9980 * Ext JS Library 1.1.1
9981 * Copyright(c) 2006-2007, Ext JS, LLC.
9983 * Originally Released Under LGPL - original licence link has changed is not relivant.
9986 * <script type="text/javascript">
9990 Roo.data.Field = function(config){
9991 if(typeof config == "string"){
9992 config = {name: config};
9994 Roo.apply(this, config);
10000 var st = Roo.data.SortTypes;
10001 // named sortTypes are supported, here we look them up
10002 if(typeof this.sortType == "string"){
10003 this.sortType = st[this.sortType];
10006 // set default sortType for strings and dates
10007 if(!this.sortType){
10010 this.sortType = st.asUCString;
10013 this.sortType = st.asDate;
10016 this.sortType = st.none;
10021 var stripRe = /[\$,%]/g;
10023 // prebuilt conversion function for this field, instead of
10024 // switching every time we're reading a value
10026 var cv, dateFormat = this.dateFormat;
10031 cv = function(v){ return v; };
10034 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
10038 return v !== undefined && v !== null && v !== '' ?
10039 parseInt(String(v).replace(stripRe, ""), 10) : '';
10044 return v !== undefined && v !== null && v !== '' ?
10045 parseFloat(String(v).replace(stripRe, ""), 10) : '';
10050 cv = function(v){ return v === true || v === "true" || v == 1; };
10057 if(v instanceof Date){
10061 if(dateFormat == "timestamp"){
10062 return new Date(v*1000);
10064 return Date.parseDate(v, dateFormat);
10066 var parsed = Date.parse(v);
10067 return parsed ? new Date(parsed) : null;
10076 Roo.data.Field.prototype = {
10084 * Ext JS Library 1.1.1
10085 * Copyright(c) 2006-2007, Ext JS, LLC.
10087 * Originally Released Under LGPL - original licence link has changed is not relivant.
10090 * <script type="text/javascript">
10093 // Base class for reading structured data from a data source. This class is intended to be
10094 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
10097 * @class Roo.data.DataReader
10098 * Base class for reading structured data from a data source. This class is intended to be
10099 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
10102 Roo.data.DataReader = function(meta, recordType){
10106 this.recordType = recordType instanceof Array ?
10107 Roo.data.Record.create(recordType) : recordType;
10110 Roo.data.DataReader.prototype = {
10112 * Create an empty record
10113 * @param {Object} data (optional) - overlay some values
10114 * @return {Roo.data.Record} record created.
10116 newRow : function(d) {
10118 this.recordType.prototype.fields.each(function(c) {
10120 case 'int' : da[c.name] = 0; break;
10121 case 'date' : da[c.name] = new Date(); break;
10122 case 'float' : da[c.name] = 0.0; break;
10123 case 'boolean' : da[c.name] = false; break;
10124 default : da[c.name] = ""; break;
10128 return new this.recordType(Roo.apply(da, d));
10133 * Ext JS Library 1.1.1
10134 * Copyright(c) 2006-2007, Ext JS, LLC.
10136 * Originally Released Under LGPL - original licence link has changed is not relivant.
10139 * <script type="text/javascript">
10143 * @class Roo.data.DataProxy
10144 * @extends Roo.data.Observable
10145 * This class is an abstract base class for implementations which provide retrieval of
10146 * unformatted data objects.<br>
10148 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
10149 * (of the appropriate type which knows how to parse the data object) to provide a block of
10150 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
10152 * Custom implementations must implement the load method as described in
10153 * {@link Roo.data.HttpProxy#load}.
10155 Roo.data.DataProxy = function(){
10158 * @event beforeload
10159 * Fires before a network request is made to retrieve a data object.
10160 * @param {Object} This DataProxy object.
10161 * @param {Object} params The params parameter to the load function.
10166 * Fires before the load method's callback is called.
10167 * @param {Object} This DataProxy object.
10168 * @param {Object} o The data object.
10169 * @param {Object} arg The callback argument object passed to the load function.
10173 * @event loadexception
10174 * Fires if an Exception occurs during data retrieval.
10175 * @param {Object} This DataProxy object.
10176 * @param {Object} o The data object.
10177 * @param {Object} arg The callback argument object passed to the load function.
10178 * @param {Object} e The Exception.
10180 loadexception : true
10182 Roo.data.DataProxy.superclass.constructor.call(this);
10185 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
10188 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
10192 * Ext JS Library 1.1.1
10193 * Copyright(c) 2006-2007, Ext JS, LLC.
10195 * Originally Released Under LGPL - original licence link has changed is not relivant.
10198 * <script type="text/javascript">
10201 * @class Roo.data.MemoryProxy
10202 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
10203 * to the Reader when its load method is called.
10205 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
10207 Roo.data.MemoryProxy = function(data){
10211 Roo.data.MemoryProxy.superclass.constructor.call(this);
10215 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
10217 * Load data from the requested source (in this case an in-memory
10218 * data object passed to the constructor), read the data object into
10219 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10220 * process that block using the passed callback.
10221 * @param {Object} params This parameter is not used by the MemoryProxy class.
10222 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10223 * object into a block of Roo.data.Records.
10224 * @param {Function} callback The function into which to pass the block of Roo.data.records.
10225 * The function must be passed <ul>
10226 * <li>The Record block object</li>
10227 * <li>The "arg" argument from the load function</li>
10228 * <li>A boolean success indicator</li>
10230 * @param {Object} scope The scope in which to call the callback
10231 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10233 load : function(params, reader, callback, scope, arg){
10234 params = params || {};
10237 result = reader.readRecords(this.data);
10239 this.fireEvent("loadexception", this, arg, null, e);
10240 callback.call(scope, null, arg, false);
10243 callback.call(scope, result, arg, true);
10247 update : function(params, records){
10252 * Ext JS Library 1.1.1
10253 * Copyright(c) 2006-2007, Ext JS, LLC.
10255 * Originally Released Under LGPL - original licence link has changed is not relivant.
10258 * <script type="text/javascript">
10261 * @class Roo.data.HttpProxy
10262 * @extends Roo.data.DataProxy
10263 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
10264 * configured to reference a certain URL.<br><br>
10266 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
10267 * from which the running page was served.<br><br>
10269 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
10271 * Be aware that to enable the browser to parse an XML document, the server must set
10272 * the Content-Type header in the HTTP response to "text/xml".
10274 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
10275 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
10276 * will be used to make the request.
10278 Roo.data.HttpProxy = function(conn){
10279 Roo.data.HttpProxy.superclass.constructor.call(this);
10280 // is conn a conn config or a real conn?
10282 this.useAjax = !conn || !conn.events;
10286 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
10287 // thse are take from connection...
10290 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
10293 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
10294 * extra parameters to each request made by this object. (defaults to undefined)
10297 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
10298 * to each request made by this object. (defaults to undefined)
10301 * @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)
10304 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
10307 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
10313 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
10317 * Return the {@link Roo.data.Connection} object being used by this Proxy.
10318 * @return {Connection} The Connection object. This object may be used to subscribe to events on
10319 * a finer-grained basis than the DataProxy events.
10321 getConnection : function(){
10322 return this.useAjax ? Roo.Ajax : this.conn;
10326 * Load data from the configured {@link Roo.data.Connection}, read the data object into
10327 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
10328 * process that block using the passed callback.
10329 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10330 * for the request to the remote server.
10331 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10332 * object into a block of Roo.data.Records.
10333 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10334 * The function must be passed <ul>
10335 * <li>The Record block object</li>
10336 * <li>The "arg" argument from the load function</li>
10337 * <li>A boolean success indicator</li>
10339 * @param {Object} scope The scope in which to call the callback
10340 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10342 load : function(params, reader, callback, scope, arg){
10343 if(this.fireEvent("beforeload", this, params) !== false){
10345 params : params || {},
10347 callback : callback,
10352 callback : this.loadResponse,
10356 Roo.applyIf(o, this.conn);
10357 if(this.activeRequest){
10358 Roo.Ajax.abort(this.activeRequest);
10360 this.activeRequest = Roo.Ajax.request(o);
10362 this.conn.request(o);
10365 callback.call(scope||this, null, arg, false);
10370 loadResponse : function(o, success, response){
10371 delete this.activeRequest;
10373 this.fireEvent("loadexception", this, o, response);
10374 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10379 result = o.reader.read(response);
10381 this.fireEvent("loadexception", this, o, response, e);
10382 o.request.callback.call(o.request.scope, null, o.request.arg, false);
10386 this.fireEvent("load", this, o, o.request.arg);
10387 o.request.callback.call(o.request.scope, result, o.request.arg, true);
10391 update : function(dataSet){
10396 updateResponse : function(dataSet){
10401 * Ext JS Library 1.1.1
10402 * Copyright(c) 2006-2007, Ext JS, LLC.
10404 * Originally Released Under LGPL - original licence link has changed is not relivant.
10407 * <script type="text/javascript">
10411 * @class Roo.data.ScriptTagProxy
10412 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
10413 * other than the originating domain of the running page.<br><br>
10415 * <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
10416 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
10418 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
10419 * source code that is used as the source inside a <script> tag.<br><br>
10421 * In order for the browser to process the returned data, the server must wrap the data object
10422 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
10423 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
10424 * depending on whether the callback name was passed:
10427 boolean scriptTag = false;
10428 String cb = request.getParameter("callback");
10431 response.setContentType("text/javascript");
10433 response.setContentType("application/x-json");
10435 Writer out = response.getWriter();
10437 out.write(cb + "(");
10439 out.print(dataBlock.toJsonString());
10446 * @param {Object} config A configuration object.
10448 Roo.data.ScriptTagProxy = function(config){
10449 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
10450 Roo.apply(this, config);
10451 this.head = document.getElementsByTagName("head")[0];
10454 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
10456 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
10458 * @cfg {String} url The URL from which to request the data object.
10461 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
10465 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
10466 * the server the name of the callback function set up by the load call to process the returned data object.
10467 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
10468 * javascript output which calls this named function passing the data object as its only parameter.
10470 callbackParam : "callback",
10472 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
10473 * name to the request.
10478 * Load data from the configured URL, read the data object into
10479 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
10480 * process that block using the passed callback.
10481 * @param {Object} params An object containing properties which are to be used as HTTP parameters
10482 * for the request to the remote server.
10483 * @param {Roo.data.DataReader} reader The Reader object which converts the data
10484 * object into a block of Roo.data.Records.
10485 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
10486 * The function must be passed <ul>
10487 * <li>The Record block object</li>
10488 * <li>The "arg" argument from the load function</li>
10489 * <li>A boolean success indicator</li>
10491 * @param {Object} scope The scope in which to call the callback
10492 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
10494 load : function(params, reader, callback, scope, arg){
10495 if(this.fireEvent("beforeload", this, params) !== false){
10497 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
10499 var url = this.url;
10500 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
10502 url += "&_dc=" + (new Date().getTime());
10504 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
10507 cb : "stcCallback"+transId,
10508 scriptId : "stcScript"+transId,
10512 callback : callback,
10518 window[trans.cb] = function(o){
10519 conn.handleResponse(o, trans);
10522 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
10524 if(this.autoAbort !== false){
10528 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
10530 var script = document.createElement("script");
10531 script.setAttribute("src", url);
10532 script.setAttribute("type", "text/javascript");
10533 script.setAttribute("id", trans.scriptId);
10534 this.head.appendChild(script);
10536 this.trans = trans;
10538 callback.call(scope||this, null, arg, false);
10543 isLoading : function(){
10544 return this.trans ? true : false;
10548 * Abort the current server request.
10550 abort : function(){
10551 if(this.isLoading()){
10552 this.destroyTrans(this.trans);
10557 destroyTrans : function(trans, isLoaded){
10558 this.head.removeChild(document.getElementById(trans.scriptId));
10559 clearTimeout(trans.timeoutId);
10561 window[trans.cb] = undefined;
10563 delete window[trans.cb];
10566 // if hasn't been loaded, wait for load to remove it to prevent script error
10567 window[trans.cb] = function(){
10568 window[trans.cb] = undefined;
10570 delete window[trans.cb];
10577 handleResponse : function(o, trans){
10578 this.trans = false;
10579 this.destroyTrans(trans, true);
10582 result = trans.reader.readRecords(o);
10584 this.fireEvent("loadexception", this, o, trans.arg, e);
10585 trans.callback.call(trans.scope||window, null, trans.arg, false);
10588 this.fireEvent("load", this, o, trans.arg);
10589 trans.callback.call(trans.scope||window, result, trans.arg, true);
10593 handleFailure : function(trans){
10594 this.trans = false;
10595 this.destroyTrans(trans, false);
10596 this.fireEvent("loadexception", this, null, trans.arg);
10597 trans.callback.call(trans.scope||window, null, trans.arg, false);
10601 * Ext JS Library 1.1.1
10602 * Copyright(c) 2006-2007, Ext JS, LLC.
10604 * Originally Released Under LGPL - original licence link has changed is not relivant.
10607 * <script type="text/javascript">
10611 * @class Roo.data.JsonReader
10612 * @extends Roo.data.DataReader
10613 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
10614 * based on mappings in a provided Roo.data.Record constructor.
10616 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
10617 * in the reply previously.
10622 var RecordDef = Roo.data.Record.create([
10623 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
10624 {name: 'occupation'} // This field will use "occupation" as the mapping.
10626 var myReader = new Roo.data.JsonReader({
10627 totalProperty: "results", // The property which contains the total dataset size (optional)
10628 root: "rows", // The property which contains an Array of row objects
10629 id: "id" // The property within each row object that provides an ID for the record (optional)
10633 * This would consume a JSON file like this:
10635 { 'results': 2, 'rows': [
10636 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
10637 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
10640 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
10641 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
10642 * paged from the remote server.
10643 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
10644 * @cfg {String} root name of the property which contains the Array of row objects.
10645 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
10647 * Create a new JsonReader
10648 * @param {Object} meta Metadata configuration options
10649 * @param {Object} recordType Either an Array of field definition objects,
10650 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
10652 Roo.data.JsonReader = function(meta, recordType){
10655 // set some defaults:
10656 Roo.applyIf(meta, {
10657 totalProperty: 'total',
10658 successProperty : 'success',
10663 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
10665 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
10668 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
10669 * Used by Store query builder to append _requestMeta to params.
10672 metaFromRemote : false,
10674 * This method is only used by a DataProxy which has retrieved data from a remote server.
10675 * @param {Object} response The XHR object which contains the JSON data in its responseText.
10676 * @return {Object} data A data block which is used by an Roo.data.Store object as
10677 * a cache of Roo.data.Records.
10679 read : function(response){
10680 var json = response.responseText;
10682 var o = /* eval:var:o */ eval("("+json+")");
10684 throw {message: "JsonReader.read: Json object not found"};
10690 this.metaFromRemote = true;
10691 this.meta = o.metaData;
10692 this.recordType = Roo.data.Record.create(o.metaData.fields);
10693 this.onMetaChange(this.meta, this.recordType, o);
10695 return this.readRecords(o);
10698 // private function a store will implement
10699 onMetaChange : function(meta, recordType, o){
10706 simpleAccess: function(obj, subsc) {
10713 getJsonAccessor: function(){
10715 return function(expr) {
10717 return(re.test(expr))
10718 ? new Function("obj", "return obj." + expr)
10723 return Roo.emptyFn;
10728 * Create a data block containing Roo.data.Records from an XML document.
10729 * @param {Object} o An object which contains an Array of row objects in the property specified
10730 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
10731 * which contains the total size of the dataset.
10732 * @return {Object} data A data block which is used by an Roo.data.Store object as
10733 * a cache of Roo.data.Records.
10735 readRecords : function(o){
10737 * After any data loads, the raw JSON data is available for further custom processing.
10741 var s = this.meta, Record = this.recordType,
10742 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
10744 // Generate extraction functions for the totalProperty, the root, the id, and for each field
10746 if(s.totalProperty) {
10747 this.getTotal = this.getJsonAccessor(s.totalProperty);
10749 if(s.successProperty) {
10750 this.getSuccess = this.getJsonAccessor(s.successProperty);
10752 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
10754 var g = this.getJsonAccessor(s.id);
10755 this.getId = function(rec) {
10757 return (r === undefined || r === "") ? null : r;
10760 this.getId = function(){return null;};
10763 for(var jj = 0; jj < fl; jj++){
10765 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
10766 this.ef[jj] = this.getJsonAccessor(map);
10770 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
10771 if(s.totalProperty){
10772 var vt = parseInt(this.getTotal(o), 10);
10777 if(s.successProperty){
10778 var vs = this.getSuccess(o);
10779 if(vs === false || vs === 'false'){
10784 for(var i = 0; i < c; i++){
10787 var id = this.getId(n);
10788 for(var j = 0; j < fl; j++){
10790 var v = this.ef[j](n);
10792 Roo.log('missing convert for ' + f.name);
10796 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
10798 var record = new Record(values, id);
10800 records[i] = record;
10806 totalRecords : totalRecords
10811 * Ext JS Library 1.1.1
10812 * Copyright(c) 2006-2007, Ext JS, LLC.
10814 * Originally Released Under LGPL - original licence link has changed is not relivant.
10817 * <script type="text/javascript">
10821 * @class Roo.data.ArrayReader
10822 * @extends Roo.data.DataReader
10823 * Data reader class to create an Array of Roo.data.Record objects from an Array.
10824 * Each element of that Array represents a row of data fields. The
10825 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
10826 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
10830 var RecordDef = Roo.data.Record.create([
10831 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
10832 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
10834 var myReader = new Roo.data.ArrayReader({
10835 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
10839 * This would consume an Array like this:
10841 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
10843 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
10845 * Create a new JsonReader
10846 * @param {Object} meta Metadata configuration options.
10847 * @param {Object} recordType Either an Array of field definition objects
10848 * as specified to {@link Roo.data.Record#create},
10849 * or an {@link Roo.data.Record} object
10850 * created using {@link Roo.data.Record#create}.
10852 Roo.data.ArrayReader = function(meta, recordType){
10853 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
10856 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
10858 * Create a data block containing Roo.data.Records from an XML document.
10859 * @param {Object} o An Array of row objects which represents the dataset.
10860 * @return {Object} data A data block which is used by an Roo.data.Store object as
10861 * a cache of Roo.data.Records.
10863 readRecords : function(o){
10864 var sid = this.meta ? this.meta.id : null;
10865 var recordType = this.recordType, fields = recordType.prototype.fields;
10868 for(var i = 0; i < root.length; i++){
10871 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
10872 for(var j = 0, jlen = fields.length; j < jlen; j++){
10873 var f = fields.items[j];
10874 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
10875 var v = n[k] !== undefined ? n[k] : f.defaultValue;
10877 values[f.name] = v;
10879 var record = new recordType(values, id);
10881 records[records.length] = record;
10885 totalRecords : records.length
10894 * @class Roo.bootstrap.ComboBox
10895 * @extends Roo.bootstrap.TriggerField
10896 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
10897 * @cfg {Boolean} append (true|false) default false
10898 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
10899 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
10900 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
10901 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
10902 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
10904 * Create a new ComboBox.
10905 * @param {Object} config Configuration options
10907 Roo.bootstrap.ComboBox = function(config){
10908 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
10912 * Fires when the dropdown list is expanded
10913 * @param {Roo.bootstrap.ComboBox} combo This combo box
10918 * Fires when the dropdown list is collapsed
10919 * @param {Roo.bootstrap.ComboBox} combo This combo box
10923 * @event beforeselect
10924 * Fires before a list item is selected. Return false to cancel the selection.
10925 * @param {Roo.bootstrap.ComboBox} combo This combo box
10926 * @param {Roo.data.Record} record The data record returned from the underlying store
10927 * @param {Number} index The index of the selected item in the dropdown list
10929 'beforeselect' : true,
10932 * Fires when a list item is selected
10933 * @param {Roo.bootstrap.ComboBox} combo This combo box
10934 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
10935 * @param {Number} index The index of the selected item in the dropdown list
10939 * @event beforequery
10940 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
10941 * The event object passed has these properties:
10942 * @param {Roo.bootstrap.ComboBox} combo This combo box
10943 * @param {String} query The query
10944 * @param {Boolean} forceAll true to force "all" query
10945 * @param {Boolean} cancel true to cancel the query
10946 * @param {Object} e The query event object
10948 'beforequery': true,
10951 * Fires when the 'add' icon is pressed (add a listener to enable add button)
10952 * @param {Roo.bootstrap.ComboBox} combo This combo box
10957 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
10958 * @param {Roo.bootstrap.ComboBox} combo This combo box
10959 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
10964 * Fires when the remove value from the combobox array
10965 * @param {Roo.bootstrap.ComboBox} combo This combo box
10969 * @event specialfilter
10970 * Fires when specialfilter
10971 * @param {Roo.bootstrap.ComboBox} combo This combo box
10973 'specialfilter' : true
10978 this.tickItems = [];
10980 this.selectedIndex = -1;
10981 if(this.mode == 'local'){
10982 if(config.queryDelay === undefined){
10983 this.queryDelay = 10;
10985 if(config.minChars === undefined){
10991 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
10994 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
10995 * rendering into an Roo.Editor, defaults to false)
10998 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
10999 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
11002 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
11005 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
11006 * the dropdown list (defaults to undefined, with no header element)
11010 * @cfg {String/Roo.Template} tpl The template to use to render the output
11014 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
11016 listWidth: undefined,
11018 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
11019 * mode = 'remote' or 'text' if mode = 'local')
11021 displayField: undefined,
11024 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
11025 * mode = 'remote' or 'value' if mode = 'local').
11026 * Note: use of a valueField requires the user make a selection
11027 * in order for a value to be mapped.
11029 valueField: undefined,
11033 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
11034 * field's data value (defaults to the underlying DOM element's name)
11036 hiddenName: undefined,
11038 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
11042 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
11044 selectedClass: 'active',
11047 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
11051 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
11052 * anchor positions (defaults to 'tl-bl')
11054 listAlign: 'tl-bl?',
11056 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
11060 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
11061 * query specified by the allQuery config option (defaults to 'query')
11063 triggerAction: 'query',
11065 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
11066 * (defaults to 4, does not apply if editable = false)
11070 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
11071 * delay (typeAheadDelay) if it matches a known value (defaults to false)
11075 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
11076 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
11080 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
11081 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
11085 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
11086 * when editable = true (defaults to false)
11088 selectOnFocus:false,
11090 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
11092 queryParam: 'query',
11094 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
11095 * when mode = 'remote' (defaults to 'Loading...')
11097 loadingText: 'Loading...',
11099 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
11103 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
11107 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
11108 * traditional select (defaults to true)
11112 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
11116 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
11120 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
11121 * listWidth has a higher value)
11125 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
11126 * allow the user to set arbitrary text into the field (defaults to false)
11128 forceSelection:false,
11130 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
11131 * if typeAhead = true (defaults to 250)
11133 typeAheadDelay : 250,
11135 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
11136 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
11138 valueNotFoundText : undefined,
11140 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
11142 blockFocus : false,
11145 * @cfg {Boolean} disableClear Disable showing of clear button.
11147 disableClear : false,
11149 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
11151 alwaysQuery : false,
11154 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
11159 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
11161 invalidClass : "has-warning",
11164 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
11166 validClass : "has-success",
11169 * @cfg {Boolean} specialFilter (true|false) special filter default false
11171 specialFilter : false,
11183 btnPosition : 'right',
11184 triggerList : true,
11185 showToggleBtn : true,
11186 // element that contains real text value.. (when hidden is used..)
11188 getAutoCreate : function()
11195 if(!this.tickable){
11196 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
11201 * ComboBox with tickable selections
11204 var align = this.labelAlign || this.parentLabelAlign();
11207 cls : 'form-group roo-combobox-tickable' //input-group
11212 cls : 'tickable-buttons',
11217 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
11224 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
11231 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
11238 buttons.cn.unshift({
11240 cls: 'select2-search-field-input'
11246 Roo.each(buttons.cn, function(c){
11248 c.cls += ' btn-' + _this.size;
11251 if (_this.disabled) {
11262 cls: 'form-hidden-field'
11266 cls: 'select2-choices',
11270 cls: 'select2-search-field',
11282 cls: 'select2-container input-group select2-container-multi',
11287 // cls: 'typeahead typeahead-long dropdown-menu',
11288 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
11293 if(this.hasFeedback && !this.allowBlank){
11297 cls: 'glyphicon form-control-feedback'
11300 combobox.cn.push(feedback);
11303 if (align ==='left' && this.fieldLabel.length) {
11305 Roo.log("left and has label");
11311 cls : 'control-label col-sm-' + this.labelWidth,
11312 html : this.fieldLabel
11316 cls : "col-sm-" + (12 - this.labelWidth),
11323 } else if ( this.fieldLabel.length) {
11329 //cls : 'input-group-addon',
11330 html : this.fieldLabel
11340 Roo.log(" no label && no align");
11347 ['xs','sm','md','lg'].map(function(size){
11348 if (settings[size]) {
11349 cfg.cls += ' col-' + size + '-' + settings[size];
11358 initEvents: function()
11362 throw "can not find store for combo";
11364 this.store = Roo.factory(this.store, Roo.data);
11367 this.initTickableEvents();
11371 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
11373 if(this.hiddenName){
11375 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11377 this.hiddenField.dom.value =
11378 this.hiddenValue !== undefined ? this.hiddenValue :
11379 this.value !== undefined ? this.value : '';
11381 // prevent input submission
11382 this.el.dom.removeAttribute('name');
11383 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11388 // this.el.dom.setAttribute('autocomplete', 'off');
11391 var cls = 'x-combo-list';
11393 //this.list = new Roo.Layer({
11394 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
11400 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11401 _this.list.setWidth(lw);
11404 this.list.on('mouseover', this.onViewOver, this);
11405 this.list.on('mousemove', this.onViewMove, this);
11407 this.list.on('scroll', this.onViewScroll, this);
11410 this.list.swallowEvent('mousewheel');
11411 this.assetHeight = 0;
11414 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
11415 this.assetHeight += this.header.getHeight();
11418 this.innerList = this.list.createChild({cls:cls+'-inner'});
11419 this.innerList.on('mouseover', this.onViewOver, this);
11420 this.innerList.on('mousemove', this.onViewMove, this);
11421 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11423 if(this.allowBlank && !this.pageSize && !this.disableClear){
11424 this.footer = this.list.createChild({cls:cls+'-ft'});
11425 this.pageTb = new Roo.Toolbar(this.footer);
11429 this.footer = this.list.createChild({cls:cls+'-ft'});
11430 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
11431 {pageSize: this.pageSize});
11435 if (this.pageTb && this.allowBlank && !this.disableClear) {
11437 this.pageTb.add(new Roo.Toolbar.Fill(), {
11438 cls: 'x-btn-icon x-btn-clear',
11440 handler: function()
11443 _this.clearValue();
11444 _this.onSelect(false, -1);
11449 this.assetHeight += this.footer.getHeight();
11454 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
11457 this.view = new Roo.View(this.list, this.tpl, {
11458 singleSelect:true, store: this.store, selectedClass: this.selectedClass
11460 //this.view.wrapEl.setDisplayed(false);
11461 this.view.on('click', this.onViewClick, this);
11465 this.store.on('beforeload', this.onBeforeLoad, this);
11466 this.store.on('load', this.onLoad, this);
11467 this.store.on('loadexception', this.onLoadException, this);
11469 if(this.resizable){
11470 this.resizer = new Roo.Resizable(this.list, {
11471 pinned:true, handles:'se'
11473 this.resizer.on('resize', function(r, w, h){
11474 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
11475 this.listWidth = w;
11476 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
11477 this.restrictHeight();
11479 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
11482 if(!this.editable){
11483 this.editable = true;
11484 this.setEditable(false);
11489 if (typeof(this.events.add.listeners) != 'undefined') {
11491 this.addicon = this.wrap.createChild(
11492 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
11494 this.addicon.on('click', function(e) {
11495 this.fireEvent('add', this);
11498 if (typeof(this.events.edit.listeners) != 'undefined') {
11500 this.editicon = this.wrap.createChild(
11501 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
11502 if (this.addicon) {
11503 this.editicon.setStyle('margin-left', '40px');
11505 this.editicon.on('click', function(e) {
11507 // we fire even if inothing is selected..
11508 this.fireEvent('edit', this, this.lastData );
11514 this.keyNav = new Roo.KeyNav(this.inputEl(), {
11515 "up" : function(e){
11516 this.inKeyMode = true;
11520 "down" : function(e){
11521 if(!this.isExpanded()){
11522 this.onTriggerClick();
11524 this.inKeyMode = true;
11529 "enter" : function(e){
11530 // this.onViewClick();
11534 if(this.fireEvent("specialkey", this, e)){
11535 this.onViewClick(false);
11541 "esc" : function(e){
11545 "tab" : function(e){
11548 if(this.fireEvent("specialkey", this, e)){
11549 this.onViewClick(false);
11557 doRelay : function(foo, bar, hname){
11558 if(hname == 'down' || this.scope.isExpanded()){
11559 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11568 this.queryDelay = Math.max(this.queryDelay || 10,
11569 this.mode == 'local' ? 10 : 250);
11572 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11574 if(this.typeAhead){
11575 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11577 if(this.editable !== false){
11578 this.inputEl().on("keyup", this.onKeyUp, this);
11580 if(this.forceSelection){
11581 this.inputEl().on('blur', this.doForce, this);
11585 this.choices = this.el.select('ul.select2-choices', true).first();
11586 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11590 initTickableEvents: function()
11594 if(this.hiddenName){
11596 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
11598 this.hiddenField.dom.value =
11599 this.hiddenValue !== undefined ? this.hiddenValue :
11600 this.value !== undefined ? this.value : '';
11602 // prevent input submission
11603 this.el.dom.removeAttribute('name');
11604 this.hiddenField.dom.setAttribute('name', this.hiddenName);
11609 // this.list = this.el.select('ul.dropdown-menu',true).first();
11611 this.choices = this.el.select('ul.select2-choices', true).first();
11612 this.searchField = this.el.select('ul li.select2-search-field', true).first();
11613 if(this.triggerList){
11614 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
11617 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
11618 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
11620 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
11621 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
11623 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
11624 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
11626 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
11627 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
11628 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
11631 this.cancelBtn.hide();
11636 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
11637 _this.list.setWidth(lw);
11640 this.list.on('mouseover', this.onViewOver, this);
11641 this.list.on('mousemove', this.onViewMove, this);
11643 this.list.on('scroll', this.onViewScroll, this);
11646 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>';
11649 this.view = new Roo.View(this.list, this.tpl, {
11650 singleSelect:true, tickable:true, parent:this, store: this.store, selectedClass: this.selectedClass
11653 //this.view.wrapEl.setDisplayed(false);
11654 this.view.on('click', this.onViewClick, this);
11658 this.store.on('beforeload', this.onBeforeLoad, this);
11659 this.store.on('load', this.onLoad, this);
11660 this.store.on('loadexception', this.onLoadException, this);
11663 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
11664 "up" : function(e){
11665 this.inKeyMode = true;
11669 "down" : function(e){
11670 this.inKeyMode = true;
11674 "enter" : function(e){
11675 if(this.fireEvent("specialkey", this, e)){
11676 this.onViewClick(false);
11682 "esc" : function(e){
11683 this.onTickableFooterButtonClick(e, false, false);
11686 "tab" : function(e){
11687 this.fireEvent("specialkey", this, e);
11689 this.onTickableFooterButtonClick(e, false, false);
11696 doRelay : function(e, fn, key){
11697 if(this.scope.isExpanded()){
11698 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
11707 this.queryDelay = Math.max(this.queryDelay || 10,
11708 this.mode == 'local' ? 10 : 250);
11711 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
11713 if(this.typeAhead){
11714 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
11717 if(this.editable !== false){
11718 this.tickableInputEl().on("keyup", this.onKeyUp, this);
11723 onDestroy : function(){
11725 this.view.setStore(null);
11726 this.view.el.removeAllListeners();
11727 this.view.el.remove();
11728 this.view.purgeListeners();
11731 this.list.dom.innerHTML = '';
11735 this.store.un('beforeload', this.onBeforeLoad, this);
11736 this.store.un('load', this.onLoad, this);
11737 this.store.un('loadexception', this.onLoadException, this);
11739 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
11743 fireKey : function(e){
11744 if(e.isNavKeyPress() && !this.list.isVisible()){
11745 this.fireEvent("specialkey", this, e);
11750 onResize: function(w, h){
11751 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
11753 // if(typeof w != 'number'){
11754 // // we do not handle it!?!?
11757 // var tw = this.trigger.getWidth();
11758 // // tw += this.addicon ? this.addicon.getWidth() : 0;
11759 // // tw += this.editicon ? this.editicon.getWidth() : 0;
11761 // this.inputEl().setWidth( this.adjustWidth('input', x));
11763 // //this.trigger.setStyle('left', x+'px');
11765 // if(this.list && this.listWidth === undefined){
11766 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
11767 // this.list.setWidth(lw);
11768 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
11776 * Allow or prevent the user from directly editing the field text. If false is passed,
11777 * the user will only be able to select from the items defined in the dropdown list. This method
11778 * is the runtime equivalent of setting the 'editable' config option at config time.
11779 * @param {Boolean} value True to allow the user to directly edit the field text
11781 setEditable : function(value){
11782 if(value == this.editable){
11785 this.editable = value;
11787 this.inputEl().dom.setAttribute('readOnly', true);
11788 this.inputEl().on('mousedown', this.onTriggerClick, this);
11789 this.inputEl().addClass('x-combo-noedit');
11791 this.inputEl().dom.setAttribute('readOnly', false);
11792 this.inputEl().un('mousedown', this.onTriggerClick, this);
11793 this.inputEl().removeClass('x-combo-noedit');
11799 onBeforeLoad : function(combo,opts){
11800 if(!this.hasFocus){
11804 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
11806 this.restrictHeight();
11807 this.selectedIndex = -1;
11811 onLoad : function(){
11813 this.hasQuery = false;
11815 if(!this.hasFocus){
11819 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11820 this.loading.hide();
11823 if(this.store.getCount() > 0){
11825 this.restrictHeight();
11826 if(this.lastQuery == this.allQuery){
11827 if(this.editable && !this.tickable){
11828 this.inputEl().dom.select();
11832 !this.selectByValue(this.value, true) &&
11835 !this.store.lastOptions ||
11836 typeof(this.store.lastOptions.add) == 'undefined' ||
11837 this.store.lastOptions.add != true
11840 this.select(0, true);
11843 if(this.autoFocus){
11846 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
11847 this.taTask.delay(this.typeAheadDelay);
11851 this.onEmptyResults();
11857 onLoadException : function()
11859 this.hasQuery = false;
11861 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
11862 this.loading.hide();
11865 if(this.tickable && this.editable){
11871 Roo.log(this.store.reader.jsonData);
11872 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
11874 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
11880 onTypeAhead : function(){
11881 if(this.store.getCount() > 0){
11882 var r = this.store.getAt(0);
11883 var newValue = r.data[this.displayField];
11884 var len = newValue.length;
11885 var selStart = this.getRawValue().length;
11887 if(selStart != len){
11888 this.setRawValue(newValue);
11889 this.selectText(selStart, newValue.length);
11895 onSelect : function(record, index){
11897 if(this.fireEvent('beforeselect', this, record, index) !== false){
11899 this.setFromData(index > -1 ? record.data : false);
11902 this.fireEvent('select', this, record, index);
11907 * Returns the currently selected field value or empty string if no value is set.
11908 * @return {String} value The selected value
11910 getValue : function(){
11913 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
11916 if(this.valueField){
11917 return typeof this.value != 'undefined' ? this.value : '';
11919 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
11924 * Clears any text/value currently set in the field
11926 clearValue : function(){
11927 if(this.hiddenField){
11928 this.hiddenField.dom.value = '';
11931 this.setRawValue('');
11932 this.lastSelectionText = '';
11933 this.lastData = false;
11938 * Sets the specified value into the field. If the value finds a match, the corresponding record text
11939 * will be displayed in the field. If the value does not match the data value of an existing item,
11940 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
11941 * Otherwise the field will be blank (although the value will still be set).
11942 * @param {String} value The value to match
11944 setValue : function(v){
11951 if(this.valueField){
11952 var r = this.findRecord(this.valueField, v);
11954 text = r.data[this.displayField];
11955 }else if(this.valueNotFoundText !== undefined){
11956 text = this.valueNotFoundText;
11959 this.lastSelectionText = text;
11960 if(this.hiddenField){
11961 this.hiddenField.dom.value = v;
11963 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
11967 * @property {Object} the last set data for the element
11972 * Sets the value of the field based on a object which is related to the record format for the store.
11973 * @param {Object} value the value to set as. or false on reset?
11975 setFromData : function(o){
11982 var dv = ''; // display value
11983 var vv = ''; // value value..
11985 if (this.displayField) {
11986 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
11988 // this is an error condition!!!
11989 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
11992 if(this.valueField){
11993 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
11996 if(this.hiddenField){
11997 this.hiddenField.dom.value = vv;
11999 this.lastSelectionText = dv;
12000 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12004 // no hidden field.. - we store the value in 'value', but still display
12005 // display field!!!!
12006 this.lastSelectionText = dv;
12007 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
12013 reset : function(){
12014 // overridden so that last data is reset..
12021 this.setValue(this.originalValue);
12022 this.clearInvalid();
12023 this.lastData = false;
12025 this.view.clearSelections();
12029 findRecord : function(prop, value){
12031 if(this.store.getCount() > 0){
12032 this.store.each(function(r){
12033 if(r.data[prop] == value){
12043 getName: function()
12045 // returns hidden if it's set..
12046 if (!this.rendered) {return ''};
12047 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
12051 onViewMove : function(e, t){
12052 this.inKeyMode = false;
12056 onViewOver : function(e, t){
12057 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
12060 var item = this.view.findItemFromChild(t);
12063 var index = this.view.indexOf(item);
12064 this.select(index, false);
12069 onViewClick : function(view, doFocus, el, e)
12071 var index = this.view.getSelectedIndexes()[0];
12073 var r = this.store.getAt(index);
12077 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
12084 Roo.each(this.tickItems, function(v,k){
12086 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
12087 _this.tickItems.splice(k, 1);
12089 if(typeof(e) == 'undefined' && view == false){
12090 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
12102 this.tickItems.push(r.data);
12104 if(typeof(e) == 'undefined' && view == false){
12105 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
12112 this.onSelect(r, index);
12114 if(doFocus !== false && !this.blockFocus){
12115 this.inputEl().focus();
12120 restrictHeight : function(){
12121 //this.innerList.dom.style.height = '';
12122 //var inner = this.innerList.dom;
12123 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
12124 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
12125 //this.list.beginUpdate();
12126 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
12127 this.list.alignTo(this.inputEl(), this.listAlign);
12128 this.list.alignTo(this.inputEl(), this.listAlign);
12129 //this.list.endUpdate();
12133 onEmptyResults : function(){
12135 if(this.tickable && this.editable){
12136 this.restrictHeight();
12144 * Returns true if the dropdown list is expanded, else false.
12146 isExpanded : function(){
12147 return this.list.isVisible();
12151 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
12152 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12153 * @param {String} value The data value of the item to select
12154 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12155 * selected item if it is not currently in view (defaults to true)
12156 * @return {Boolean} True if the value matched an item in the list, else false
12158 selectByValue : function(v, scrollIntoView){
12159 if(v !== undefined && v !== null){
12160 var r = this.findRecord(this.valueField || this.displayField, v);
12162 this.select(this.store.indexOf(r), scrollIntoView);
12170 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
12171 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
12172 * @param {Number} index The zero-based index of the list item to select
12173 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
12174 * selected item if it is not currently in view (defaults to true)
12176 select : function(index, scrollIntoView){
12177 this.selectedIndex = index;
12178 this.view.select(index);
12179 if(scrollIntoView !== false){
12180 var el = this.view.getNode(index);
12182 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
12185 this.list.scrollChildIntoView(el, false);
12191 selectNext : function(){
12192 var ct = this.store.getCount();
12194 if(this.selectedIndex == -1){
12196 }else if(this.selectedIndex < ct-1){
12197 this.select(this.selectedIndex+1);
12203 selectPrev : function(){
12204 var ct = this.store.getCount();
12206 if(this.selectedIndex == -1){
12208 }else if(this.selectedIndex != 0){
12209 this.select(this.selectedIndex-1);
12215 onKeyUp : function(e){
12216 if(this.editable !== false && !e.isSpecialKey()){
12217 this.lastKey = e.getKey();
12218 this.dqTask.delay(this.queryDelay);
12223 validateBlur : function(){
12224 return !this.list || !this.list.isVisible();
12228 initQuery : function(){
12230 var v = this.getRawValue();
12232 if(this.tickable && this.editable){
12233 v = this.tickableInputEl().getValue();
12240 doForce : function(){
12241 if(this.inputEl().dom.value.length > 0){
12242 this.inputEl().dom.value =
12243 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
12249 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
12250 * query allowing the query action to be canceled if needed.
12251 * @param {String} query The SQL query to execute
12252 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
12253 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
12254 * saved in the current store (defaults to false)
12256 doQuery : function(q, forceAll){
12258 if(q === undefined || q === null){
12263 forceAll: forceAll,
12267 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
12272 forceAll = qe.forceAll;
12273 if(forceAll === true || (q.length >= this.minChars)){
12275 this.hasQuery = true;
12277 if(this.lastQuery != q || this.alwaysQuery){
12278 this.lastQuery = q;
12279 if(this.mode == 'local'){
12280 this.selectedIndex = -1;
12282 this.store.clearFilter();
12285 if(this.specialFilter){
12286 this.fireEvent('specialfilter', this);
12291 this.store.filter(this.displayField, q);
12294 this.store.fireEvent("datachanged", this.store);
12301 this.store.baseParams[this.queryParam] = q;
12303 var options = {params : this.getParams(q)};
12306 options.add = true;
12307 options.params.start = this.page * this.pageSize;
12310 this.store.load(options);
12313 * this code will make the page width larger, at the beginning, the list not align correctly,
12314 * we should expand the list on onLoad
12315 * so command out it
12320 this.selectedIndex = -1;
12325 this.loadNext = false;
12329 getParams : function(q){
12331 //p[this.queryParam] = q;
12335 p.limit = this.pageSize;
12341 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
12343 collapse : function(){
12344 if(!this.isExpanded()){
12351 this.hasFocus = false;
12353 this.cancelBtn.hide();
12354 this.trigger.show();
12357 this.tickableInputEl().dom.value = '';
12358 this.tickableInputEl().blur();
12363 Roo.get(document).un('mousedown', this.collapseIf, this);
12364 Roo.get(document).un('mousewheel', this.collapseIf, this);
12365 if (!this.editable) {
12366 Roo.get(document).un('keydown', this.listKeyPress, this);
12368 this.fireEvent('collapse', this);
12372 collapseIf : function(e){
12373 var in_combo = e.within(this.el);
12374 var in_list = e.within(this.list);
12375 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
12377 if (in_combo || in_list || is_list) {
12378 //e.stopPropagation();
12383 this.onTickableFooterButtonClick(e, false, false);
12391 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
12393 expand : function(){
12395 if(this.isExpanded() || !this.hasFocus){
12399 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
12400 this.list.setWidth(lw);
12407 this.restrictHeight();
12411 this.tickItems = Roo.apply([], this.item);
12414 this.cancelBtn.show();
12415 this.trigger.hide();
12418 this.tickableInputEl().focus();
12423 Roo.get(document).on('mousedown', this.collapseIf, this);
12424 Roo.get(document).on('mousewheel', this.collapseIf, this);
12425 if (!this.editable) {
12426 Roo.get(document).on('keydown', this.listKeyPress, this);
12429 this.fireEvent('expand', this);
12433 // Implements the default empty TriggerField.onTriggerClick function
12434 onTriggerClick : function(e)
12436 Roo.log('trigger click');
12438 if(this.disabled || !this.triggerList){
12443 this.loadNext = false;
12445 if(this.isExpanded()){
12447 if (!this.blockFocus) {
12448 this.inputEl().focus();
12452 this.hasFocus = true;
12453 if(this.triggerAction == 'all') {
12454 this.doQuery(this.allQuery, true);
12456 this.doQuery(this.getRawValue());
12458 if (!this.blockFocus) {
12459 this.inputEl().focus();
12464 onTickableTriggerClick : function(e)
12471 this.loadNext = false;
12472 this.hasFocus = true;
12474 if(this.triggerAction == 'all') {
12475 this.doQuery(this.allQuery, true);
12477 this.doQuery(this.getRawValue());
12481 onSearchFieldClick : function(e)
12483 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
12484 this.onTickableFooterButtonClick(e, false, false);
12488 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
12493 this.loadNext = false;
12494 this.hasFocus = true;
12496 if(this.triggerAction == 'all') {
12497 this.doQuery(this.allQuery, true);
12499 this.doQuery(this.getRawValue());
12503 listKeyPress : function(e)
12505 //Roo.log('listkeypress');
12506 // scroll to first matching element based on key pres..
12507 if (e.isSpecialKey()) {
12510 var k = String.fromCharCode(e.getKey()).toUpperCase();
12513 var csel = this.view.getSelectedNodes();
12514 var cselitem = false;
12516 var ix = this.view.indexOf(csel[0]);
12517 cselitem = this.store.getAt(ix);
12518 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
12524 this.store.each(function(v) {
12526 // start at existing selection.
12527 if (cselitem.id == v.id) {
12533 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
12534 match = this.store.indexOf(v);
12540 if (match === false) {
12541 return true; // no more action?
12544 this.view.select(match);
12545 var sn = Roo.get(this.view.getSelectedNodes()[0])
12546 sn.scrollIntoView(sn.dom.parentNode, false);
12549 onViewScroll : function(e, t){
12551 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){
12555 this.hasQuery = true;
12557 this.loading = this.list.select('.loading', true).first();
12559 if(this.loading === null){
12560 this.list.createChild({
12562 cls: 'loading select2-more-results select2-active',
12563 html: 'Loading more results...'
12566 this.loading = this.list.select('.loading', true).first();
12568 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
12570 this.loading.hide();
12573 this.loading.show();
12578 this.loadNext = true;
12580 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
12585 addItem : function(o)
12587 var dv = ''; // display value
12589 if (this.displayField) {
12590 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
12592 // this is an error condition!!!
12593 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
12600 var choice = this.choices.createChild({
12602 cls: 'select2-search-choice',
12611 cls: 'select2-search-choice-close',
12616 }, this.searchField);
12618 var close = choice.select('a.select2-search-choice-close', true).first()
12620 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
12628 this.inputEl().dom.value = '';
12633 onRemoveItem : function(e, _self, o)
12635 e.preventDefault();
12637 this.lastItem = Roo.apply([], this.item);
12639 var index = this.item.indexOf(o.data) * 1;
12642 Roo.log('not this item?!');
12646 this.item.splice(index, 1);
12651 this.fireEvent('remove', this, e);
12657 syncValue : function()
12659 if(!this.item.length){
12666 Roo.each(this.item, function(i){
12667 if(_this.valueField){
12668 value.push(i[_this.valueField]);
12675 this.value = value.join(',');
12677 if(this.hiddenField){
12678 this.hiddenField.dom.value = this.value;
12681 this.store.fireEvent("datachanged", this.store);
12684 clearItem : function()
12686 if(!this.multiple){
12692 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
12701 inputEl: function ()
12704 return this.searchField;
12706 return this.el.select('input.form-control',true).first();
12710 onTickableFooterButtonClick : function(e, btn, el)
12712 e.preventDefault();
12714 this.lastItem = Roo.apply([], this.item);
12716 if(btn && btn.name == 'cancel'){
12717 this.tickItems = Roo.apply([], this.item);
12726 Roo.each(this.tickItems, function(o){
12734 validate : function()
12736 var v = this.getRawValue();
12739 v = this.getValue();
12742 if(this.disabled || this.allowBlank || v.length){
12747 this.markInvalid();
12751 tickableInputEl : function()
12753 if(!this.tickable || !this.editable){
12754 return this.inputEl();
12757 return this.inputEl().select('.select2-search-field-input', true).first();
12763 * @cfg {Boolean} grow
12767 * @cfg {Number} growMin
12771 * @cfg {Number} growMax
12781 * Ext JS Library 1.1.1
12782 * Copyright(c) 2006-2007, Ext JS, LLC.
12784 * Originally Released Under LGPL - original licence link has changed is not relivant.
12787 * <script type="text/javascript">
12792 * @extends Roo.util.Observable
12793 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
12794 * This class also supports single and multi selection modes. <br>
12795 * Create a data model bound view:
12797 var store = new Roo.data.Store(...);
12799 var view = new Roo.View({
12801 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
12803 singleSelect: true,
12804 selectedClass: "ydataview-selected",
12808 // listen for node click?
12809 view.on("click", function(vw, index, node, e){
12810 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
12814 dataModel.load("foobar.xml");
12816 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
12818 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
12819 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
12821 * Note: old style constructor is still suported (container, template, config)
12824 * Create a new View
12825 * @param {Object} config The config object
12828 Roo.View = function(config, depreciated_tpl, depreciated_config){
12830 this.parent = false;
12832 if (typeof(depreciated_tpl) == 'undefined') {
12833 // new way.. - universal constructor.
12834 Roo.apply(this, config);
12835 this.el = Roo.get(this.el);
12838 this.el = Roo.get(config);
12839 this.tpl = depreciated_tpl;
12840 Roo.apply(this, depreciated_config);
12842 this.wrapEl = this.el.wrap().wrap();
12843 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
12846 if(typeof(this.tpl) == "string"){
12847 this.tpl = new Roo.Template(this.tpl);
12849 // support xtype ctors..
12850 this.tpl = new Roo.factory(this.tpl, Roo);
12854 this.tpl.compile();
12859 * @event beforeclick
12860 * Fires before a click is processed. Returns false to cancel the default action.
12861 * @param {Roo.View} this
12862 * @param {Number} index The index of the target node
12863 * @param {HTMLElement} node The target node
12864 * @param {Roo.EventObject} e The raw event object
12866 "beforeclick" : true,
12869 * Fires when a template node is clicked.
12870 * @param {Roo.View} this
12871 * @param {Number} index The index of the target node
12872 * @param {HTMLElement} node The target node
12873 * @param {Roo.EventObject} e The raw event object
12878 * Fires when a template node is double clicked.
12879 * @param {Roo.View} this
12880 * @param {Number} index The index of the target node
12881 * @param {HTMLElement} node The target node
12882 * @param {Roo.EventObject} e The raw event object
12886 * @event contextmenu
12887 * Fires when a template node is right clicked.
12888 * @param {Roo.View} this
12889 * @param {Number} index The index of the target node
12890 * @param {HTMLElement} node The target node
12891 * @param {Roo.EventObject} e The raw event object
12893 "contextmenu" : true,
12895 * @event selectionchange
12896 * Fires when the selected nodes change.
12897 * @param {Roo.View} this
12898 * @param {Array} selections Array of the selected nodes
12900 "selectionchange" : true,
12903 * @event beforeselect
12904 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
12905 * @param {Roo.View} this
12906 * @param {HTMLElement} node The node to be selected
12907 * @param {Array} selections Array of currently selected nodes
12909 "beforeselect" : true,
12911 * @event preparedata
12912 * Fires on every row to render, to allow you to change the data.
12913 * @param {Roo.View} this
12914 * @param {Object} data to be rendered (change this)
12916 "preparedata" : true
12924 "click": this.onClick,
12925 "dblclick": this.onDblClick,
12926 "contextmenu": this.onContextMenu,
12930 this.selections = [];
12932 this.cmp = new Roo.CompositeElementLite([]);
12934 this.store = Roo.factory(this.store, Roo.data);
12935 this.setStore(this.store, true);
12938 if ( this.footer && this.footer.xtype) {
12940 var fctr = this.wrapEl.appendChild(document.createElement("div"));
12942 this.footer.dataSource = this.store
12943 this.footer.container = fctr;
12944 this.footer = Roo.factory(this.footer, Roo);
12945 fctr.insertFirst(this.el);
12947 // this is a bit insane - as the paging toolbar seems to detach the el..
12948 // dom.parentNode.parentNode.parentNode
12949 // they get detached?
12953 Roo.View.superclass.constructor.call(this);
12958 Roo.extend(Roo.View, Roo.util.Observable, {
12961 * @cfg {Roo.data.Store} store Data store to load data from.
12966 * @cfg {String|Roo.Element} el The container element.
12971 * @cfg {String|Roo.Template} tpl The template used by this View
12975 * @cfg {String} dataName the named area of the template to use as the data area
12976 * Works with domtemplates roo-name="name"
12980 * @cfg {String} selectedClass The css class to add to selected nodes
12982 selectedClass : "x-view-selected",
12984 * @cfg {String} emptyText The empty text to show when nothing is loaded.
12989 * @cfg {String} text to display on mask (default Loading)
12993 * @cfg {Boolean} multiSelect Allow multiple selection
12995 multiSelect : false,
12997 * @cfg {Boolean} singleSelect Allow single selection
12999 singleSelect: false,
13002 * @cfg {Boolean} toggleSelect - selecting
13004 toggleSelect : false,
13007 * @cfg {Boolean} tickable - selecting
13012 * Returns the element this view is bound to.
13013 * @return {Roo.Element}
13015 getEl : function(){
13016 return this.wrapEl;
13022 * Refreshes the view. - called by datachanged on the store. - do not call directly.
13024 refresh : function(){
13025 //Roo.log('refresh');
13028 // if we are using something like 'domtemplate', then
13029 // the what gets used is:
13030 // t.applySubtemplate(NAME, data, wrapping data..)
13031 // the outer template then get' applied with
13032 // the store 'extra data'
13033 // and the body get's added to the
13034 // roo-name="data" node?
13035 // <span class='roo-tpl-{name}'></span> ?????
13039 this.clearSelections();
13040 this.el.update("");
13042 var records = this.store.getRange();
13043 if(records.length < 1) {
13045 // is this valid?? = should it render a template??
13047 this.el.update(this.emptyText);
13051 if (this.dataName) {
13052 this.el.update(t.apply(this.store.meta)); //????
13053 el = this.el.child('.roo-tpl-' + this.dataName);
13056 for(var i = 0, len = records.length; i < len; i++){
13057 var data = this.prepareData(records[i].data, i, records[i]);
13058 this.fireEvent("preparedata", this, data, i, records[i]);
13060 var d = Roo.apply({}, data);
13063 Roo.apply(d, {'roo-id' : Roo.id()});
13067 Roo.each(this.parent.item, function(item){
13068 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
13071 Roo.apply(d, {'roo-data-checked' : 'checked'});
13075 html[html.length] = Roo.util.Format.trim(
13077 t.applySubtemplate(this.dataName, d, this.store.meta) :
13084 el.update(html.join(""));
13085 this.nodes = el.dom.childNodes;
13086 this.updateIndexes(0);
13091 * Function to override to reformat the data that is sent to
13092 * the template for each node.
13093 * DEPRICATED - use the preparedata event handler.
13094 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
13095 * a JSON object for an UpdateManager bound view).
13097 prepareData : function(data, index, record)
13099 this.fireEvent("preparedata", this, data, index, record);
13103 onUpdate : function(ds, record){
13104 // Roo.log('on update');
13105 this.clearSelections();
13106 var index = this.store.indexOf(record);
13107 var n = this.nodes[index];
13108 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
13109 n.parentNode.removeChild(n);
13110 this.updateIndexes(index, index);
13116 onAdd : function(ds, records, index)
13118 //Roo.log(['on Add', ds, records, index] );
13119 this.clearSelections();
13120 if(this.nodes.length == 0){
13124 var n = this.nodes[index];
13125 for(var i = 0, len = records.length; i < len; i++){
13126 var d = this.prepareData(records[i].data, i, records[i]);
13128 this.tpl.insertBefore(n, d);
13131 this.tpl.append(this.el, d);
13134 this.updateIndexes(index);
13137 onRemove : function(ds, record, index){
13138 // Roo.log('onRemove');
13139 this.clearSelections();
13140 var el = this.dataName ?
13141 this.el.child('.roo-tpl-' + this.dataName) :
13144 el.dom.removeChild(this.nodes[index]);
13145 this.updateIndexes(index);
13149 * Refresh an individual node.
13150 * @param {Number} index
13152 refreshNode : function(index){
13153 this.onUpdate(this.store, this.store.getAt(index));
13156 updateIndexes : function(startIndex, endIndex){
13157 var ns = this.nodes;
13158 startIndex = startIndex || 0;
13159 endIndex = endIndex || ns.length - 1;
13160 for(var i = startIndex; i <= endIndex; i++){
13161 ns[i].nodeIndex = i;
13166 * Changes the data store this view uses and refresh the view.
13167 * @param {Store} store
13169 setStore : function(store, initial){
13170 if(!initial && this.store){
13171 this.store.un("datachanged", this.refresh);
13172 this.store.un("add", this.onAdd);
13173 this.store.un("remove", this.onRemove);
13174 this.store.un("update", this.onUpdate);
13175 this.store.un("clear", this.refresh);
13176 this.store.un("beforeload", this.onBeforeLoad);
13177 this.store.un("load", this.onLoad);
13178 this.store.un("loadexception", this.onLoad);
13182 store.on("datachanged", this.refresh, this);
13183 store.on("add", this.onAdd, this);
13184 store.on("remove", this.onRemove, this);
13185 store.on("update", this.onUpdate, this);
13186 store.on("clear", this.refresh, this);
13187 store.on("beforeload", this.onBeforeLoad, this);
13188 store.on("load", this.onLoad, this);
13189 store.on("loadexception", this.onLoad, this);
13197 * onbeforeLoad - masks the loading area.
13200 onBeforeLoad : function(store,opts)
13202 //Roo.log('onBeforeLoad');
13204 this.el.update("");
13206 this.el.mask(this.mask ? this.mask : "Loading" );
13208 onLoad : function ()
13215 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
13216 * @param {HTMLElement} node
13217 * @return {HTMLElement} The template node
13219 findItemFromChild : function(node){
13220 var el = this.dataName ?
13221 this.el.child('.roo-tpl-' + this.dataName,true) :
13224 if(!node || node.parentNode == el){
13227 var p = node.parentNode;
13228 while(p && p != el){
13229 if(p.parentNode == el){
13238 onClick : function(e){
13239 var item = this.findItemFromChild(e.getTarget());
13241 var index = this.indexOf(item);
13242 if(this.onItemClick(item, index, e) !== false){
13243 this.fireEvent("click", this, index, item, e);
13246 this.clearSelections();
13251 onContextMenu : function(e){
13252 var item = this.findItemFromChild(e.getTarget());
13254 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
13259 onDblClick : function(e){
13260 var item = this.findItemFromChild(e.getTarget());
13262 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
13266 onItemClick : function(item, index, e)
13268 if(this.fireEvent("beforeclick", this, index, item, e) === false){
13271 if (this.toggleSelect) {
13272 var m = this.isSelected(item) ? 'unselect' : 'select';
13275 _t[m](item, true, false);
13278 if(this.multiSelect || this.singleSelect){
13279 if(this.multiSelect && e.shiftKey && this.lastSelection){
13280 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
13282 this.select(item, this.multiSelect && e.ctrlKey);
13283 this.lastSelection = item;
13286 if(!this.tickable){
13287 e.preventDefault();
13295 * Get the number of selected nodes.
13298 getSelectionCount : function(){
13299 return this.selections.length;
13303 * Get the currently selected nodes.
13304 * @return {Array} An array of HTMLElements
13306 getSelectedNodes : function(){
13307 return this.selections;
13311 * Get the indexes of the selected nodes.
13314 getSelectedIndexes : function(){
13315 var indexes = [], s = this.selections;
13316 for(var i = 0, len = s.length; i < len; i++){
13317 indexes.push(s[i].nodeIndex);
13323 * Clear all selections
13324 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
13326 clearSelections : function(suppressEvent){
13327 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
13328 this.cmp.elements = this.selections;
13329 this.cmp.removeClass(this.selectedClass);
13330 this.selections = [];
13331 if(!suppressEvent){
13332 this.fireEvent("selectionchange", this, this.selections);
13338 * Returns true if the passed node is selected
13339 * @param {HTMLElement/Number} node The node or node index
13340 * @return {Boolean}
13342 isSelected : function(node){
13343 var s = this.selections;
13347 node = this.getNode(node);
13348 return s.indexOf(node) !== -1;
13353 * @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
13354 * @param {Boolean} keepExisting (optional) true to keep existing selections
13355 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13357 select : function(nodeInfo, keepExisting, suppressEvent){
13358 if(nodeInfo instanceof Array){
13360 this.clearSelections(true);
13362 for(var i = 0, len = nodeInfo.length; i < len; i++){
13363 this.select(nodeInfo[i], true, true);
13367 var node = this.getNode(nodeInfo);
13368 if(!node || this.isSelected(node)){
13369 return; // already selected.
13372 this.clearSelections(true);
13375 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
13376 Roo.fly(node).addClass(this.selectedClass);
13377 this.selections.push(node);
13378 if(!suppressEvent){
13379 this.fireEvent("selectionchange", this, this.selections);
13387 * @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
13388 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
13389 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
13391 unselect : function(nodeInfo, keepExisting, suppressEvent)
13393 if(nodeInfo instanceof Array){
13394 Roo.each(this.selections, function(s) {
13395 this.unselect(s, nodeInfo);
13399 var node = this.getNode(nodeInfo);
13400 if(!node || !this.isSelected(node)){
13401 //Roo.log("not selected");
13402 return; // not selected.
13406 Roo.each(this.selections, function(s) {
13408 Roo.fly(node).removeClass(this.selectedClass);
13415 this.selections= ns;
13416 this.fireEvent("selectionchange", this, this.selections);
13420 * Gets a template node.
13421 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13422 * @return {HTMLElement} The node or null if it wasn't found
13424 getNode : function(nodeInfo){
13425 if(typeof nodeInfo == "string"){
13426 return document.getElementById(nodeInfo);
13427 }else if(typeof nodeInfo == "number"){
13428 return this.nodes[nodeInfo];
13434 * Gets a range template nodes.
13435 * @param {Number} startIndex
13436 * @param {Number} endIndex
13437 * @return {Array} An array of nodes
13439 getNodes : function(start, end){
13440 var ns = this.nodes;
13441 start = start || 0;
13442 end = typeof end == "undefined" ? ns.length - 1 : end;
13445 for(var i = start; i <= end; i++){
13449 for(var i = start; i >= end; i--){
13457 * Finds the index of the passed node
13458 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
13459 * @return {Number} The index of the node or -1
13461 indexOf : function(node){
13462 node = this.getNode(node);
13463 if(typeof node.nodeIndex == "number"){
13464 return node.nodeIndex;
13466 var ns = this.nodes;
13467 for(var i = 0, len = ns.length; i < len; i++){
13478 * based on jquery fullcalendar
13482 Roo.bootstrap = Roo.bootstrap || {};
13484 * @class Roo.bootstrap.Calendar
13485 * @extends Roo.bootstrap.Component
13486 * Bootstrap Calendar class
13487 * @cfg {Boolean} loadMask (true|false) default false
13488 * @cfg {Object} header generate the user specific header of the calendar, default false
13491 * Create a new Container
13492 * @param {Object} config The config object
13497 Roo.bootstrap.Calendar = function(config){
13498 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
13502 * Fires when a date is selected
13503 * @param {DatePicker} this
13504 * @param {Date} date The selected date
13508 * @event monthchange
13509 * Fires when the displayed month changes
13510 * @param {DatePicker} this
13511 * @param {Date} date The selected month
13513 'monthchange': true,
13515 * @event evententer
13516 * Fires when mouse over an event
13517 * @param {Calendar} this
13518 * @param {event} Event
13520 'evententer': true,
13522 * @event eventleave
13523 * Fires when the mouse leaves an
13524 * @param {Calendar} this
13527 'eventleave': true,
13529 * @event eventclick
13530 * Fires when the mouse click an
13531 * @param {Calendar} this
13540 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
13543 * @cfg {Number} startDay
13544 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
13552 getAutoCreate : function(){
13555 var fc_button = function(name, corner, style, content ) {
13556 return Roo.apply({},{
13558 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
13560 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
13563 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
13574 style : 'width:100%',
13581 cls : 'fc-header-left',
13583 fc_button('prev', 'left', 'arrow', '‹' ),
13584 fc_button('next', 'right', 'arrow', '›' ),
13585 { tag: 'span', cls: 'fc-header-space' },
13586 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
13594 cls : 'fc-header-center',
13598 cls: 'fc-header-title',
13601 html : 'month / year'
13609 cls : 'fc-header-right',
13611 /* fc_button('month', 'left', '', 'month' ),
13612 fc_button('week', '', '', 'week' ),
13613 fc_button('day', 'right', '', 'day' )
13625 header = this.header;
13628 var cal_heads = function() {
13630 // fixme - handle this.
13632 for (var i =0; i < Date.dayNames.length; i++) {
13633 var d = Date.dayNames[i];
13636 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
13637 html : d.substring(0,3)
13641 ret[0].cls += ' fc-first';
13642 ret[6].cls += ' fc-last';
13645 var cal_cell = function(n) {
13648 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
13653 cls: 'fc-day-number',
13657 cls: 'fc-day-content',
13661 style: 'position: relative;' // height: 17px;
13673 var cal_rows = function() {
13676 for (var r = 0; r < 6; r++) {
13683 for (var i =0; i < Date.dayNames.length; i++) {
13684 var d = Date.dayNames[i];
13685 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
13688 row.cn[0].cls+=' fc-first';
13689 row.cn[0].cn[0].style = 'min-height:90px';
13690 row.cn[6].cls+=' fc-last';
13694 ret[0].cls += ' fc-first';
13695 ret[4].cls += ' fc-prev-last';
13696 ret[5].cls += ' fc-last';
13703 cls: 'fc-border-separate',
13704 style : 'width:100%',
13712 cls : 'fc-first fc-last',
13730 cls : 'fc-content',
13731 style : "position: relative;",
13734 cls : 'fc-view fc-view-month fc-grid',
13735 style : 'position: relative',
13736 unselectable : 'on',
13739 cls : 'fc-event-container',
13740 style : 'position:absolute;z-index:8;top:0;left:0;'
13758 initEvents : function()
13761 throw "can not find store for calendar";
13767 style: "text-align:center",
13771 style: "background-color:white;width:50%;margin:250 auto",
13775 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
13786 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
13788 var size = this.el.select('.fc-content', true).first().getSize();
13789 this.maskEl.setSize(size.width, size.height);
13790 this.maskEl.enableDisplayMode("block");
13791 if(!this.loadMask){
13792 this.maskEl.hide();
13795 this.store = Roo.factory(this.store, Roo.data);
13796 this.store.on('load', this.onLoad, this);
13797 this.store.on('beforeload', this.onBeforeLoad, this);
13801 this.cells = this.el.select('.fc-day',true);
13802 //Roo.log(this.cells);
13803 this.textNodes = this.el.query('.fc-day-number');
13804 this.cells.addClassOnOver('fc-state-hover');
13806 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
13807 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
13808 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
13809 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
13811 this.on('monthchange', this.onMonthChange, this);
13813 this.update(new Date().clearTime());
13816 resize : function() {
13817 var sz = this.el.getSize();
13819 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
13820 this.el.select('.fc-day-content div',true).setHeight(34);
13825 showPrevMonth : function(e){
13826 this.update(this.activeDate.add("mo", -1));
13828 showToday : function(e){
13829 this.update(new Date().clearTime());
13832 showNextMonth : function(e){
13833 this.update(this.activeDate.add("mo", 1));
13837 showPrevYear : function(){
13838 this.update(this.activeDate.add("y", -1));
13842 showNextYear : function(){
13843 this.update(this.activeDate.add("y", 1));
13848 update : function(date)
13850 var vd = this.activeDate;
13851 this.activeDate = date;
13852 // if(vd && this.el){
13853 // var t = date.getTime();
13854 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
13855 // Roo.log('using add remove');
13857 // this.fireEvent('monthchange', this, date);
13859 // this.cells.removeClass("fc-state-highlight");
13860 // this.cells.each(function(c){
13861 // if(c.dateValue == t){
13862 // c.addClass("fc-state-highlight");
13863 // setTimeout(function(){
13864 // try{c.dom.firstChild.focus();}catch(e){}
13874 var days = date.getDaysInMonth();
13876 var firstOfMonth = date.getFirstDateOfMonth();
13877 var startingPos = firstOfMonth.getDay()-this.startDay;
13879 if(startingPos < this.startDay){
13883 var pm = date.add(Date.MONTH, -1);
13884 var prevStart = pm.getDaysInMonth()-startingPos;
13886 this.cells = this.el.select('.fc-day',true);
13887 this.textNodes = this.el.query('.fc-day-number');
13888 this.cells.addClassOnOver('fc-state-hover');
13890 var cells = this.cells.elements;
13891 var textEls = this.textNodes;
13893 Roo.each(cells, function(cell){
13894 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
13897 days += startingPos;
13899 // convert everything to numbers so it's fast
13900 var day = 86400000;
13901 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
13904 //Roo.log(prevStart);
13906 var today = new Date().clearTime().getTime();
13907 var sel = date.clearTime().getTime();
13908 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
13909 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
13910 var ddMatch = this.disabledDatesRE;
13911 var ddText = this.disabledDatesText;
13912 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
13913 var ddaysText = this.disabledDaysText;
13914 var format = this.format;
13916 var setCellClass = function(cal, cell){
13920 //Roo.log('set Cell Class');
13922 var t = d.getTime();
13926 cell.dateValue = t;
13928 cell.className += " fc-today";
13929 cell.className += " fc-state-highlight";
13930 cell.title = cal.todayText;
13933 // disable highlight in other month..
13934 //cell.className += " fc-state-highlight";
13939 cell.className = " fc-state-disabled";
13940 cell.title = cal.minText;
13944 cell.className = " fc-state-disabled";
13945 cell.title = cal.maxText;
13949 if(ddays.indexOf(d.getDay()) != -1){
13950 cell.title = ddaysText;
13951 cell.className = " fc-state-disabled";
13954 if(ddMatch && format){
13955 var fvalue = d.dateFormat(format);
13956 if(ddMatch.test(fvalue)){
13957 cell.title = ddText.replace("%0", fvalue);
13958 cell.className = " fc-state-disabled";
13962 if (!cell.initialClassName) {
13963 cell.initialClassName = cell.dom.className;
13966 cell.dom.className = cell.initialClassName + ' ' + cell.className;
13971 for(; i < startingPos; i++) {
13972 textEls[i].innerHTML = (++prevStart);
13973 d.setDate(d.getDate()+1);
13975 cells[i].className = "fc-past fc-other-month";
13976 setCellClass(this, cells[i]);
13981 for(; i < days; i++){
13982 intDay = i - startingPos + 1;
13983 textEls[i].innerHTML = (intDay);
13984 d.setDate(d.getDate()+1);
13986 cells[i].className = ''; // "x-date-active";
13987 setCellClass(this, cells[i]);
13991 for(; i < 42; i++) {
13992 textEls[i].innerHTML = (++extraDays);
13993 d.setDate(d.getDate()+1);
13995 cells[i].className = "fc-future fc-other-month";
13996 setCellClass(this, cells[i]);
13999 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
14001 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
14003 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
14004 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
14006 if(totalRows != 6){
14007 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
14008 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
14011 this.fireEvent('monthchange', this, date);
14015 if(!this.internalRender){
14016 var main = this.el.dom.firstChild;
14017 var w = main.offsetWidth;
14018 this.el.setWidth(w + this.el.getBorderWidth("lr"));
14019 Roo.fly(main).setWidth(w);
14020 this.internalRender = true;
14021 // opera does not respect the auto grow header center column
14022 // then, after it gets a width opera refuses to recalculate
14023 // without a second pass
14024 if(Roo.isOpera && !this.secondPass){
14025 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
14026 this.secondPass = true;
14027 this.update.defer(10, this, [date]);
14034 findCell : function(dt) {
14035 dt = dt.clearTime().getTime();
14037 this.cells.each(function(c){
14038 //Roo.log("check " +c.dateValue + '?=' + dt);
14039 if(c.dateValue == dt){
14049 findCells : function(ev) {
14050 var s = ev.start.clone().clearTime().getTime();
14052 var e= ev.end.clone().clearTime().getTime();
14055 this.cells.each(function(c){
14056 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
14058 if(c.dateValue > e){
14061 if(c.dateValue < s){
14070 // findBestRow: function(cells)
14074 // for (var i =0 ; i < cells.length;i++) {
14075 // ret = Math.max(cells[i].rows || 0,ret);
14082 addItem : function(ev)
14084 // look for vertical location slot in
14085 var cells = this.findCells(ev);
14087 // ev.row = this.findBestRow(cells);
14089 // work out the location.
14093 for(var i =0; i < cells.length; i++) {
14095 cells[i].row = cells[0].row;
14098 cells[i].row = cells[i].row + 1;
14108 if (crow.start.getY() == cells[i].getY()) {
14110 crow.end = cells[i];
14127 cells[0].events.push(ev);
14129 this.calevents.push(ev);
14132 clearEvents: function() {
14134 if(!this.calevents){
14138 Roo.each(this.cells.elements, function(c){
14144 Roo.each(this.calevents, function(e) {
14145 Roo.each(e.els, function(el) {
14146 el.un('mouseenter' ,this.onEventEnter, this);
14147 el.un('mouseleave' ,this.onEventLeave, this);
14152 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
14158 renderEvents: function()
14162 this.cells.each(function(c) {
14171 if(c.row != c.events.length){
14172 r = 4 - (4 - (c.row - c.events.length));
14175 c.events = ev.slice(0, r);
14176 c.more = ev.slice(r);
14178 if(c.more.length && c.more.length == 1){
14179 c.events.push(c.more.pop());
14182 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
14186 this.cells.each(function(c) {
14188 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
14191 for (var e = 0; e < c.events.length; e++){
14192 var ev = c.events[e];
14193 var rows = ev.rows;
14195 for(var i = 0; i < rows.length; i++) {
14197 // how many rows should it span..
14200 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
14201 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
14203 unselectable : "on",
14206 cls: 'fc-event-inner',
14210 // cls: 'fc-event-time',
14211 // html : cells.length > 1 ? '' : ev.time
14215 cls: 'fc-event-title',
14216 html : String.format('{0}', ev.title)
14223 cls: 'ui-resizable-handle ui-resizable-e',
14224 html : '  '
14231 cfg.cls += ' fc-event-start';
14233 if ((i+1) == rows.length) {
14234 cfg.cls += ' fc-event-end';
14237 var ctr = _this.el.select('.fc-event-container',true).first();
14238 var cg = ctr.createChild(cfg);
14240 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
14241 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
14243 var r = (c.more.length) ? 1 : 0;
14244 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
14245 cg.setWidth(ebox.right - sbox.x -2);
14247 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
14248 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
14249 cg.on('click', _this.onEventClick, _this, ev);
14260 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
14261 style : 'position: absolute',
14262 unselectable : "on",
14265 cls: 'fc-event-inner',
14269 cls: 'fc-event-title',
14277 cls: 'ui-resizable-handle ui-resizable-e',
14278 html : '  '
14284 var ctr = _this.el.select('.fc-event-container',true).first();
14285 var cg = ctr.createChild(cfg);
14287 var sbox = c.select('.fc-day-content',true).first().getBox();
14288 var ebox = c.select('.fc-day-content',true).first().getBox();
14290 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
14291 cg.setWidth(ebox.right - sbox.x -2);
14293 cg.on('click', _this.onMoreEventClick, _this, c.more);
14303 onEventEnter: function (e, el,event,d) {
14304 this.fireEvent('evententer', this, el, event);
14307 onEventLeave: function (e, el,event,d) {
14308 this.fireEvent('eventleave', this, el, event);
14311 onEventClick: function (e, el,event,d) {
14312 this.fireEvent('eventclick', this, el, event);
14315 onMonthChange: function () {
14319 onMoreEventClick: function(e, el, more)
14323 this.calpopover.placement = 'right';
14324 this.calpopover.setTitle('More');
14326 this.calpopover.setContent('');
14328 var ctr = this.calpopover.el.select('.popover-content', true).first();
14330 Roo.each(more, function(m){
14332 cls : 'fc-event-hori fc-event-draggable',
14335 var cg = ctr.createChild(cfg);
14337 cg.on('click', _this.onEventClick, _this, m);
14340 this.calpopover.show(el);
14345 onLoad: function ()
14347 this.calevents = [];
14350 if(this.store.getCount() > 0){
14351 this.store.data.each(function(d){
14354 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
14355 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
14356 time : d.data.start_time,
14357 title : d.data.title,
14358 description : d.data.description,
14359 venue : d.data.venue
14364 this.renderEvents();
14366 if(this.calevents.length && this.loadMask){
14367 this.maskEl.hide();
14371 onBeforeLoad: function()
14373 this.clearEvents();
14375 this.maskEl.show();
14389 * @class Roo.bootstrap.Popover
14390 * @extends Roo.bootstrap.Component
14391 * Bootstrap Popover class
14392 * @cfg {String} html contents of the popover (or false to use children..)
14393 * @cfg {String} title of popover (or false to hide)
14394 * @cfg {String} placement how it is placed
14395 * @cfg {String} trigger click || hover (or false to trigger manually)
14396 * @cfg {String} over what (parent or false to trigger manually.)
14397 * @cfg {Number} delay - delay before showing
14400 * Create a new Popover
14401 * @param {Object} config The config object
14404 Roo.bootstrap.Popover = function(config){
14405 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
14408 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
14410 title: 'Fill in a title',
14413 placement : 'right',
14414 trigger : 'hover', // hover
14420 can_build_overlaid : false,
14422 getChildContainer : function()
14424 return this.el.select('.popover-content',true).first();
14427 getAutoCreate : function(){
14428 Roo.log('make popover?');
14430 cls : 'popover roo-dynamic',
14431 style: 'display:block',
14437 cls : 'popover-inner',
14441 cls: 'popover-title',
14445 cls : 'popover-content',
14456 setTitle: function(str)
14458 this.el.select('.popover-title',true).first().dom.innerHTML = str;
14460 setContent: function(str)
14462 this.el.select('.popover-content',true).first().dom.innerHTML = str;
14464 // as it get's added to the bottom of the page.
14465 onRender : function(ct, position)
14467 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
14469 var cfg = Roo.apply({}, this.getAutoCreate());
14473 cfg.cls += ' ' + this.cls;
14476 cfg.style = this.style;
14478 Roo.log("adding to ")
14479 this.el = Roo.get(document.body).createChild(cfg, position);
14485 initEvents : function()
14487 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
14488 this.el.enableDisplayMode('block');
14490 if (this.over === false) {
14493 if (this.triggers === false) {
14496 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14497 var triggers = this.trigger ? this.trigger.split(' ') : [];
14498 Roo.each(triggers, function(trigger) {
14500 if (trigger == 'click') {
14501 on_el.on('click', this.toggle, this);
14502 } else if (trigger != 'manual') {
14503 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
14504 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
14506 on_el.on(eventIn ,this.enter, this);
14507 on_el.on(eventOut, this.leave, this);
14518 toggle : function () {
14519 this.hoverState == 'in' ? this.leave() : this.enter();
14522 enter : function () {
14525 clearTimeout(this.timeout);
14527 this.hoverState = 'in';
14529 if (!this.delay || !this.delay.show) {
14534 this.timeout = setTimeout(function () {
14535 if (_t.hoverState == 'in') {
14538 }, this.delay.show)
14540 leave : function() {
14541 clearTimeout(this.timeout);
14543 this.hoverState = 'out';
14545 if (!this.delay || !this.delay.hide) {
14550 this.timeout = setTimeout(function () {
14551 if (_t.hoverState == 'out') {
14554 }, this.delay.hide)
14557 show : function (on_el)
14560 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
14563 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
14564 if (this.html !== false) {
14565 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
14567 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
14568 if (!this.title.length) {
14569 this.el.select('.popover-title',true).hide();
14572 var placement = typeof this.placement == 'function' ?
14573 this.placement.call(this, this.el, on_el) :
14576 var autoToken = /\s?auto?\s?/i;
14577 var autoPlace = autoToken.test(placement);
14579 placement = placement.replace(autoToken, '') || 'top';
14583 //this.el.setXY([0,0]);
14585 this.el.dom.style.display='block';
14586 this.el.addClass(placement);
14588 //this.el.appendTo(on_el);
14590 var p = this.getPosition();
14591 var box = this.el.getBox();
14596 var align = Roo.bootstrap.Popover.alignment[placement];
14597 this.el.alignTo(on_el, align[0],align[1]);
14598 //var arrow = this.el.select('.arrow',true).first();
14599 //arrow.set(align[2],
14601 this.el.addClass('in');
14602 this.hoverState = null;
14604 if (this.el.hasClass('fade')) {
14611 this.el.setXY([0,0]);
14612 this.el.removeClass('in');
14619 Roo.bootstrap.Popover.alignment = {
14620 'left' : ['r-l', [-10,0], 'right'],
14621 'right' : ['l-r', [10,0], 'left'],
14622 'bottom' : ['t-b', [0,10], 'top'],
14623 'top' : [ 'b-t', [0,-10], 'bottom']
14634 * @class Roo.bootstrap.Progress
14635 * @extends Roo.bootstrap.Component
14636 * Bootstrap Progress class
14637 * @cfg {Boolean} striped striped of the progress bar
14638 * @cfg {Boolean} active animated of the progress bar
14642 * Create a new Progress
14643 * @param {Object} config The config object
14646 Roo.bootstrap.Progress = function(config){
14647 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
14650 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
14655 getAutoCreate : function(){
14663 cfg.cls += ' progress-striped';
14667 cfg.cls += ' active';
14686 * @class Roo.bootstrap.ProgressBar
14687 * @extends Roo.bootstrap.Component
14688 * Bootstrap ProgressBar class
14689 * @cfg {Number} aria_valuenow aria-value now
14690 * @cfg {Number} aria_valuemin aria-value min
14691 * @cfg {Number} aria_valuemax aria-value max
14692 * @cfg {String} label label for the progress bar
14693 * @cfg {String} panel (success | info | warning | danger )
14694 * @cfg {String} role role of the progress bar
14695 * @cfg {String} sr_only text
14699 * Create a new ProgressBar
14700 * @param {Object} config The config object
14703 Roo.bootstrap.ProgressBar = function(config){
14704 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
14707 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
14711 aria_valuemax : 100,
14717 getAutoCreate : function()
14722 cls: 'progress-bar',
14723 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
14735 cfg.role = this.role;
14738 if(this.aria_valuenow){
14739 cfg['aria-valuenow'] = this.aria_valuenow;
14742 if(this.aria_valuemin){
14743 cfg['aria-valuemin'] = this.aria_valuemin;
14746 if(this.aria_valuemax){
14747 cfg['aria-valuemax'] = this.aria_valuemax;
14750 if(this.label && !this.sr_only){
14751 cfg.html = this.label;
14755 cfg.cls += ' progress-bar-' + this.panel;
14761 update : function(aria_valuenow)
14763 this.aria_valuenow = aria_valuenow;
14765 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
14780 * @class Roo.bootstrap.TabGroup
14781 * @extends Roo.bootstrap.Column
14782 * Bootstrap Column class
14783 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
14784 * @cfg {Boolean} carousel true to make the group behave like a carousel
14785 * @cfg {Number} bullets show the panel pointer.. default 0
14786 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
14787 * @cfg {Boolean} slideOnTouch (true|false) slide on touch .. default false
14788 * @cfg {Number} timer auto slide timer .. default 0 millisecond
14791 * Create a new TabGroup
14792 * @param {Object} config The config object
14795 Roo.bootstrap.TabGroup = function(config){
14796 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
14798 this.navId = Roo.id();
14801 Roo.bootstrap.TabGroup.register(this);
14805 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
14808 transition : false,
14813 slideOnTouch : false,
14815 getAutoCreate : function()
14817 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
14819 cfg.cls += ' tab-content';
14821 Roo.log('get auto create...............');
14823 if (this.carousel) {
14824 cfg.cls += ' carousel slide';
14827 cls : 'carousel-inner'
14830 if(this.bullets > 0 && !Roo.isTouch){
14833 cls : 'carousel-bullets',
14837 if(this.bullets_cls){
14838 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
14841 for (var i = 0; i < this.bullets; i++){
14843 cls : 'bullet bullet-' + i
14851 cfg.cn[0].cn = bullets;
14858 initEvents: function()
14860 Roo.log('-------- init events on tab group ---------');
14862 if(this.bullets > 0 && !Roo.isTouch){
14868 if(Roo.isTouch && this.slideOnTouch){
14869 this.el.on("touchstart", this.onTouchStart, this);
14872 if(this.autoslide){
14875 this.slideFn = window.setInterval(function() {
14876 _this.showPanelNext();
14882 onTouchStart : function(e, el, o)
14884 if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
14888 this.showPanelNext();
14891 getChildContainer : function()
14893 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
14897 * register a Navigation item
14898 * @param {Roo.bootstrap.NavItem} the navitem to add
14900 register : function(item)
14902 this.tabs.push( item);
14903 item.navId = this.navId; // not really needed..
14907 getActivePanel : function()
14910 Roo.each(this.tabs, function(t) {
14920 getPanelByName : function(n)
14923 Roo.each(this.tabs, function(t) {
14924 if (t.tabId == n) {
14932 indexOfPanel : function(p)
14935 Roo.each(this.tabs, function(t,i) {
14936 if (t.tabId == p.tabId) {
14945 * show a specific panel
14946 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
14947 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
14949 showPanel : function (pan)
14951 if(this.transition){
14952 Roo.log("waiting for the transitionend");
14956 if (typeof(pan) == 'number') {
14957 pan = this.tabs[pan];
14959 if (typeof(pan) == 'string') {
14960 pan = this.getPanelByName(pan);
14962 if (pan.tabId == this.getActivePanel().tabId) {
14965 var cur = this.getActivePanel();
14967 if (false === cur.fireEvent('beforedeactivate')) {
14971 if(this.bullets > 0 && !Roo.isTouch){
14972 this.setActiveBullet(this.indexOfPanel(pan));
14975 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
14977 this.transition = true;
14978 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
14979 var lr = dir == 'next' ? 'left' : 'right';
14980 pan.el.addClass(dir); // or prev
14981 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
14982 cur.el.addClass(lr); // or right
14983 pan.el.addClass(lr);
14986 cur.el.on('transitionend', function() {
14987 Roo.log("trans end?");
14989 pan.el.removeClass([lr,dir]);
14990 pan.setActive(true);
14992 cur.el.removeClass([lr]);
14993 cur.setActive(false);
14995 _this.transition = false;
14997 }, this, { single: true } );
15002 cur.setActive(false);
15003 pan.setActive(true);
15008 showPanelNext : function()
15010 var i = this.indexOfPanel(this.getActivePanel());
15012 if (i >= this.tabs.length - 1 && !this.autoslide) {
15016 if (i >= this.tabs.length - 1 && this.autoslide) {
15020 this.showPanel(this.tabs[i+1]);
15023 showPanelPrev : function()
15025 var i = this.indexOfPanel(this.getActivePanel());
15027 if (i < 1 && !this.autoslide) {
15031 if (i < 1 && this.autoslide) {
15032 i = this.tabs.length;
15035 this.showPanel(this.tabs[i-1]);
15038 initBullet : function()
15046 for (var i = 0; i < this.bullets; i++){
15047 var bullet = this.el.select('.bullet-' + i, true).first();
15053 bullet.on('click', (function(e, el, o, ii, t){
15055 e.preventDefault();
15057 _this.showPanel(ii);
15059 if(_this.autoslide && _this.slideFn){
15060 clearInterval(_this.slideFn);
15061 _this.slideFn = window.setInterval(function() {
15062 _this.showPanelNext();
15066 }).createDelegate(this, [i, bullet], true));
15070 setActiveBullet : function(i)
15076 Roo.each(this.el.select('.bullet', true).elements, function(el){
15077 el.removeClass('selected');
15080 var bullet = this.el.select('.bullet-' + i, true).first();
15086 bullet.addClass('selected');
15097 Roo.apply(Roo.bootstrap.TabGroup, {
15101 * register a Navigation Group
15102 * @param {Roo.bootstrap.NavGroup} the navgroup to add
15104 register : function(navgrp)
15106 this.groups[navgrp.navId] = navgrp;
15110 * fetch a Navigation Group based on the navigation ID
15111 * if one does not exist , it will get created.
15112 * @param {string} the navgroup to add
15113 * @returns {Roo.bootstrap.NavGroup} the navgroup
15115 get: function(navId) {
15116 if (typeof(this.groups[navId]) == 'undefined') {
15117 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
15119 return this.groups[navId] ;
15134 * @class Roo.bootstrap.TabPanel
15135 * @extends Roo.bootstrap.Component
15136 * Bootstrap TabPanel class
15137 * @cfg {Boolean} active panel active
15138 * @cfg {String} html panel content
15139 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
15140 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
15144 * Create a new TabPanel
15145 * @param {Object} config The config object
15148 Roo.bootstrap.TabPanel = function(config){
15149 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
15153 * Fires when the active status changes
15154 * @param {Roo.bootstrap.TabPanel} this
15155 * @param {Boolean} state the new state
15160 * @event beforedeactivate
15161 * Fires before a tab is de-activated - can be used to do validation on a form.
15162 * @param {Roo.bootstrap.TabPanel} this
15163 * @return {Boolean} false if there is an error
15166 'beforedeactivate': true
15169 this.tabId = this.tabId || Roo.id();
15173 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
15180 getAutoCreate : function(){
15183 // item is needed for carousel - not sure if it has any effect otherwise
15184 cls: 'tab-pane item',
15185 html: this.html || ''
15189 cfg.cls += ' active';
15193 cfg.tabId = this.tabId;
15200 initEvents: function()
15202 Roo.log('-------- init events on tab panel ---------');
15204 var p = this.parent();
15205 this.navId = this.navId || p.navId;
15207 if (typeof(this.navId) != 'undefined') {
15208 // not really needed.. but just in case.. parent should be a NavGroup.
15209 var tg = Roo.bootstrap.TabGroup.get(this.navId);
15210 Roo.log(['register', tg, this]);
15213 var i = tg.tabs.length - 1;
15215 if(this.active && tg.bullets > 0 && i < tg.bullets){
15216 tg.setActiveBullet(i);
15223 onRender : function(ct, position)
15225 // Roo.log("Call onRender: " + this.xtype);
15227 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
15235 setActive: function(state)
15237 Roo.log("panel - set active " + this.tabId + "=" + state);
15239 this.active = state;
15241 this.el.removeClass('active');
15243 } else if (!this.el.hasClass('active')) {
15244 this.el.addClass('active');
15247 this.fireEvent('changed', this, state);
15264 * @class Roo.bootstrap.DateField
15265 * @extends Roo.bootstrap.Input
15266 * Bootstrap DateField class
15267 * @cfg {Number} weekStart default 0
15268 * @cfg {String} viewMode default empty, (months|years)
15269 * @cfg {String} minViewMode default empty, (months|years)
15270 * @cfg {Number} startDate default -Infinity
15271 * @cfg {Number} endDate default Infinity
15272 * @cfg {Boolean} todayHighlight default false
15273 * @cfg {Boolean} todayBtn default false
15274 * @cfg {Boolean} calendarWeeks default false
15275 * @cfg {Object} daysOfWeekDisabled default empty
15276 * @cfg {Boolean} singleMode default false (true | false)
15278 * @cfg {Boolean} keyboardNavigation default true
15279 * @cfg {String} language default en
15282 * Create a new DateField
15283 * @param {Object} config The config object
15286 Roo.bootstrap.DateField = function(config){
15287 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
15291 * Fires when this field show.
15292 * @param {Roo.bootstrap.DateField} this
15293 * @param {Mixed} date The date value
15298 * Fires when this field hide.
15299 * @param {Roo.bootstrap.DateField} this
15300 * @param {Mixed} date The date value
15305 * Fires when select a date.
15306 * @param {Roo.bootstrap.DateField} this
15307 * @param {Mixed} date The date value
15313 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
15316 * @cfg {String} format
15317 * The default date format string which can be overriden for localization support. The format must be
15318 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
15322 * @cfg {String} altFormats
15323 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
15324 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
15326 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
15334 todayHighlight : false,
15340 keyboardNavigation: true,
15342 calendarWeeks: false,
15344 startDate: -Infinity,
15348 daysOfWeekDisabled: [],
15352 singleMode : false,
15354 UTCDate: function()
15356 return new Date(Date.UTC.apply(Date, arguments));
15359 UTCToday: function()
15361 var today = new Date();
15362 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
15365 getDate: function() {
15366 var d = this.getUTCDate();
15367 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
15370 getUTCDate: function() {
15374 setDate: function(d) {
15375 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
15378 setUTCDate: function(d) {
15380 this.setValue(this.formatDate(this.date));
15383 onRender: function(ct, position)
15386 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
15388 this.language = this.language || 'en';
15389 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
15390 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
15392 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
15393 this.format = this.format || 'm/d/y';
15394 this.isInline = false;
15395 this.isInput = true;
15396 this.component = this.el.select('.add-on', true).first() || false;
15397 this.component = (this.component && this.component.length === 0) ? false : this.component;
15398 this.hasInput = this.component && this.inputEL().length;
15400 if (typeof(this.minViewMode === 'string')) {
15401 switch (this.minViewMode) {
15403 this.minViewMode = 1;
15406 this.minViewMode = 2;
15409 this.minViewMode = 0;
15414 if (typeof(this.viewMode === 'string')) {
15415 switch (this.viewMode) {
15428 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
15430 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
15432 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15434 this.picker().on('mousedown', this.onMousedown, this);
15435 this.picker().on('click', this.onClick, this);
15437 this.picker().addClass('datepicker-dropdown');
15439 this.startViewMode = this.viewMode;
15441 if(this.singleMode){
15442 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
15443 v.setVisibilityMode(Roo.Element.DISPLAY)
15447 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
15448 v.setStyle('width', '189px');
15452 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
15453 if(!this.calendarWeeks){
15458 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15459 v.attr('colspan', function(i, val){
15460 return parseInt(val) + 1;
15465 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
15467 this.setStartDate(this.startDate);
15468 this.setEndDate(this.endDate);
15470 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
15477 if(this.isInline) {
15482 picker : function()
15484 return this.pickerEl;
15485 // return this.el.select('.datepicker', true).first();
15488 fillDow: function()
15490 var dowCnt = this.weekStart;
15499 if(this.calendarWeeks){
15507 while (dowCnt < this.weekStart + 7) {
15511 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
15515 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
15518 fillMonths: function()
15521 var months = this.picker().select('>.datepicker-months td', true).first();
15523 months.dom.innerHTML = '';
15529 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
15532 months.createChild(month);
15539 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;
15541 if (this.date < this.startDate) {
15542 this.viewDate = new Date(this.startDate);
15543 } else if (this.date > this.endDate) {
15544 this.viewDate = new Date(this.endDate);
15546 this.viewDate = new Date(this.date);
15554 var d = new Date(this.viewDate),
15555 year = d.getUTCFullYear(),
15556 month = d.getUTCMonth(),
15557 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
15558 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
15559 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
15560 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
15561 currentDate = this.date && this.date.valueOf(),
15562 today = this.UTCToday();
15564 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
15566 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
15568 // this.picker.select('>tfoot th.today').
15569 // .text(dates[this.language].today)
15570 // .toggle(this.todayBtn !== false);
15572 this.updateNavArrows();
15575 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
15577 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
15579 prevMonth.setUTCDate(day);
15581 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
15583 var nextMonth = new Date(prevMonth);
15585 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
15587 nextMonth = nextMonth.valueOf();
15589 var fillMonths = false;
15591 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
15593 while(prevMonth.valueOf() < nextMonth) {
15596 if (prevMonth.getUTCDay() === this.weekStart) {
15598 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
15606 if(this.calendarWeeks){
15607 // ISO 8601: First week contains first thursday.
15608 // ISO also states week starts on Monday, but we can be more abstract here.
15610 // Start of current week: based on weekstart/current date
15611 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
15612 // Thursday of this week
15613 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
15614 // First Thursday of year, year from thursday
15615 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
15616 // Calendar week: ms between thursdays, div ms per day, div 7 days
15617 calWeek = (th - yth) / 864e5 / 7 + 1;
15619 fillMonths.cn.push({
15627 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
15629 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
15632 if (this.todayHighlight &&
15633 prevMonth.getUTCFullYear() == today.getFullYear() &&
15634 prevMonth.getUTCMonth() == today.getMonth() &&
15635 prevMonth.getUTCDate() == today.getDate()) {
15636 clsName += ' today';
15639 if (currentDate && prevMonth.valueOf() === currentDate) {
15640 clsName += ' active';
15643 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
15644 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
15645 clsName += ' disabled';
15648 fillMonths.cn.push({
15650 cls: 'day ' + clsName,
15651 html: prevMonth.getDate()
15654 prevMonth.setDate(prevMonth.getDate()+1);
15657 var currentYear = this.date && this.date.getUTCFullYear();
15658 var currentMonth = this.date && this.date.getUTCMonth();
15660 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
15662 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
15663 v.removeClass('active');
15665 if(currentYear === year && k === currentMonth){
15666 v.addClass('active');
15669 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
15670 v.addClass('disabled');
15676 year = parseInt(year/10, 10) * 10;
15678 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
15680 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
15683 for (var i = -1; i < 11; i++) {
15684 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
15686 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
15694 showMode: function(dir)
15697 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
15700 Roo.each(this.picker().select('>div',true).elements, function(v){
15701 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15704 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
15709 if(this.isInline) return;
15711 this.picker().removeClass(['bottom', 'top']);
15713 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
15715 * place to the top of element!
15719 this.picker().addClass('top');
15720 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
15725 this.picker().addClass('bottom');
15727 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
15730 parseDate : function(value)
15732 if(!value || value instanceof Date){
15735 var v = Date.parseDate(value, this.format);
15736 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
15737 v = Date.parseDate(value, 'Y-m-d');
15739 if(!v && this.altFormats){
15740 if(!this.altFormatsArray){
15741 this.altFormatsArray = this.altFormats.split("|");
15743 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
15744 v = Date.parseDate(value, this.altFormatsArray[i]);
15750 formatDate : function(date, fmt)
15752 return (!date || !(date instanceof Date)) ?
15753 date : date.dateFormat(fmt || this.format);
15756 onFocus : function()
15758 Roo.bootstrap.DateField.superclass.onFocus.call(this);
15762 onBlur : function()
15764 Roo.bootstrap.DateField.superclass.onBlur.call(this);
15766 var d = this.inputEl().getValue();
15775 this.picker().show();
15779 this.fireEvent('show', this, this.date);
15784 if(this.isInline) return;
15785 this.picker().hide();
15786 this.viewMode = this.startViewMode;
15789 this.fireEvent('hide', this, this.date);
15793 onMousedown: function(e)
15795 e.stopPropagation();
15796 e.preventDefault();
15801 Roo.bootstrap.DateField.superclass.keyup.call(this);
15805 setValue: function(v)
15808 // v can be a string or a date..
15811 var d = new Date(this.parseDate(v) ).clearTime();
15813 if(isNaN(d.getTime())){
15814 this.date = this.viewDate = '';
15815 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
15819 v = this.formatDate(d);
15821 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
15823 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
15827 this.fireEvent('select', this, this.date);
15831 getValue: function()
15833 return this.formatDate(this.date);
15836 fireKey: function(e)
15838 if (!this.picker().isVisible()){
15839 if (e.keyCode == 27) // allow escape to hide and re-show picker
15844 var dateChanged = false,
15846 newDate, newViewDate;
15851 e.preventDefault();
15855 if (!this.keyboardNavigation) break;
15856 dir = e.keyCode == 37 ? -1 : 1;
15859 newDate = this.moveYear(this.date, dir);
15860 newViewDate = this.moveYear(this.viewDate, dir);
15861 } else if (e.shiftKey){
15862 newDate = this.moveMonth(this.date, dir);
15863 newViewDate = this.moveMonth(this.viewDate, dir);
15865 newDate = new Date(this.date);
15866 newDate.setUTCDate(this.date.getUTCDate() + dir);
15867 newViewDate = new Date(this.viewDate);
15868 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
15870 if (this.dateWithinRange(newDate)){
15871 this.date = newDate;
15872 this.viewDate = newViewDate;
15873 this.setValue(this.formatDate(this.date));
15875 e.preventDefault();
15876 dateChanged = true;
15881 if (!this.keyboardNavigation) break;
15882 dir = e.keyCode == 38 ? -1 : 1;
15884 newDate = this.moveYear(this.date, dir);
15885 newViewDate = this.moveYear(this.viewDate, dir);
15886 } else if (e.shiftKey){
15887 newDate = this.moveMonth(this.date, dir);
15888 newViewDate = this.moveMonth(this.viewDate, dir);
15890 newDate = new Date(this.date);
15891 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
15892 newViewDate = new Date(this.viewDate);
15893 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
15895 if (this.dateWithinRange(newDate)){
15896 this.date = newDate;
15897 this.viewDate = newViewDate;
15898 this.setValue(this.formatDate(this.date));
15900 e.preventDefault();
15901 dateChanged = true;
15905 this.setValue(this.formatDate(this.date));
15907 e.preventDefault();
15910 this.setValue(this.formatDate(this.date));
15924 onClick: function(e)
15926 e.stopPropagation();
15927 e.preventDefault();
15929 var target = e.getTarget();
15931 if(target.nodeName.toLowerCase() === 'i'){
15932 target = Roo.get(target).dom.parentNode;
15935 var nodeName = target.nodeName;
15936 var className = target.className;
15937 var html = target.innerHTML;
15938 //Roo.log(nodeName);
15940 switch(nodeName.toLowerCase()) {
15942 switch(className) {
15948 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
15949 switch(this.viewMode){
15951 this.viewDate = this.moveMonth(this.viewDate, dir);
15955 this.viewDate = this.moveYear(this.viewDate, dir);
15961 var date = new Date();
15962 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
15964 this.setValue(this.formatDate(this.date));
15971 if (className.indexOf('disabled') < 0) {
15972 this.viewDate.setUTCDate(1);
15973 if (className.indexOf('month') > -1) {
15974 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
15976 var year = parseInt(html, 10) || 0;
15977 this.viewDate.setUTCFullYear(year);
15981 if(this.singleMode){
15982 this.setValue(this.formatDate(this.viewDate));
15993 //Roo.log(className);
15994 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
15995 var day = parseInt(html, 10) || 1;
15996 var year = this.viewDate.getUTCFullYear(),
15997 month = this.viewDate.getUTCMonth();
15999 if (className.indexOf('old') > -1) {
16006 } else if (className.indexOf('new') > -1) {
16014 //Roo.log([year,month,day]);
16015 this.date = this.UTCDate(year, month, day,0,0,0,0);
16016 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
16018 //Roo.log(this.formatDate(this.date));
16019 this.setValue(this.formatDate(this.date));
16026 setStartDate: function(startDate)
16028 this.startDate = startDate || -Infinity;
16029 if (this.startDate !== -Infinity) {
16030 this.startDate = this.parseDate(this.startDate);
16033 this.updateNavArrows();
16036 setEndDate: function(endDate)
16038 this.endDate = endDate || Infinity;
16039 if (this.endDate !== Infinity) {
16040 this.endDate = this.parseDate(this.endDate);
16043 this.updateNavArrows();
16046 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
16048 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
16049 if (typeof(this.daysOfWeekDisabled) !== 'object') {
16050 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
16052 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
16053 return parseInt(d, 10);
16056 this.updateNavArrows();
16059 updateNavArrows: function()
16061 if(this.singleMode){
16065 var d = new Date(this.viewDate),
16066 year = d.getUTCFullYear(),
16067 month = d.getUTCMonth();
16069 Roo.each(this.picker().select('.prev', true).elements, function(v){
16071 switch (this.viewMode) {
16074 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
16080 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
16087 Roo.each(this.picker().select('.next', true).elements, function(v){
16089 switch (this.viewMode) {
16092 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
16098 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
16106 moveMonth: function(date, dir)
16108 if (!dir) return date;
16109 var new_date = new Date(date.valueOf()),
16110 day = new_date.getUTCDate(),
16111 month = new_date.getUTCMonth(),
16112 mag = Math.abs(dir),
16114 dir = dir > 0 ? 1 : -1;
16117 // If going back one month, make sure month is not current month
16118 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
16120 return new_date.getUTCMonth() == month;
16122 // If going forward one month, make sure month is as expected
16123 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
16125 return new_date.getUTCMonth() != new_month;
16127 new_month = month + dir;
16128 new_date.setUTCMonth(new_month);
16129 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
16130 if (new_month < 0 || new_month > 11)
16131 new_month = (new_month + 12) % 12;
16133 // For magnitudes >1, move one month at a time...
16134 for (var i=0; i<mag; i++)
16135 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
16136 new_date = this.moveMonth(new_date, dir);
16137 // ...then reset the day, keeping it in the new month
16138 new_month = new_date.getUTCMonth();
16139 new_date.setUTCDate(day);
16141 return new_month != new_date.getUTCMonth();
16144 // Common date-resetting loop -- if date is beyond end of month, make it
16147 new_date.setUTCDate(--day);
16148 new_date.setUTCMonth(new_month);
16153 moveYear: function(date, dir)
16155 return this.moveMonth(date, dir*12);
16158 dateWithinRange: function(date)
16160 return date >= this.startDate && date <= this.endDate;
16166 this.picker().remove();
16171 Roo.apply(Roo.bootstrap.DateField, {
16182 html: '<i class="fa fa-arrow-left"/>'
16192 html: '<i class="fa fa-arrow-right"/>'
16234 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
16235 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
16236 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
16237 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
16238 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
16251 navFnc: 'FullYear',
16256 navFnc: 'FullYear',
16261 Roo.apply(Roo.bootstrap.DateField, {
16265 cls: 'datepicker dropdown-menu roo-dynamic',
16269 cls: 'datepicker-days',
16273 cls: 'table-condensed',
16275 Roo.bootstrap.DateField.head,
16279 Roo.bootstrap.DateField.footer
16286 cls: 'datepicker-months',
16290 cls: 'table-condensed',
16292 Roo.bootstrap.DateField.head,
16293 Roo.bootstrap.DateField.content,
16294 Roo.bootstrap.DateField.footer
16301 cls: 'datepicker-years',
16305 cls: 'table-condensed',
16307 Roo.bootstrap.DateField.head,
16308 Roo.bootstrap.DateField.content,
16309 Roo.bootstrap.DateField.footer
16328 * @class Roo.bootstrap.TimeField
16329 * @extends Roo.bootstrap.Input
16330 * Bootstrap DateField class
16334 * Create a new TimeField
16335 * @param {Object} config The config object
16338 Roo.bootstrap.TimeField = function(config){
16339 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
16343 * Fires when this field show.
16344 * @param {Roo.bootstrap.DateField} thisthis
16345 * @param {Mixed} date The date value
16350 * Fires when this field hide.
16351 * @param {Roo.bootstrap.DateField} this
16352 * @param {Mixed} date The date value
16357 * Fires when select a date.
16358 * @param {Roo.bootstrap.DateField} this
16359 * @param {Mixed} date The date value
16365 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
16368 * @cfg {String} format
16369 * The default time format string which can be overriden for localization support. The format must be
16370 * valid according to {@link Date#parseDate} (defaults to 'H:i').
16374 onRender: function(ct, position)
16377 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
16379 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
16381 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16383 this.pop = this.picker().select('>.datepicker-time',true).first();
16384 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16386 this.picker().on('mousedown', this.onMousedown, this);
16387 this.picker().on('click', this.onClick, this);
16389 this.picker().addClass('datepicker-dropdown');
16394 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
16395 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
16396 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
16397 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
16398 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
16399 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
16403 fireKey: function(e){
16404 if (!this.picker().isVisible()){
16405 if (e.keyCode == 27) { // allow escape to hide and re-show picker
16411 e.preventDefault();
16419 this.onTogglePeriod();
16422 this.onIncrementMinutes();
16425 this.onDecrementMinutes();
16434 onClick: function(e) {
16435 e.stopPropagation();
16436 e.preventDefault();
16439 picker : function()
16441 return this.el.select('.datepicker', true).first();
16444 fillTime: function()
16446 var time = this.pop.select('tbody', true).first();
16448 time.dom.innerHTML = '';
16463 cls: 'hours-up glyphicon glyphicon-chevron-up'
16483 cls: 'minutes-up glyphicon glyphicon-chevron-up'
16504 cls: 'timepicker-hour',
16519 cls: 'timepicker-minute',
16534 cls: 'btn btn-primary period',
16556 cls: 'hours-down glyphicon glyphicon-chevron-down'
16576 cls: 'minutes-down glyphicon glyphicon-chevron-down'
16594 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
16601 var hours = this.time.getHours();
16602 var minutes = this.time.getMinutes();
16615 hours = hours - 12;
16619 hours = '0' + hours;
16623 minutes = '0' + minutes;
16626 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
16627 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
16628 this.pop.select('button', true).first().dom.innerHTML = period;
16634 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
16636 var cls = ['bottom'];
16638 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
16645 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
16650 this.picker().addClass(cls.join('-'));
16654 Roo.each(cls, function(c){
16656 _this.picker().setTop(_this.inputEl().getHeight());
16660 _this.picker().setTop(0 - _this.picker().getHeight());
16665 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
16669 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
16676 onFocus : function()
16678 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
16682 onBlur : function()
16684 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
16690 this.picker().show();
16695 this.fireEvent('show', this, this.date);
16700 this.picker().hide();
16703 this.fireEvent('hide', this, this.date);
16706 setTime : function()
16709 this.setValue(this.time.format(this.format));
16711 this.fireEvent('select', this, this.date);
16716 onMousedown: function(e){
16717 e.stopPropagation();
16718 e.preventDefault();
16721 onIncrementHours: function()
16723 Roo.log('onIncrementHours');
16724 this.time = this.time.add(Date.HOUR, 1);
16729 onDecrementHours: function()
16731 Roo.log('onDecrementHours');
16732 this.time = this.time.add(Date.HOUR, -1);
16736 onIncrementMinutes: function()
16738 Roo.log('onIncrementMinutes');
16739 this.time = this.time.add(Date.MINUTE, 1);
16743 onDecrementMinutes: function()
16745 Roo.log('onDecrementMinutes');
16746 this.time = this.time.add(Date.MINUTE, -1);
16750 onTogglePeriod: function()
16752 Roo.log('onTogglePeriod');
16753 this.time = this.time.add(Date.HOUR, 12);
16760 Roo.apply(Roo.bootstrap.TimeField, {
16790 cls: 'btn btn-info ok',
16802 Roo.apply(Roo.bootstrap.TimeField, {
16806 cls: 'datepicker dropdown-menu',
16810 cls: 'datepicker-time',
16814 cls: 'table-condensed',
16816 Roo.bootstrap.TimeField.content,
16817 Roo.bootstrap.TimeField.footer
16836 * @class Roo.bootstrap.MonthField
16837 * @extends Roo.bootstrap.Input
16838 * Bootstrap MonthField class
16840 * @cfg {String} language default en
16843 * Create a new MonthField
16844 * @param {Object} config The config object
16847 Roo.bootstrap.MonthField = function(config){
16848 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
16853 * Fires when this field show.
16854 * @param {Roo.bootstrap.MonthField} this
16855 * @param {Mixed} date The date value
16860 * Fires when this field hide.
16861 * @param {Roo.bootstrap.MonthField} this
16862 * @param {Mixed} date The date value
16867 * Fires when select a date.
16868 * @param {Roo.bootstrap.MonthField} this
16869 * @param {String} oldvalue The old value
16870 * @param {String} newvalue The new value
16876 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
16878 onRender: function(ct, position)
16881 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
16883 this.language = this.language || 'en';
16884 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
16885 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
16887 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
16888 this.isInline = false;
16889 this.isInput = true;
16890 this.component = this.el.select('.add-on', true).first() || false;
16891 this.component = (this.component && this.component.length === 0) ? false : this.component;
16892 this.hasInput = this.component && this.inputEL().length;
16894 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
16896 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
16898 this.picker().on('mousedown', this.onMousedown, this);
16899 this.picker().on('click', this.onClick, this);
16901 this.picker().addClass('datepicker-dropdown');
16903 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
16904 v.setStyle('width', '189px');
16911 if(this.isInline) {
16917 setValue: function(v, suppressEvent)
16919 var o = this.getValue();
16921 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
16925 if(suppressEvent !== true){
16926 this.fireEvent('select', this, o, v);
16931 getValue: function()
16936 onClick: function(e)
16938 e.stopPropagation();
16939 e.preventDefault();
16941 var target = e.getTarget();
16943 if(target.nodeName.toLowerCase() === 'i'){
16944 target = Roo.get(target).dom.parentNode;
16947 var nodeName = target.nodeName;
16948 var className = target.className;
16949 var html = target.innerHTML;
16951 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
16955 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
16957 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
16963 picker : function()
16965 return this.pickerEl;
16968 fillMonths: function()
16971 var months = this.picker().select('>.datepicker-months td', true).first();
16973 months.dom.innerHTML = '';
16979 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
16982 months.createChild(month);
16991 if(typeof(this.vIndex) == 'undefined' && this.value.length){
16992 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
16995 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
16996 e.removeClass('active');
16998 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
16999 e.addClass('active');
17006 if(this.isInline) return;
17008 this.picker().removeClass(['bottom', 'top']);
17010 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
17012 * place to the top of element!
17016 this.picker().addClass('top');
17017 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
17022 this.picker().addClass('bottom');
17024 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
17027 onFocus : function()
17029 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
17033 onBlur : function()
17035 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
17037 var d = this.inputEl().getValue();
17046 this.picker().show();
17047 this.picker().select('>.datepicker-months', true).first().show();
17051 this.fireEvent('show', this, this.date);
17056 if(this.isInline) return;
17057 this.picker().hide();
17058 this.fireEvent('hide', this, this.date);
17062 onMousedown: function(e)
17064 e.stopPropagation();
17065 e.preventDefault();
17070 Roo.bootstrap.MonthField.superclass.keyup.call(this);
17074 fireKey: function(e)
17076 if (!this.picker().isVisible()){
17077 if (e.keyCode == 27) // allow escape to hide and re-show picker
17087 e.preventDefault();
17091 dir = e.keyCode == 37 ? -1 : 1;
17093 this.vIndex = this.vIndex + dir;
17095 if(this.vIndex < 0){
17099 if(this.vIndex > 11){
17103 if(isNaN(this.vIndex)){
17107 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17113 dir = e.keyCode == 38 ? -1 : 1;
17115 this.vIndex = this.vIndex + dir * 4;
17117 if(this.vIndex < 0){
17121 if(this.vIndex > 11){
17125 if(isNaN(this.vIndex)){
17129 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17134 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17135 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17139 e.preventDefault();
17142 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
17143 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
17159 this.picker().remove();
17164 Roo.apply(Roo.bootstrap.MonthField, {
17183 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
17184 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
17189 Roo.apply(Roo.bootstrap.MonthField, {
17193 cls: 'datepicker dropdown-menu roo-dynamic',
17197 cls: 'datepicker-months',
17201 cls: 'table-condensed',
17203 Roo.bootstrap.DateField.content
17223 * @class Roo.bootstrap.CheckBox
17224 * @extends Roo.bootstrap.Input
17225 * Bootstrap CheckBox class
17227 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
17228 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
17229 * @cfg {String} boxLabel The text that appears beside the checkbox
17230 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
17231 * @cfg {Boolean} checked initnal the element
17232 * @cfg {Boolean} inline inline the element (default false)
17233 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
17236 * Create a new CheckBox
17237 * @param {Object} config The config object
17240 Roo.bootstrap.CheckBox = function(config){
17241 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
17246 * Fires when the element is checked or unchecked.
17247 * @param {Roo.bootstrap.CheckBox} this This input
17248 * @param {Boolean} checked The new checked value
17255 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
17257 inputType: 'checkbox',
17265 getAutoCreate : function()
17267 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17273 cfg.cls = 'form-group ' + this.inputType; //input-group
17276 cfg.cls += ' ' + this.inputType + '-inline';
17282 type : this.inputType,
17283 value : this.inputType == 'radio' ? this.inputValue : ((!this.checked) ? this.valueOff : this.inputValue),
17284 cls : 'roo-' + this.inputType, //'form-box',
17285 placeholder : this.placeholder || ''
17289 if (this.weight) { // Validity check?
17290 cfg.cls += " " + this.inputType + "-" + this.weight;
17293 if (this.disabled) {
17294 input.disabled=true;
17298 input.checked = this.checked;
17302 input.name = this.name;
17306 input.cls += ' input-' + this.size;
17311 ['xs','sm','md','lg'].map(function(size){
17312 if (settings[size]) {
17313 cfg.cls += ' col-' + size + '-' + settings[size];
17317 var inputblock = input;
17319 if (this.before || this.after) {
17322 cls : 'input-group',
17327 inputblock.cn.push({
17329 cls : 'input-group-addon',
17334 inputblock.cn.push(input);
17337 inputblock.cn.push({
17339 cls : 'input-group-addon',
17346 if (align ==='left' && this.fieldLabel.length) {
17347 Roo.log("left and has label");
17353 cls : 'control-label col-md-' + this.labelWidth,
17354 html : this.fieldLabel
17358 cls : "col-md-" + (12 - this.labelWidth),
17365 } else if ( this.fieldLabel.length) {
17370 tag: this.boxLabel ? 'span' : 'label',
17372 cls: 'control-label box-input-label',
17373 //cls : 'input-group-addon',
17374 html : this.fieldLabel
17384 Roo.log(" no label && no align");
17385 cfg.cn = [ inputblock ] ;
17390 var boxLabelCfg = {
17392 //'for': id, // box label is handled by onclick - so no for...
17394 html: this.boxLabel
17398 boxLabelCfg.tooltip = this.tooltip;
17401 cfg.cn.push(boxLabelCfg);
17411 * return the real input element.
17413 inputEl: function ()
17415 return this.el.select('input.roo-' + this.inputType,true).first();
17418 labelEl: function()
17420 return this.el.select('label.control-label',true).first();
17422 /* depricated... */
17426 return this.labelEl();
17429 initEvents : function()
17431 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17433 this.inputEl().on('click', this.onClick, this);
17435 if (this.boxLabel) {
17436 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
17439 this.startValue = this.getValue();
17442 Roo.bootstrap.CheckBox.register(this);
17446 onClick : function()
17448 this.setChecked(!this.checked);
17451 setChecked : function(state,suppressEvent)
17453 this.startValue = this.getValue();
17455 if(this.inputType == 'radio'){
17457 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17458 e.dom.checked = false;
17461 this.inputEl().dom.checked = true;
17463 this.inputEl().dom.value = this.inputValue;
17465 if(suppressEvent !== true){
17466 this.fireEvent('check', this, true);
17474 this.checked = state;
17476 this.inputEl().dom.checked = state;
17478 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17480 if(suppressEvent !== true){
17481 this.fireEvent('check', this, state);
17487 getValue : function()
17489 if(this.inputType == 'radio'){
17490 return this.getGroupValue();
17493 return this.inputEl().getValue();
17497 getGroupValue : function()
17499 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
17503 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
17506 setValue : function(v,suppressEvent)
17508 if(this.inputType == 'radio'){
17509 this.setGroupValue(v, suppressEvent);
17513 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
17518 setGroupValue : function(v, suppressEvent)
17520 this.startValue = this.getValue();
17522 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17523 e.dom.checked = false;
17525 if(e.dom.value == v){
17526 e.dom.checked = true;
17530 if(suppressEvent !== true){
17531 this.fireEvent('check', this, true);
17539 validate : function()
17543 (this.inputType == 'radio' && this.validateRadio()) ||
17544 (this.inputType == 'checkbox' && this.validateCheckbox())
17550 this.markInvalid();
17554 validateRadio : function()
17558 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17559 if(!e.dom.checked){
17571 validateCheckbox : function()
17574 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
17577 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17585 for(var i in group){
17590 r = (group[i].getValue() == group[i].inputValue) ? true : false;
17597 * Mark this field as valid
17599 markValid : function()
17601 if(this.allowBlank){
17607 this.fireEvent('valid', this);
17609 if(this.inputType == 'radio'){
17610 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17611 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17612 e.findParent('.form-group', false, true).addClass(_this.validClass);
17619 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17620 this.el.findParent('.form-group', false, true).addClass(this.validClass);
17624 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17630 for(var i in group){
17631 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17632 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
17637 * Mark this field as invalid
17638 * @param {String} msg The validation message
17640 markInvalid : function(msg)
17642 if(this.allowBlank){
17648 this.fireEvent('invalid', this, msg);
17650 if(this.inputType == 'radio'){
17651 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
17652 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
17653 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
17660 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17661 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
17665 var group = Roo.bootstrap.CheckBox.get(this.groupId);
17671 for(var i in group){
17672 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
17673 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
17680 Roo.apply(Roo.bootstrap.CheckBox, {
17685 * register a CheckBox Group
17686 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
17688 register : function(checkbox)
17690 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
17691 this.groups[checkbox.groupId] = {};
17694 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
17698 this.groups[checkbox.groupId][checkbox.name] = checkbox;
17702 * fetch a CheckBox Group based on the group ID
17703 * @param {string} the group ID
17704 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
17706 get: function(groupId) {
17707 if (typeof(this.groups[groupId]) == 'undefined') {
17711 return this.groups[groupId] ;
17723 *<div class="radio">
17725 <input type="radio" name="optionsRadios" id="optionsRadios1" value="option1" checked>
17726 Option one is this and that—be sure to include why it's great
17733 *<label class="radio-inline">fieldLabel</label>
17734 *<label class="radio-inline">
17735 <input type="radio" name="inlineRadioOptions" id="inlineRadio1" value="option1"> 1
17743 * @class Roo.bootstrap.Radio
17744 * @extends Roo.bootstrap.CheckBox
17745 * Bootstrap Radio class
17748 * Create a new Radio
17749 * @param {Object} config The config object
17752 Roo.bootstrap.Radio = function(config){
17753 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
17757 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
17759 inputType: 'radio',
17763 getAutoCreate : function()
17765 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
17766 align = align || 'left'; // default...
17773 tag : this.inline ? 'span' : 'div',
17778 var inline = this.inline ? ' radio-inline' : '';
17782 // does not need for, as we wrap the input with it..
17784 cls : 'control-label box-label' + inline,
17787 var labelWidth = this.labelWidth ? this.labelWidth *1 : 100;
17791 //cls : 'control-label' + inline,
17792 html : this.fieldLabel,
17793 style : 'width:' + labelWidth + 'px;line-height:1;vertical-align:bottom;cursor:default;' // should be css really.
17802 type : this.inputType,
17803 //value : (!this.checked) ? this.valueOff : this.inputValue,
17804 value : this.inputValue,
17806 placeholder : this.placeholder || '' // ?? needed????
17809 if (this.weight) { // Validity check?
17810 input.cls += " radio-" + this.weight;
17812 if (this.disabled) {
17813 input.disabled=true;
17817 input.checked = this.checked;
17821 input.name = this.name;
17825 input.cls += ' input-' + this.size;
17828 //?? can span's inline have a width??
17831 ['xs','sm','md','lg'].map(function(size){
17832 if (settings[size]) {
17833 cfg.cls += ' col-' + size + '-' + settings[size];
17837 var inputblock = input;
17839 if (this.before || this.after) {
17842 cls : 'input-group',
17847 inputblock.cn.push({
17849 cls : 'input-group-addon',
17853 inputblock.cn.push(input);
17855 inputblock.cn.push({
17857 cls : 'input-group-addon',
17865 if (this.fieldLabel && this.fieldLabel.length) {
17866 cfg.cn.push(fieldLabel);
17869 // normal bootstrap puts the input inside the label.
17870 // however with our styled version - it has to go after the input.
17872 //lbl.cn.push(inputblock);
17876 cls: 'radio' + inline,
17883 cfg.cn.push( lblwrap);
17888 html: this.boxLabel
17897 initEvents : function()
17899 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
17901 this.inputEl().on('click', this.onClick, this);
17902 if (this.boxLabel) {
17903 Roo.log('find label')
17904 this.el.select('span.radio label span',true).first().on('click', this.onClick, this);
17909 inputEl: function ()
17911 return this.el.select('input.roo-radio',true).first();
17913 onClick : function()
17916 this.setChecked(true);
17919 setChecked : function(state,suppressEvent)
17922 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17923 v.dom.checked = false;
17926 Roo.log(this.inputEl().dom);
17927 this.checked = state;
17928 this.inputEl().dom.checked = state;
17930 if(suppressEvent !== true){
17931 this.fireEvent('check', this, state);
17934 //this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
17938 getGroupValue : function()
17941 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
17942 if(v.dom.checked == true){
17943 value = v.dom.value;
17951 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
17952 * @return {Mixed} value The field value
17954 getValue : function(){
17955 return this.getGroupValue();
17961 //<script type="text/javascript">
17964 * Based Ext JS Library 1.1.1
17965 * Copyright(c) 2006-2007, Ext JS, LLC.
17971 * @class Roo.HtmlEditorCore
17972 * @extends Roo.Component
17973 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
17975 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
17978 Roo.HtmlEditorCore = function(config){
17981 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
17986 * @event initialize
17987 * Fires when the editor is fully initialized (including the iframe)
17988 * @param {Roo.HtmlEditorCore} this
17993 * Fires when the editor is first receives the focus. Any insertion must wait
17994 * until after this event.
17995 * @param {Roo.HtmlEditorCore} this
17999 * @event beforesync
18000 * Fires before the textarea is updated with content from the editor iframe. Return false
18001 * to cancel the sync.
18002 * @param {Roo.HtmlEditorCore} this
18003 * @param {String} html
18007 * @event beforepush
18008 * Fires before the iframe editor is updated with content from the textarea. Return false
18009 * to cancel the push.
18010 * @param {Roo.HtmlEditorCore} this
18011 * @param {String} html
18016 * Fires when the textarea is updated with content from the editor iframe.
18017 * @param {Roo.HtmlEditorCore} this
18018 * @param {String} html
18023 * Fires when the iframe editor is updated with content from the textarea.
18024 * @param {Roo.HtmlEditorCore} this
18025 * @param {String} html
18030 * @event editorevent
18031 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
18032 * @param {Roo.HtmlEditorCore} this
18038 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
18040 // defaults : white / black...
18041 this.applyBlacklists();
18048 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
18052 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
18058 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
18063 * @cfg {Number} height (in pixels)
18067 * @cfg {Number} width (in pixels)
18072 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
18075 stylesheets: false,
18080 // private properties
18081 validationEvent : false,
18083 initialized : false,
18085 sourceEditMode : false,
18086 onFocus : Roo.emptyFn,
18088 hideMode:'offsets',
18092 // blacklist + whitelisted elements..
18099 * Protected method that will not generally be called directly. It
18100 * is called when the editor initializes the iframe with HTML contents. Override this method if you
18101 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
18103 getDocMarkup : function(){
18107 // inherit styels from page...??
18108 if (this.stylesheets === false) {
18110 Roo.get(document.head).select('style').each(function(node) {
18111 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18114 Roo.get(document.head).select('link').each(function(node) {
18115 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
18118 } else if (!this.stylesheets.length) {
18120 st = '<style type="text/css">' +
18121 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18127 st += '<style type="text/css">' +
18128 'IMG { cursor: pointer } ' +
18132 return '<html><head>' + st +
18133 //<style type="text/css">' +
18134 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
18136 ' </head><body class="roo-htmleditor-body"></body></html>';
18140 onRender : function(ct, position)
18143 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
18144 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
18147 this.el.dom.style.border = '0 none';
18148 this.el.dom.setAttribute('tabIndex', -1);
18149 this.el.addClass('x-hidden hide');
18153 if(Roo.isIE){ // fix IE 1px bogus margin
18154 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
18158 this.frameId = Roo.id();
18162 var iframe = this.owner.wrap.createChild({
18164 cls: 'form-control', // bootstrap..
18166 name: this.frameId,
18167 frameBorder : 'no',
18168 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
18173 this.iframe = iframe.dom;
18175 this.assignDocWin();
18177 this.doc.designMode = 'on';
18180 this.doc.write(this.getDocMarkup());
18184 var task = { // must defer to wait for browser to be ready
18186 //console.log("run task?" + this.doc.readyState);
18187 this.assignDocWin();
18188 if(this.doc.body || this.doc.readyState == 'complete'){
18190 this.doc.designMode="on";
18194 Roo.TaskMgr.stop(task);
18195 this.initEditor.defer(10, this);
18202 Roo.TaskMgr.start(task);
18207 onResize : function(w, h)
18209 Roo.log('resize: ' +w + ',' + h );
18210 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
18214 if(typeof w == 'number'){
18216 this.iframe.style.width = w + 'px';
18218 if(typeof h == 'number'){
18220 this.iframe.style.height = h + 'px';
18222 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
18229 * Toggles the editor between standard and source edit mode.
18230 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
18232 toggleSourceEdit : function(sourceEditMode){
18234 this.sourceEditMode = sourceEditMode === true;
18236 if(this.sourceEditMode){
18238 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
18241 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
18242 //this.iframe.className = '';
18245 //this.setSize(this.owner.wrap.getSize());
18246 //this.fireEvent('editmodechange', this, this.sourceEditMode);
18253 * Protected method that will not generally be called directly. If you need/want
18254 * custom HTML cleanup, this is the method you should override.
18255 * @param {String} html The HTML to be cleaned
18256 * return {String} The cleaned HTML
18258 cleanHtml : function(html){
18259 html = String(html);
18260 if(html.length > 5){
18261 if(Roo.isSafari){ // strip safari nonsense
18262 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
18265 if(html == ' '){
18272 * HTML Editor -> Textarea
18273 * Protected method that will not generally be called directly. Syncs the contents
18274 * of the editor iframe with the textarea.
18276 syncValue : function(){
18277 if(this.initialized){
18278 var bd = (this.doc.body || this.doc.documentElement);
18279 //this.cleanUpPaste(); -- this is done else where and causes havoc..
18280 var html = bd.innerHTML;
18282 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
18283 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
18285 html = '<div style="'+m[0]+'">' + html + '</div>';
18288 html = this.cleanHtml(html);
18289 // fix up the special chars.. normaly like back quotes in word...
18290 // however we do not want to do this with chinese..
18291 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
18292 var cc = b.charCodeAt();
18294 (cc >= 0x4E00 && cc < 0xA000 ) ||
18295 (cc >= 0x3400 && cc < 0x4E00 ) ||
18296 (cc >= 0xf900 && cc < 0xfb00 )
18302 if(this.owner.fireEvent('beforesync', this, html) !== false){
18303 this.el.dom.value = html;
18304 this.owner.fireEvent('sync', this, html);
18310 * Protected method that will not generally be called directly. Pushes the value of the textarea
18311 * into the iframe editor.
18313 pushValue : function(){
18314 if(this.initialized){
18315 var v = this.el.dom.value.trim();
18317 // if(v.length < 1){
18321 if(this.owner.fireEvent('beforepush', this, v) !== false){
18322 var d = (this.doc.body || this.doc.documentElement);
18324 this.cleanUpPaste();
18325 this.el.dom.value = d.innerHTML;
18326 this.owner.fireEvent('push', this, v);
18332 deferFocus : function(){
18333 this.focus.defer(10, this);
18337 focus : function(){
18338 if(this.win && !this.sourceEditMode){
18345 assignDocWin: function()
18347 var iframe = this.iframe;
18350 this.doc = iframe.contentWindow.document;
18351 this.win = iframe.contentWindow;
18353 // if (!Roo.get(this.frameId)) {
18356 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18357 // this.win = Roo.get(this.frameId).dom.contentWindow;
18359 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
18363 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
18364 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
18369 initEditor : function(){
18370 //console.log("INIT EDITOR");
18371 this.assignDocWin();
18375 this.doc.designMode="on";
18377 this.doc.write(this.getDocMarkup());
18380 var dbody = (this.doc.body || this.doc.documentElement);
18381 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
18382 // this copies styles from the containing element into thsi one..
18383 // not sure why we need all of this..
18384 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
18386 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
18387 //ss['background-attachment'] = 'fixed'; // w3c
18388 dbody.bgProperties = 'fixed'; // ie
18389 //Roo.DomHelper.applyStyles(dbody, ss);
18390 Roo.EventManager.on(this.doc, {
18391 //'mousedown': this.onEditorEvent,
18392 'mouseup': this.onEditorEvent,
18393 'dblclick': this.onEditorEvent,
18394 'click': this.onEditorEvent,
18395 'keyup': this.onEditorEvent,
18400 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
18402 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
18403 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
18405 this.initialized = true;
18407 this.owner.fireEvent('initialize', this);
18412 onDestroy : function(){
18418 //for (var i =0; i < this.toolbars.length;i++) {
18419 // // fixme - ask toolbars for heights?
18420 // this.toolbars[i].onDestroy();
18423 //this.wrap.dom.innerHTML = '';
18424 //this.wrap.remove();
18429 onFirstFocus : function(){
18431 this.assignDocWin();
18434 this.activated = true;
18437 if(Roo.isGecko){ // prevent silly gecko errors
18439 var s = this.win.getSelection();
18440 if(!s.focusNode || s.focusNode.nodeType != 3){
18441 var r = s.getRangeAt(0);
18442 r.selectNodeContents((this.doc.body || this.doc.documentElement));
18447 this.execCmd('useCSS', true);
18448 this.execCmd('styleWithCSS', false);
18451 this.owner.fireEvent('activate', this);
18455 adjustFont: function(btn){
18456 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
18457 //if(Roo.isSafari){ // safari
18460 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
18461 if(Roo.isSafari){ // safari
18462 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
18463 v = (v < 10) ? 10 : v;
18464 v = (v > 48) ? 48 : v;
18465 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
18470 v = Math.max(1, v+adjust);
18472 this.execCmd('FontSize', v );
18475 onEditorEvent : function(e)
18477 this.owner.fireEvent('editorevent', this, e);
18478 // this.updateToolbar();
18479 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
18482 insertTag : function(tg)
18484 // could be a bit smarter... -> wrap the current selected tRoo..
18485 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
18487 range = this.createRange(this.getSelection());
18488 var wrappingNode = this.doc.createElement(tg.toLowerCase());
18489 wrappingNode.appendChild(range.extractContents());
18490 range.insertNode(wrappingNode);
18497 this.execCmd("formatblock", tg);
18501 insertText : function(txt)
18505 var range = this.createRange();
18506 range.deleteContents();
18507 //alert(Sender.getAttribute('label'));
18509 range.insertNode(this.doc.createTextNode(txt));
18515 * Executes a Midas editor command on the editor document and performs necessary focus and
18516 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
18517 * @param {String} cmd The Midas command
18518 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18520 relayCmd : function(cmd, value){
18522 this.execCmd(cmd, value);
18523 this.owner.fireEvent('editorevent', this);
18524 //this.updateToolbar();
18525 this.owner.deferFocus();
18529 * Executes a Midas editor command directly on the editor document.
18530 * For visual commands, you should use {@link #relayCmd} instead.
18531 * <b>This should only be called after the editor is initialized.</b>
18532 * @param {String} cmd The Midas command
18533 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
18535 execCmd : function(cmd, value){
18536 this.doc.execCommand(cmd, false, value === undefined ? null : value);
18543 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
18545 * @param {String} text | dom node..
18547 insertAtCursor : function(text)
18552 if(!this.activated){
18558 var r = this.doc.selection.createRange();
18569 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
18573 // from jquery ui (MIT licenced)
18575 var win = this.win;
18577 if (win.getSelection && win.getSelection().getRangeAt) {
18578 range = win.getSelection().getRangeAt(0);
18579 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
18580 range.insertNode(node);
18581 } else if (win.document.selection && win.document.selection.createRange) {
18582 // no firefox support
18583 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18584 win.document.selection.createRange().pasteHTML(txt);
18586 // no firefox support
18587 var txt = typeof(text) == 'string' ? text : text.outerHTML;
18588 this.execCmd('InsertHTML', txt);
18597 mozKeyPress : function(e){
18599 var c = e.getCharCode(), cmd;
18602 c = String.fromCharCode(c).toLowerCase();
18616 this.cleanUpPaste.defer(100, this);
18624 e.preventDefault();
18632 fixKeys : function(){ // load time branching for fastest keydown performance
18634 return function(e){
18635 var k = e.getKey(), r;
18638 r = this.doc.selection.createRange();
18641 r.pasteHTML('    ');
18648 r = this.doc.selection.createRange();
18650 var target = r.parentElement();
18651 if(!target || target.tagName.toLowerCase() != 'li'){
18653 r.pasteHTML('<br />');
18659 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18660 this.cleanUpPaste.defer(100, this);
18666 }else if(Roo.isOpera){
18667 return function(e){
18668 var k = e.getKey();
18672 this.execCmd('InsertHTML','    ');
18675 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18676 this.cleanUpPaste.defer(100, this);
18681 }else if(Roo.isSafari){
18682 return function(e){
18683 var k = e.getKey();
18687 this.execCmd('InsertText','\t');
18691 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
18692 this.cleanUpPaste.defer(100, this);
18700 getAllAncestors: function()
18702 var p = this.getSelectedNode();
18705 a.push(p); // push blank onto stack..
18706 p = this.getParentElement();
18710 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
18714 a.push(this.doc.body);
18718 lastSelNode : false,
18721 getSelection : function()
18723 this.assignDocWin();
18724 return Roo.isIE ? this.doc.selection : this.win.getSelection();
18727 getSelectedNode: function()
18729 // this may only work on Gecko!!!
18731 // should we cache this!!!!
18736 var range = this.createRange(this.getSelection()).cloneRange();
18739 var parent = range.parentElement();
18741 var testRange = range.duplicate();
18742 testRange.moveToElementText(parent);
18743 if (testRange.inRange(range)) {
18746 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
18749 parent = parent.parentElement;
18754 // is ancestor a text element.
18755 var ac = range.commonAncestorContainer;
18756 if (ac.nodeType == 3) {
18757 ac = ac.parentNode;
18760 var ar = ac.childNodes;
18763 var other_nodes = [];
18764 var has_other_nodes = false;
18765 for (var i=0;i<ar.length;i++) {
18766 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
18769 // fullly contained node.
18771 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
18776 // probably selected..
18777 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
18778 other_nodes.push(ar[i]);
18782 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
18787 has_other_nodes = true;
18789 if (!nodes.length && other_nodes.length) {
18790 nodes= other_nodes;
18792 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
18798 createRange: function(sel)
18800 // this has strange effects when using with
18801 // top toolbar - not sure if it's a great idea.
18802 //this.editor.contentWindow.focus();
18803 if (typeof sel != "undefined") {
18805 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
18807 return this.doc.createRange();
18810 return this.doc.createRange();
18813 getParentElement: function()
18816 this.assignDocWin();
18817 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
18819 var range = this.createRange(sel);
18822 var p = range.commonAncestorContainer;
18823 while (p.nodeType == 3) { // text node
18834 * Range intersection.. the hard stuff...
18838 * [ -- selected range --- ]
18842 * if end is before start or hits it. fail.
18843 * if start is after end or hits it fail.
18845 * if either hits (but other is outside. - then it's not
18851 // @see http://www.thismuchiknow.co.uk/?p=64.
18852 rangeIntersectsNode : function(range, node)
18854 var nodeRange = node.ownerDocument.createRange();
18856 nodeRange.selectNode(node);
18858 nodeRange.selectNodeContents(node);
18861 var rangeStartRange = range.cloneRange();
18862 rangeStartRange.collapse(true);
18864 var rangeEndRange = range.cloneRange();
18865 rangeEndRange.collapse(false);
18867 var nodeStartRange = nodeRange.cloneRange();
18868 nodeStartRange.collapse(true);
18870 var nodeEndRange = nodeRange.cloneRange();
18871 nodeEndRange.collapse(false);
18873 return rangeStartRange.compareBoundaryPoints(
18874 Range.START_TO_START, nodeEndRange) == -1 &&
18875 rangeEndRange.compareBoundaryPoints(
18876 Range.START_TO_START, nodeStartRange) == 1;
18880 rangeCompareNode : function(range, node)
18882 var nodeRange = node.ownerDocument.createRange();
18884 nodeRange.selectNode(node);
18886 nodeRange.selectNodeContents(node);
18890 range.collapse(true);
18892 nodeRange.collapse(true);
18894 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
18895 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
18897 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
18899 var nodeIsBefore = ss == 1;
18900 var nodeIsAfter = ee == -1;
18902 if (nodeIsBefore && nodeIsAfter)
18904 if (!nodeIsBefore && nodeIsAfter)
18905 return 1; //right trailed.
18907 if (nodeIsBefore && !nodeIsAfter)
18908 return 2; // left trailed.
18913 // private? - in a new class?
18914 cleanUpPaste : function()
18916 // cleans up the whole document..
18917 Roo.log('cleanuppaste');
18919 this.cleanUpChildren(this.doc.body);
18920 var clean = this.cleanWordChars(this.doc.body.innerHTML);
18921 if (clean != this.doc.body.innerHTML) {
18922 this.doc.body.innerHTML = clean;
18927 cleanWordChars : function(input) {// change the chars to hex code
18928 var he = Roo.HtmlEditorCore;
18930 var output = input;
18931 Roo.each(he.swapCodes, function(sw) {
18932 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
18934 output = output.replace(swapper, sw[1]);
18941 cleanUpChildren : function (n)
18943 if (!n.childNodes.length) {
18946 for (var i = n.childNodes.length-1; i > -1 ; i--) {
18947 this.cleanUpChild(n.childNodes[i]);
18954 cleanUpChild : function (node)
18957 //console.log(node);
18958 if (node.nodeName == "#text") {
18959 // clean up silly Windows -- stuff?
18962 if (node.nodeName == "#comment") {
18963 node.parentNode.removeChild(node);
18964 // clean up silly Windows -- stuff?
18967 var lcname = node.tagName.toLowerCase();
18968 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
18969 // whitelist of tags..
18971 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
18973 node.parentNode.removeChild(node);
18978 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
18980 // remove <a name=....> as rendering on yahoo mailer is borked with this.
18981 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
18983 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
18984 // remove_keep_children = true;
18987 if (remove_keep_children) {
18988 this.cleanUpChildren(node);
18989 // inserts everything just before this node...
18990 while (node.childNodes.length) {
18991 var cn = node.childNodes[0];
18992 node.removeChild(cn);
18993 node.parentNode.insertBefore(cn, node);
18995 node.parentNode.removeChild(node);
18999 if (!node.attributes || !node.attributes.length) {
19000 this.cleanUpChildren(node);
19004 function cleanAttr(n,v)
19007 if (v.match(/^\./) || v.match(/^\//)) {
19010 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
19013 if (v.match(/^#/)) {
19016 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
19017 node.removeAttribute(n);
19021 var cwhite = this.cwhite;
19022 var cblack = this.cblack;
19024 function cleanStyle(n,v)
19026 if (v.match(/expression/)) { //XSS?? should we even bother..
19027 node.removeAttribute(n);
19031 var parts = v.split(/;/);
19034 Roo.each(parts, function(p) {
19035 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
19039 var l = p.split(':').shift().replace(/\s+/g,'');
19040 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
19042 if ( cwhite.length && cblack.indexOf(l) > -1) {
19043 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19044 //node.removeAttribute(n);
19048 // only allow 'c whitelisted system attributes'
19049 if ( cwhite.length && cwhite.indexOf(l) < 0) {
19050 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
19051 //node.removeAttribute(n);
19061 if (clean.length) {
19062 node.setAttribute(n, clean.join(';'));
19064 node.removeAttribute(n);
19070 for (var i = node.attributes.length-1; i > -1 ; i--) {
19071 var a = node.attributes[i];
19074 if (a.name.toLowerCase().substr(0,2)=='on') {
19075 node.removeAttribute(a.name);
19078 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
19079 node.removeAttribute(a.name);
19082 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
19083 cleanAttr(a.name,a.value); // fixme..
19086 if (a.name == 'style') {
19087 cleanStyle(a.name,a.value);
19090 /// clean up MS crap..
19091 // tecnically this should be a list of valid class'es..
19094 if (a.name == 'class') {
19095 if (a.value.match(/^Mso/)) {
19096 node.className = '';
19099 if (a.value.match(/body/)) {
19100 node.className = '';
19111 this.cleanUpChildren(node);
19116 * Clean up MS wordisms...
19118 cleanWord : function(node)
19121 var cleanWordChildren = function()
19123 if (!node.childNodes.length) {
19126 for (var i = node.childNodes.length-1; i > -1 ; i--) {
19127 _t.cleanWord(node.childNodes[i]);
19133 this.cleanWord(this.doc.body);
19136 if (node.nodeName == "#text") {
19137 // clean up silly Windows -- stuff?
19140 if (node.nodeName == "#comment") {
19141 node.parentNode.removeChild(node);
19142 // clean up silly Windows -- stuff?
19146 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
19147 node.parentNode.removeChild(node);
19151 // remove - but keep children..
19152 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
19153 while (node.childNodes.length) {
19154 var cn = node.childNodes[0];
19155 node.removeChild(cn);
19156 node.parentNode.insertBefore(cn, node);
19158 node.parentNode.removeChild(node);
19159 cleanWordChildren();
19163 if (node.className.length) {
19165 var cn = node.className.split(/\W+/);
19167 Roo.each(cn, function(cls) {
19168 if (cls.match(/Mso[a-zA-Z]+/)) {
19173 node.className = cna.length ? cna.join(' ') : '';
19175 node.removeAttribute("class");
19179 if (node.hasAttribute("lang")) {
19180 node.removeAttribute("lang");
19183 if (node.hasAttribute("style")) {
19185 var styles = node.getAttribute("style").split(";");
19187 Roo.each(styles, function(s) {
19188 if (!s.match(/:/)) {
19191 var kv = s.split(":");
19192 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
19195 // what ever is left... we allow.
19198 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
19199 if (!nstyle.length) {
19200 node.removeAttribute('style');
19204 cleanWordChildren();
19208 domToHTML : function(currentElement, depth, nopadtext) {
19210 depth = depth || 0;
19211 nopadtext = nopadtext || false;
19213 if (!currentElement) {
19214 return this.domToHTML(this.doc.body);
19217 //Roo.log(currentElement);
19219 var allText = false;
19220 var nodeName = currentElement.nodeName;
19221 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
19223 if (nodeName == '#text') {
19225 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
19230 if (nodeName != 'BODY') {
19233 // Prints the node tagName, such as <A>, <IMG>, etc
19236 for(i = 0; i < currentElement.attributes.length;i++) {
19238 var aname = currentElement.attributes.item(i).name;
19239 if (!currentElement.attributes.item(i).value.length) {
19242 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
19245 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
19254 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
19257 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
19262 // Traverse the tree
19264 var currentElementChild = currentElement.childNodes.item(i);
19265 var allText = true;
19266 var innerHTML = '';
19268 while (currentElementChild) {
19269 // Formatting code (indent the tree so it looks nice on the screen)
19270 var nopad = nopadtext;
19271 if (lastnode == 'SPAN') {
19275 if (currentElementChild.nodeName == '#text') {
19276 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
19277 toadd = nopadtext ? toadd : toadd.trim();
19278 if (!nopad && toadd.length > 80) {
19279 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
19281 innerHTML += toadd;
19284 currentElementChild = currentElement.childNodes.item(i);
19290 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
19292 // Recursively traverse the tree structure of the child node
19293 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
19294 lastnode = currentElementChild.nodeName;
19296 currentElementChild=currentElement.childNodes.item(i);
19302 // The remaining code is mostly for formatting the tree
19303 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
19308 ret+= "</"+tagName+">";
19314 applyBlacklists : function()
19316 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
19317 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
19321 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
19322 if (b.indexOf(tag) > -1) {
19325 this.white.push(tag);
19329 Roo.each(w, function(tag) {
19330 if (b.indexOf(tag) > -1) {
19333 if (this.white.indexOf(tag) > -1) {
19336 this.white.push(tag);
19341 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
19342 if (w.indexOf(tag) > -1) {
19345 this.black.push(tag);
19349 Roo.each(b, function(tag) {
19350 if (w.indexOf(tag) > -1) {
19353 if (this.black.indexOf(tag) > -1) {
19356 this.black.push(tag);
19361 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
19362 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
19366 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
19367 if (b.indexOf(tag) > -1) {
19370 this.cwhite.push(tag);
19374 Roo.each(w, function(tag) {
19375 if (b.indexOf(tag) > -1) {
19378 if (this.cwhite.indexOf(tag) > -1) {
19381 this.cwhite.push(tag);
19386 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
19387 if (w.indexOf(tag) > -1) {
19390 this.cblack.push(tag);
19394 Roo.each(b, function(tag) {
19395 if (w.indexOf(tag) > -1) {
19398 if (this.cblack.indexOf(tag) > -1) {
19401 this.cblack.push(tag);
19406 setStylesheets : function(stylesheets)
19408 if(typeof(stylesheets) == 'string'){
19409 Roo.get(this.iframe.contentDocument.head).createChild({
19411 rel : 'stylesheet',
19420 Roo.each(stylesheets, function(s) {
19425 Roo.get(_this.iframe.contentDocument.head).createChild({
19427 rel : 'stylesheet',
19436 removeStylesheets : function()
19440 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
19445 // hide stuff that is not compatible
19459 * @event specialkey
19463 * @cfg {String} fieldClass @hide
19466 * @cfg {String} focusClass @hide
19469 * @cfg {String} autoCreate @hide
19472 * @cfg {String} inputType @hide
19475 * @cfg {String} invalidClass @hide
19478 * @cfg {String} invalidText @hide
19481 * @cfg {String} msgFx @hide
19484 * @cfg {String} validateOnBlur @hide
19488 Roo.HtmlEditorCore.white = [
19489 'area', 'br', 'img', 'input', 'hr', 'wbr',
19491 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
19492 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
19493 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
19494 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
19495 'table', 'ul', 'xmp',
19497 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
19500 'dir', 'menu', 'ol', 'ul', 'dl',
19506 Roo.HtmlEditorCore.black = [
19507 // 'embed', 'object', // enable - backend responsiblity to clean thiese
19509 'base', 'basefont', 'bgsound', 'blink', 'body',
19510 'frame', 'frameset', 'head', 'html', 'ilayer',
19511 'iframe', 'layer', 'link', 'meta', 'object',
19512 'script', 'style' ,'title', 'xml' // clean later..
19514 Roo.HtmlEditorCore.clean = [
19515 'script', 'style', 'title', 'xml'
19517 Roo.HtmlEditorCore.remove = [
19522 Roo.HtmlEditorCore.ablack = [
19526 Roo.HtmlEditorCore.aclean = [
19527 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
19531 Roo.HtmlEditorCore.pwhite= [
19532 'http', 'https', 'mailto'
19535 // white listed style attributes.
19536 Roo.HtmlEditorCore.cwhite= [
19537 // 'text-align', /// default is to allow most things..
19543 // black listed style attributes.
19544 Roo.HtmlEditorCore.cblack= [
19545 // 'font-size' -- this can be set by the project
19549 Roo.HtmlEditorCore.swapCodes =[
19568 * @class Roo.bootstrap.HtmlEditor
19569 * @extends Roo.bootstrap.TextArea
19570 * Bootstrap HtmlEditor class
19573 * Create a new HtmlEditor
19574 * @param {Object} config The config object
19577 Roo.bootstrap.HtmlEditor = function(config){
19578 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
19579 if (!this.toolbars) {
19580 this.toolbars = [];
19582 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
19585 * @event initialize
19586 * Fires when the editor is fully initialized (including the iframe)
19587 * @param {HtmlEditor} this
19592 * Fires when the editor is first receives the focus. Any insertion must wait
19593 * until after this event.
19594 * @param {HtmlEditor} this
19598 * @event beforesync
19599 * Fires before the textarea is updated with content from the editor iframe. Return false
19600 * to cancel the sync.
19601 * @param {HtmlEditor} this
19602 * @param {String} html
19606 * @event beforepush
19607 * Fires before the iframe editor is updated with content from the textarea. Return false
19608 * to cancel the push.
19609 * @param {HtmlEditor} this
19610 * @param {String} html
19615 * Fires when the textarea is updated with content from the editor iframe.
19616 * @param {HtmlEditor} this
19617 * @param {String} html
19622 * Fires when the iframe editor is updated with content from the textarea.
19623 * @param {HtmlEditor} this
19624 * @param {String} html
19628 * @event editmodechange
19629 * Fires when the editor switches edit modes
19630 * @param {HtmlEditor} this
19631 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
19633 editmodechange: true,
19635 * @event editorevent
19636 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
19637 * @param {HtmlEditor} this
19641 * @event firstfocus
19642 * Fires when on first focus - needed by toolbars..
19643 * @param {HtmlEditor} this
19648 * Auto save the htmlEditor value as a file into Events
19649 * @param {HtmlEditor} this
19653 * @event savedpreview
19654 * preview the saved version of htmlEditor
19655 * @param {HtmlEditor} this
19662 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
19666 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
19671 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
19676 * @cfg {Number} height (in pixels)
19680 * @cfg {Number} width (in pixels)
19685 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
19688 stylesheets: false,
19693 // private properties
19694 validationEvent : false,
19696 initialized : false,
19699 onFocus : Roo.emptyFn,
19701 hideMode:'offsets',
19704 tbContainer : false,
19706 toolbarContainer :function() {
19707 return this.wrap.select('.x-html-editor-tb',true).first();
19711 * Protected method that will not generally be called directly. It
19712 * is called when the editor creates its toolbar. Override this method if you need to
19713 * add custom toolbar buttons.
19714 * @param {HtmlEditor} editor
19716 createToolbar : function(){
19718 Roo.log("create toolbars");
19720 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
19721 this.toolbars[0].render(this.toolbarContainer());
19725 // if (!editor.toolbars || !editor.toolbars.length) {
19726 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
19729 // for (var i =0 ; i < editor.toolbars.length;i++) {
19730 // editor.toolbars[i] = Roo.factory(
19731 // typeof(editor.toolbars[i]) == 'string' ?
19732 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
19733 // Roo.bootstrap.HtmlEditor);
19734 // editor.toolbars[i].init(editor);
19740 onRender : function(ct, position)
19742 // Roo.log("Call onRender: " + this.xtype);
19744 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
19746 this.wrap = this.inputEl().wrap({
19747 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
19750 this.editorcore.onRender(ct, position);
19752 if (this.resizable) {
19753 this.resizeEl = new Roo.Resizable(this.wrap, {
19757 minHeight : this.height,
19758 height: this.height,
19759 handles : this.resizable,
19762 resize : function(r, w, h) {
19763 _t.onResize(w,h); // -something
19769 this.createToolbar(this);
19772 if(!this.width && this.resizable){
19773 this.setSize(this.wrap.getSize());
19775 if (this.resizeEl) {
19776 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
19777 // should trigger onReize..
19783 onResize : function(w, h)
19785 Roo.log('resize: ' +w + ',' + h );
19786 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
19790 if(this.inputEl() ){
19791 if(typeof w == 'number'){
19792 var aw = w - this.wrap.getFrameWidth('lr');
19793 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
19796 if(typeof h == 'number'){
19797 var tbh = -11; // fixme it needs to tool bar size!
19798 for (var i =0; i < this.toolbars.length;i++) {
19799 // fixme - ask toolbars for heights?
19800 tbh += this.toolbars[i].el.getHeight();
19801 //if (this.toolbars[i].footer) {
19802 // tbh += this.toolbars[i].footer.el.getHeight();
19810 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
19811 ah -= 5; // knock a few pixes off for look..
19812 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
19816 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
19817 this.editorcore.onResize(ew,eh);
19822 * Toggles the editor between standard and source edit mode.
19823 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
19825 toggleSourceEdit : function(sourceEditMode)
19827 this.editorcore.toggleSourceEdit(sourceEditMode);
19829 if(this.editorcore.sourceEditMode){
19830 Roo.log('editor - showing textarea');
19833 // Roo.log(this.syncValue());
19835 this.inputEl().removeClass(['hide', 'x-hidden']);
19836 this.inputEl().dom.removeAttribute('tabIndex');
19837 this.inputEl().focus();
19839 Roo.log('editor - hiding textarea');
19841 // Roo.log(this.pushValue());
19844 this.inputEl().addClass(['hide', 'x-hidden']);
19845 this.inputEl().dom.setAttribute('tabIndex', -1);
19846 //this.deferFocus();
19849 if(this.resizable){
19850 this.setSize(this.wrap.getSize());
19853 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
19856 // private (for BoxComponent)
19857 adjustSize : Roo.BoxComponent.prototype.adjustSize,
19859 // private (for BoxComponent)
19860 getResizeEl : function(){
19864 // private (for BoxComponent)
19865 getPositionEl : function(){
19870 initEvents : function(){
19871 this.originalValue = this.getValue();
19875 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19878 // markInvalid : Roo.emptyFn,
19880 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
19883 // clearInvalid : Roo.emptyFn,
19885 setValue : function(v){
19886 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
19887 this.editorcore.pushValue();
19892 deferFocus : function(){
19893 this.focus.defer(10, this);
19897 focus : function(){
19898 this.editorcore.focus();
19904 onDestroy : function(){
19910 for (var i =0; i < this.toolbars.length;i++) {
19911 // fixme - ask toolbars for heights?
19912 this.toolbars[i].onDestroy();
19915 this.wrap.dom.innerHTML = '';
19916 this.wrap.remove();
19921 onFirstFocus : function(){
19922 //Roo.log("onFirstFocus");
19923 this.editorcore.onFirstFocus();
19924 for (var i =0; i < this.toolbars.length;i++) {
19925 this.toolbars[i].onFirstFocus();
19931 syncValue : function()
19933 this.editorcore.syncValue();
19936 pushValue : function()
19938 this.editorcore.pushValue();
19942 // hide stuff that is not compatible
19956 * @event specialkey
19960 * @cfg {String} fieldClass @hide
19963 * @cfg {String} focusClass @hide
19966 * @cfg {String} autoCreate @hide
19969 * @cfg {String} inputType @hide
19972 * @cfg {String} invalidClass @hide
19975 * @cfg {String} invalidText @hide
19978 * @cfg {String} msgFx @hide
19981 * @cfg {String} validateOnBlur @hide
19990 Roo.namespace('Roo.bootstrap.htmleditor');
19992 * @class Roo.bootstrap.HtmlEditorToolbar1
19997 new Roo.bootstrap.HtmlEditor({
20000 new Roo.bootstrap.HtmlEditorToolbar1({
20001 disable : { fonts: 1 , format: 1, ..., ... , ...],
20007 * @cfg {Object} disable List of elements to disable..
20008 * @cfg {Array} btns List of additional buttons.
20012 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
20015 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
20018 Roo.apply(this, config);
20020 // default disabled, based on 'good practice'..
20021 this.disable = this.disable || {};
20022 Roo.applyIf(this.disable, {
20025 specialElements : true
20027 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
20029 this.editor = config.editor;
20030 this.editorcore = config.editor.editorcore;
20032 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
20034 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
20035 // dont call parent... till later.
20037 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
20042 editorcore : false,
20047 "h1","h2","h3","h4","h5","h6",
20049 "abbr", "acronym", "address", "cite", "samp", "var",
20053 onRender : function(ct, position)
20055 // Roo.log("Call onRender: " + this.xtype);
20057 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
20059 this.el.dom.style.marginBottom = '0';
20061 var editorcore = this.editorcore;
20062 var editor= this.editor;
20065 var btn = function(id,cmd , toggle, handler){
20067 var event = toggle ? 'toggle' : 'click';
20072 xns: Roo.bootstrap,
20075 enableToggle:toggle !== false,
20077 pressed : toggle ? false : null,
20080 a.listeners[toggle ? 'toggle' : 'click'] = function() {
20081 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
20090 xns: Roo.bootstrap,
20091 glyphicon : 'font',
20095 xns: Roo.bootstrap,
20099 Roo.each(this.formats, function(f) {
20100 style.menu.items.push({
20102 xns: Roo.bootstrap,
20103 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
20108 editorcore.insertTag(this.tagname);
20115 children.push(style);
20118 btn('bold',false,true);
20119 btn('italic',false,true);
20120 btn('align-left', 'justifyleft',true);
20121 btn('align-center', 'justifycenter',true);
20122 btn('align-right' , 'justifyright',true);
20123 btn('link', false, false, function(btn) {
20124 //Roo.log("create link?");
20125 var url = prompt(this.createLinkText, this.defaultLinkValue);
20126 if(url && url != 'http:/'+'/'){
20127 this.editorcore.relayCmd('createlink', url);
20130 btn('list','insertunorderedlist',true);
20131 btn('pencil', false,true, function(btn){
20134 this.toggleSourceEdit(btn.pressed);
20140 xns: Roo.bootstrap,
20145 xns: Roo.bootstrap,
20150 cog.menu.items.push({
20152 xns: Roo.bootstrap,
20153 html : Clean styles,
20158 editorcore.insertTag(this.tagname);
20167 this.xtype = 'NavSimplebar';
20169 for(var i=0;i< children.length;i++) {
20171 this.buttons.add(this.addxtypeChild(children[i]));
20175 editor.on('editorevent', this.updateToolbar, this);
20177 onBtnClick : function(id)
20179 this.editorcore.relayCmd(id);
20180 this.editorcore.focus();
20184 * Protected method that will not generally be called directly. It triggers
20185 * a toolbar update by reading the markup state of the current selection in the editor.
20187 updateToolbar: function(){
20189 if(!this.editorcore.activated){
20190 this.editor.onFirstFocus(); // is this neeed?
20194 var btns = this.buttons;
20195 var doc = this.editorcore.doc;
20196 btns.get('bold').setActive(doc.queryCommandState('bold'));
20197 btns.get('italic').setActive(doc.queryCommandState('italic'));
20198 //btns.get('underline').setActive(doc.queryCommandState('underline'));
20200 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
20201 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
20202 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
20204 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
20205 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
20208 var ans = this.editorcore.getAllAncestors();
20209 if (this.formatCombo) {
20212 var store = this.formatCombo.store;
20213 this.formatCombo.setValue("");
20214 for (var i =0; i < ans.length;i++) {
20215 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
20217 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
20225 // hides menus... - so this cant be on a menu...
20226 Roo.bootstrap.MenuMgr.hideAll();
20228 Roo.bootstrap.MenuMgr.hideAll();
20229 //this.editorsyncValue();
20231 onFirstFocus: function() {
20232 this.buttons.each(function(item){
20236 toggleSourceEdit : function(sourceEditMode){
20239 if(sourceEditMode){
20240 Roo.log("disabling buttons");
20241 this.buttons.each( function(item){
20242 if(item.cmd != 'pencil'){
20248 Roo.log("enabling buttons");
20249 if(this.editorcore.initialized){
20250 this.buttons.each( function(item){
20256 Roo.log("calling toggole on editor");
20257 // tell the editor that it's been pressed..
20258 this.editor.toggleSourceEdit(sourceEditMode);
20268 * @class Roo.bootstrap.Table.AbstractSelectionModel
20269 * @extends Roo.util.Observable
20270 * Abstract base class for grid SelectionModels. It provides the interface that should be
20271 * implemented by descendant classes. This class should not be directly instantiated.
20274 Roo.bootstrap.Table.AbstractSelectionModel = function(){
20275 this.locked = false;
20276 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
20280 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
20281 /** @ignore Called by the grid automatically. Do not call directly. */
20282 init : function(grid){
20288 * Locks the selections.
20291 this.locked = true;
20295 * Unlocks the selections.
20297 unlock : function(){
20298 this.locked = false;
20302 * Returns true if the selections are locked.
20303 * @return {Boolean}
20305 isLocked : function(){
20306 return this.locked;
20310 * @extends Roo.bootstrap.Table.AbstractSelectionModel
20311 * @class Roo.bootstrap.Table.RowSelectionModel
20312 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
20313 * It supports multiple selections and keyboard selection/navigation.
20315 * @param {Object} config
20318 Roo.bootstrap.Table.RowSelectionModel = function(config){
20319 Roo.apply(this, config);
20320 this.selections = new Roo.util.MixedCollection(false, function(o){
20325 this.lastActive = false;
20329 * @event selectionchange
20330 * Fires when the selection changes
20331 * @param {SelectionModel} this
20333 "selectionchange" : true,
20335 * @event afterselectionchange
20336 * Fires after the selection changes (eg. by key press or clicking)
20337 * @param {SelectionModel} this
20339 "afterselectionchange" : true,
20341 * @event beforerowselect
20342 * Fires when a row is selected being selected, return false to cancel.
20343 * @param {SelectionModel} this
20344 * @param {Number} rowIndex The selected index
20345 * @param {Boolean} keepExisting False if other selections will be cleared
20347 "beforerowselect" : true,
20350 * Fires when a row is selected.
20351 * @param {SelectionModel} this
20352 * @param {Number} rowIndex The selected index
20353 * @param {Roo.data.Record} r The record
20355 "rowselect" : true,
20357 * @event rowdeselect
20358 * Fires when a row is deselected.
20359 * @param {SelectionModel} this
20360 * @param {Number} rowIndex The selected index
20362 "rowdeselect" : true
20364 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
20365 this.locked = false;
20368 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
20370 * @cfg {Boolean} singleSelect
20371 * True to allow selection of only one row at a time (defaults to false)
20373 singleSelect : false,
20376 initEvents : function(){
20378 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
20379 this.grid.on("mousedown", this.handleMouseDown, this);
20380 }else{ // allow click to work like normal
20381 this.grid.on("rowclick", this.handleDragableRowClick, this);
20384 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
20385 "up" : function(e){
20387 this.selectPrevious(e.shiftKey);
20388 }else if(this.last !== false && this.lastActive !== false){
20389 var last = this.last;
20390 this.selectRange(this.last, this.lastActive-1);
20391 this.grid.getView().focusRow(this.lastActive);
20392 if(last !== false){
20396 this.selectFirstRow();
20398 this.fireEvent("afterselectionchange", this);
20400 "down" : function(e){
20402 this.selectNext(e.shiftKey);
20403 }else if(this.last !== false && this.lastActive !== false){
20404 var last = this.last;
20405 this.selectRange(this.last, this.lastActive+1);
20406 this.grid.getView().focusRow(this.lastActive);
20407 if(last !== false){
20411 this.selectFirstRow();
20413 this.fireEvent("afterselectionchange", this);
20418 var view = this.grid.view;
20419 view.on("refresh", this.onRefresh, this);
20420 view.on("rowupdated", this.onRowUpdated, this);
20421 view.on("rowremoved", this.onRemove, this);
20425 onRefresh : function(){
20426 var ds = this.grid.dataSource, i, v = this.grid.view;
20427 var s = this.selections;
20428 s.each(function(r){
20429 if((i = ds.indexOfId(r.id)) != -1){
20438 onRemove : function(v, index, r){
20439 this.selections.remove(r);
20443 onRowUpdated : function(v, index, r){
20444 if(this.isSelected(r)){
20445 v.onRowSelect(index);
20451 * @param {Array} records The records to select
20452 * @param {Boolean} keepExisting (optional) True to keep existing selections
20454 selectRecords : function(records, keepExisting){
20456 this.clearSelections();
20458 var ds = this.grid.dataSource;
20459 for(var i = 0, len = records.length; i < len; i++){
20460 this.selectRow(ds.indexOf(records[i]), true);
20465 * Gets the number of selected rows.
20468 getCount : function(){
20469 return this.selections.length;
20473 * Selects the first row in the grid.
20475 selectFirstRow : function(){
20480 * Select the last row.
20481 * @param {Boolean} keepExisting (optional) True to keep existing selections
20483 selectLastRow : function(keepExisting){
20484 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
20488 * Selects the row immediately following the last selected row.
20489 * @param {Boolean} keepExisting (optional) True to keep existing selections
20491 selectNext : function(keepExisting){
20492 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
20493 this.selectRow(this.last+1, keepExisting);
20494 this.grid.getView().focusRow(this.last);
20499 * Selects the row that precedes the last selected row.
20500 * @param {Boolean} keepExisting (optional) True to keep existing selections
20502 selectPrevious : function(keepExisting){
20504 this.selectRow(this.last-1, keepExisting);
20505 this.grid.getView().focusRow(this.last);
20510 * Returns the selected records
20511 * @return {Array} Array of selected records
20513 getSelections : function(){
20514 return [].concat(this.selections.items);
20518 * Returns the first selected record.
20521 getSelected : function(){
20522 return this.selections.itemAt(0);
20527 * Clears all selections.
20529 clearSelections : function(fast){
20530 if(this.locked) return;
20532 var ds = this.grid.dataSource;
20533 var s = this.selections;
20534 s.each(function(r){
20535 this.deselectRow(ds.indexOfId(r.id));
20539 this.selections.clear();
20546 * Selects all rows.
20548 selectAll : function(){
20549 if(this.locked) return;
20550 this.selections.clear();
20551 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
20552 this.selectRow(i, true);
20557 * Returns True if there is a selection.
20558 * @return {Boolean}
20560 hasSelection : function(){
20561 return this.selections.length > 0;
20565 * Returns True if the specified row is selected.
20566 * @param {Number/Record} record The record or index of the record to check
20567 * @return {Boolean}
20569 isSelected : function(index){
20570 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
20571 return (r && this.selections.key(r.id) ? true : false);
20575 * Returns True if the specified record id is selected.
20576 * @param {String} id The id of record to check
20577 * @return {Boolean}
20579 isIdSelected : function(id){
20580 return (this.selections.key(id) ? true : false);
20584 handleMouseDown : function(e, t){
20585 var view = this.grid.getView(), rowIndex;
20586 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
20589 if(e.shiftKey && this.last !== false){
20590 var last = this.last;
20591 this.selectRange(last, rowIndex, e.ctrlKey);
20592 this.last = last; // reset the last
20593 view.focusRow(rowIndex);
20595 var isSelected = this.isSelected(rowIndex);
20596 if(e.button !== 0 && isSelected){
20597 view.focusRow(rowIndex);
20598 }else if(e.ctrlKey && isSelected){
20599 this.deselectRow(rowIndex);
20600 }else if(!isSelected){
20601 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
20602 view.focusRow(rowIndex);
20605 this.fireEvent("afterselectionchange", this);
20608 handleDragableRowClick : function(grid, rowIndex, e)
20610 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
20611 this.selectRow(rowIndex, false);
20612 grid.view.focusRow(rowIndex);
20613 this.fireEvent("afterselectionchange", this);
20618 * Selects multiple rows.
20619 * @param {Array} rows Array of the indexes of the row to select
20620 * @param {Boolean} keepExisting (optional) True to keep existing selections
20622 selectRows : function(rows, keepExisting){
20624 this.clearSelections();
20626 for(var i = 0, len = rows.length; i < len; i++){
20627 this.selectRow(rows[i], true);
20632 * Selects a range of rows. All rows in between startRow and endRow are also selected.
20633 * @param {Number} startRow The index of the first row in the range
20634 * @param {Number} endRow The index of the last row in the range
20635 * @param {Boolean} keepExisting (optional) True to retain existing selections
20637 selectRange : function(startRow, endRow, keepExisting){
20638 if(this.locked) return;
20640 this.clearSelections();
20642 if(startRow <= endRow){
20643 for(var i = startRow; i <= endRow; i++){
20644 this.selectRow(i, true);
20647 for(var i = startRow; i >= endRow; i--){
20648 this.selectRow(i, true);
20654 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
20655 * @param {Number} startRow The index of the first row in the range
20656 * @param {Number} endRow The index of the last row in the range
20658 deselectRange : function(startRow, endRow, preventViewNotify){
20659 if(this.locked) return;
20660 for(var i = startRow; i <= endRow; i++){
20661 this.deselectRow(i, preventViewNotify);
20667 * @param {Number} row The index of the row to select
20668 * @param {Boolean} keepExisting (optional) True to keep existing selections
20670 selectRow : function(index, keepExisting, preventViewNotify){
20671 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
20672 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
20673 if(!keepExisting || this.singleSelect){
20674 this.clearSelections();
20676 var r = this.grid.dataSource.getAt(index);
20677 this.selections.add(r);
20678 this.last = this.lastActive = index;
20679 if(!preventViewNotify){
20680 this.grid.getView().onRowSelect(index);
20682 this.fireEvent("rowselect", this, index, r);
20683 this.fireEvent("selectionchange", this);
20689 * @param {Number} row The index of the row to deselect
20691 deselectRow : function(index, preventViewNotify){
20692 if(this.locked) return;
20693 if(this.last == index){
20696 if(this.lastActive == index){
20697 this.lastActive = false;
20699 var r = this.grid.dataSource.getAt(index);
20700 this.selections.remove(r);
20701 if(!preventViewNotify){
20702 this.grid.getView().onRowDeselect(index);
20704 this.fireEvent("rowdeselect", this, index);
20705 this.fireEvent("selectionchange", this);
20709 restoreLast : function(){
20711 this.last = this._last;
20716 acceptsNav : function(row, col, cm){
20717 return !cm.isHidden(col) && cm.isCellEditable(col, row);
20721 onEditorKey : function(field, e){
20722 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
20727 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
20729 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
20731 }else if(k == e.ENTER && !e.ctrlKey){
20735 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
20737 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
20739 }else if(k == e.ESC){
20743 g.startEditing(newCell[0], newCell[1]);
20748 * Ext JS Library 1.1.1
20749 * Copyright(c) 2006-2007, Ext JS, LLC.
20751 * Originally Released Under LGPL - original licence link has changed is not relivant.
20754 * <script type="text/javascript">
20758 * @class Roo.bootstrap.PagingToolbar
20760 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
20762 * Create a new PagingToolbar
20763 * @param {Object} config The config object
20765 Roo.bootstrap.PagingToolbar = function(config)
20767 // old args format still supported... - xtype is prefered..
20768 // created from xtype...
20769 var ds = config.dataSource;
20770 this.toolbarItems = [];
20771 if (config.items) {
20772 this.toolbarItems = config.items;
20773 // config.items = [];
20776 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
20783 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
20787 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
20789 * @cfg {Roo.data.Store} dataSource
20790 * The underlying data store providing the paged data
20793 * @cfg {String/HTMLElement/Element} container
20794 * container The id or element that will contain the toolbar
20797 * @cfg {Boolean} displayInfo
20798 * True to display the displayMsg (defaults to false)
20801 * @cfg {Number} pageSize
20802 * The number of records to display per page (defaults to 20)
20806 * @cfg {String} displayMsg
20807 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
20809 displayMsg : 'Displaying {0} - {1} of {2}',
20811 * @cfg {String} emptyMsg
20812 * The message to display when no records are found (defaults to "No data to display")
20814 emptyMsg : 'No data to display',
20816 * Customizable piece of the default paging text (defaults to "Page")
20819 beforePageText : "Page",
20821 * Customizable piece of the default paging text (defaults to "of %0")
20824 afterPageText : "of {0}",
20826 * Customizable piece of the default paging text (defaults to "First Page")
20829 firstText : "First Page",
20831 * Customizable piece of the default paging text (defaults to "Previous Page")
20834 prevText : "Previous Page",
20836 * Customizable piece of the default paging text (defaults to "Next Page")
20839 nextText : "Next Page",
20841 * Customizable piece of the default paging text (defaults to "Last Page")
20844 lastText : "Last Page",
20846 * Customizable piece of the default paging text (defaults to "Refresh")
20849 refreshText : "Refresh",
20853 onRender : function(ct, position)
20855 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
20856 this.navgroup.parentId = this.id;
20857 this.navgroup.onRender(this.el, null);
20858 // add the buttons to the navgroup
20860 if(this.displayInfo){
20861 Roo.log(this.el.select('ul.navbar-nav',true).first());
20862 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
20863 this.displayEl = this.el.select('.x-paging-info', true).first();
20864 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
20865 // this.displayEl = navel.el.select('span',true).first();
20871 Roo.each(_this.buttons, function(e){
20872 Roo.factory(e).onRender(_this.el, null);
20876 Roo.each(_this.toolbarItems, function(e) {
20877 _this.navgroup.addItem(e);
20881 this.first = this.navgroup.addItem({
20882 tooltip: this.firstText,
20884 icon : 'fa fa-backward',
20886 preventDefault: true,
20887 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
20890 this.prev = this.navgroup.addItem({
20891 tooltip: this.prevText,
20893 icon : 'fa fa-step-backward',
20895 preventDefault: true,
20896 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
20898 //this.addSeparator();
20901 var field = this.navgroup.addItem( {
20903 cls : 'x-paging-position',
20905 html : this.beforePageText +
20906 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
20907 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
20910 this.field = field.el.select('input', true).first();
20911 this.field.on("keydown", this.onPagingKeydown, this);
20912 this.field.on("focus", function(){this.dom.select();});
20915 this.afterTextEl = field.el.select('.x-paging-after',true).first();
20916 //this.field.setHeight(18);
20917 //this.addSeparator();
20918 this.next = this.navgroup.addItem({
20919 tooltip: this.nextText,
20921 html : ' <i class="fa fa-step-forward">',
20923 preventDefault: true,
20924 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
20926 this.last = this.navgroup.addItem({
20927 tooltip: this.lastText,
20928 icon : 'fa fa-forward',
20931 preventDefault: true,
20932 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
20934 //this.addSeparator();
20935 this.loading = this.navgroup.addItem({
20936 tooltip: this.refreshText,
20937 icon: 'fa fa-refresh',
20938 preventDefault: true,
20939 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
20945 updateInfo : function(){
20946 if(this.displayEl){
20947 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
20948 var msg = count == 0 ?
20952 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
20954 this.displayEl.update(msg);
20959 onLoad : function(ds, r, o){
20960 this.cursor = o.params ? o.params.start : 0;
20961 var d = this.getPageData(),
20965 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
20966 this.field.dom.value = ap;
20967 this.first.setDisabled(ap == 1);
20968 this.prev.setDisabled(ap == 1);
20969 this.next.setDisabled(ap == ps);
20970 this.last.setDisabled(ap == ps);
20971 this.loading.enable();
20976 getPageData : function(){
20977 var total = this.ds.getTotalCount();
20980 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
20981 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
20986 onLoadError : function(){
20987 this.loading.enable();
20991 onPagingKeydown : function(e){
20992 var k = e.getKey();
20993 var d = this.getPageData();
20995 var v = this.field.dom.value, pageNum;
20996 if(!v || isNaN(pageNum = parseInt(v, 10))){
20997 this.field.dom.value = d.activePage;
21000 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
21001 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21004 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))
21006 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
21007 this.field.dom.value = pageNum;
21008 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
21011 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21013 var v = this.field.dom.value, pageNum;
21014 var increment = (e.shiftKey) ? 10 : 1;
21015 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
21017 if(!v || isNaN(pageNum = parseInt(v, 10))) {
21018 this.field.dom.value = d.activePage;
21021 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
21023 this.field.dom.value = parseInt(v, 10) + increment;
21024 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
21025 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
21032 beforeLoad : function(){
21034 this.loading.disable();
21039 onClick : function(which){
21048 ds.load({params:{start: 0, limit: this.pageSize}});
21051 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
21054 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
21057 var total = ds.getTotalCount();
21058 var extra = total % this.pageSize;
21059 var lastStart = extra ? (total - extra) : total-this.pageSize;
21060 ds.load({params:{start: lastStart, limit: this.pageSize}});
21063 ds.load({params:{start: this.cursor, limit: this.pageSize}});
21069 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
21070 * @param {Roo.data.Store} store The data store to unbind
21072 unbind : function(ds){
21073 ds.un("beforeload", this.beforeLoad, this);
21074 ds.un("load", this.onLoad, this);
21075 ds.un("loadexception", this.onLoadError, this);
21076 ds.un("remove", this.updateInfo, this);
21077 ds.un("add", this.updateInfo, this);
21078 this.ds = undefined;
21082 * Binds the paging toolbar to the specified {@link Roo.data.Store}
21083 * @param {Roo.data.Store} store The data store to bind
21085 bind : function(ds){
21086 ds.on("beforeload", this.beforeLoad, this);
21087 ds.on("load", this.onLoad, this);
21088 ds.on("loadexception", this.onLoadError, this);
21089 ds.on("remove", this.updateInfo, this);
21090 ds.on("add", this.updateInfo, this);
21101 * @class Roo.bootstrap.MessageBar
21102 * @extends Roo.bootstrap.Component
21103 * Bootstrap MessageBar class
21104 * @cfg {String} html contents of the MessageBar
21105 * @cfg {String} weight (info | success | warning | danger) default info
21106 * @cfg {String} beforeClass insert the bar before the given class
21107 * @cfg {Boolean} closable (true | false) default false
21108 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
21111 * Create a new Element
21112 * @param {Object} config The config object
21115 Roo.bootstrap.MessageBar = function(config){
21116 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
21119 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
21125 beforeClass: 'bootstrap-sticky-wrap',
21127 getAutoCreate : function(){
21131 cls: 'alert alert-dismissable alert-' + this.weight,
21136 html: this.html || ''
21142 cfg.cls += ' alert-messages-fixed';
21156 onRender : function(ct, position)
21158 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
21161 var cfg = Roo.apply({}, this.getAutoCreate());
21165 cfg.cls += ' ' + this.cls;
21168 cfg.style = this.style;
21170 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
21172 this.el.setVisibilityMode(Roo.Element.DISPLAY);
21175 this.el.select('>button.close').on('click', this.hide, this);
21181 if (!this.rendered) {
21187 this.fireEvent('show', this);
21193 if (!this.rendered) {
21199 this.fireEvent('hide', this);
21202 update : function()
21204 // var e = this.el.dom.firstChild;
21206 // if(this.closable){
21207 // e = e.nextSibling;
21210 // e.data = this.html || '';
21212 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
21228 * @class Roo.bootstrap.Graph
21229 * @extends Roo.bootstrap.Component
21230 * Bootstrap Graph class
21234 @cfg {String} graphtype bar | vbar | pie
21235 @cfg {number} g_x coodinator | centre x (pie)
21236 @cfg {number} g_y coodinator | centre y (pie)
21237 @cfg {number} g_r radius (pie)
21238 @cfg {number} g_height height of the chart (respected by all elements in the set)
21239 @cfg {number} g_width width of the chart (respected by all elements in the set)
21240 @cfg {Object} title The title of the chart
21243 -opts (object) options for the chart
21245 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
21246 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
21248 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.
21249 o stacked (boolean) whether or not to tread values as in a stacked bar chart
21251 o stretch (boolean)
21253 -opts (object) options for the pie
21256 o startAngle (number)
21257 o endAngle (number)
21261 * Create a new Input
21262 * @param {Object} config The config object
21265 Roo.bootstrap.Graph = function(config){
21266 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
21272 * The img click event for the img.
21273 * @param {Roo.EventObject} e
21279 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
21290 //g_colors: this.colors,
21297 getAutoCreate : function(){
21308 onRender : function(ct,position){
21309 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
21310 this.raphael = Raphael(this.el.dom);
21312 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21313 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21314 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
21315 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
21317 r.text(160, 10, "Single Series Chart").attr(txtattr);
21318 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
21319 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
21320 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
21322 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
21323 r.barchart(330, 10, 300, 220, data1);
21324 r.barchart(10, 250, 300, 220, data2, {stacked: true});
21325 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
21328 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21329 // r.barchart(30, 30, 560, 250, xdata, {
21330 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
21331 // axis : "0 0 1 1",
21332 // axisxlabels : xdata
21333 // //yvalues : cols,
21336 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
21338 // this.load(null,xdata,{
21339 // axis : "0 0 1 1",
21340 // axisxlabels : xdata
21345 load : function(graphtype,xdata,opts){
21346 this.raphael.clear();
21348 graphtype = this.graphtype;
21353 var r = this.raphael,
21354 fin = function () {
21355 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
21357 fout = function () {
21358 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
21360 pfin = function() {
21361 this.sector.stop();
21362 this.sector.scale(1.1, 1.1, this.cx, this.cy);
21365 this.label[0].stop();
21366 this.label[0].attr({ r: 7.5 });
21367 this.label[1].attr({ "font-weight": 800 });
21370 pfout = function() {
21371 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
21374 this.label[0].animate({ r: 5 }, 500, "bounce");
21375 this.label[1].attr({ "font-weight": 400 });
21381 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21384 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
21387 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
21388 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
21390 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
21397 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
21402 setTitle: function(o)
21407 initEvents: function() {
21410 this.el.on('click', this.onClick, this);
21414 onClick : function(e)
21416 Roo.log('img onclick');
21417 this.fireEvent('click', this, e);
21429 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21432 * @class Roo.bootstrap.dash.NumberBox
21433 * @extends Roo.bootstrap.Component
21434 * Bootstrap NumberBox class
21435 * @cfg {String} headline Box headline
21436 * @cfg {String} content Box content
21437 * @cfg {String} icon Box icon
21438 * @cfg {String} footer Footer text
21439 * @cfg {String} fhref Footer href
21442 * Create a new NumberBox
21443 * @param {Object} config The config object
21447 Roo.bootstrap.dash.NumberBox = function(config){
21448 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
21452 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
21461 getAutoCreate : function(){
21465 cls : 'small-box ',
21473 cls : 'roo-headline',
21474 html : this.headline
21478 cls : 'roo-content',
21479 html : this.content
21493 cls : 'ion ' + this.icon
21502 cls : 'small-box-footer',
21503 href : this.fhref || '#',
21507 cfg.cn.push(footer);
21514 onRender : function(ct,position){
21515 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
21522 setHeadline: function (value)
21524 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
21527 setFooter: function (value, href)
21529 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
21532 this.el.select('a.small-box-footer',true).first().attr('href', href);
21537 setContent: function (value)
21539 this.el.select('.roo-content',true).first().dom.innerHTML = value;
21542 initEvents: function()
21556 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21559 * @class Roo.bootstrap.dash.TabBox
21560 * @extends Roo.bootstrap.Component
21561 * Bootstrap TabBox class
21562 * @cfg {String} title Title of the TabBox
21563 * @cfg {String} icon Icon of the TabBox
21564 * @cfg {Boolean} showtabs (true|false) show the tabs default true
21565 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
21568 * Create a new TabBox
21569 * @param {Object} config The config object
21573 Roo.bootstrap.dash.TabBox = function(config){
21574 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
21579 * When a pane is added
21580 * @param {Roo.bootstrap.dash.TabPane} pane
21584 * @event activatepane
21585 * When a pane is activated
21586 * @param {Roo.bootstrap.dash.TabPane} pane
21588 "activatepane" : true
21596 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
21601 tabScrollable : false,
21603 getChildContainer : function()
21605 return this.el.select('.tab-content', true).first();
21608 getAutoCreate : function(){
21612 cls: 'pull-left header',
21620 cls: 'fa ' + this.icon
21626 cls: 'nav nav-tabs pull-right',
21632 if(this.tabScrollable){
21639 cls: 'nav nav-tabs pull-right',
21650 cls: 'nav-tabs-custom',
21655 cls: 'tab-content no-padding',
21663 initEvents : function()
21665 //Roo.log('add add pane handler');
21666 this.on('addpane', this.onAddPane, this);
21669 * Updates the box title
21670 * @param {String} html to set the title to.
21672 setTitle : function(value)
21674 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
21676 onAddPane : function(pane)
21678 this.panes.push(pane);
21679 //Roo.log('addpane');
21681 // tabs are rendere left to right..
21682 if(!this.showtabs){
21686 var ctr = this.el.select('.nav-tabs', true).first();
21689 var existing = ctr.select('.nav-tab',true);
21690 var qty = existing.getCount();;
21693 var tab = ctr.createChild({
21695 cls : 'nav-tab' + (qty ? '' : ' active'),
21703 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
21706 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
21708 pane.el.addClass('active');
21713 onTabClick : function(ev,un,ob,pane)
21715 //Roo.log('tab - prev default');
21716 ev.preventDefault();
21719 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
21720 pane.tab.addClass('active');
21721 //Roo.log(pane.title);
21722 this.getChildContainer().select('.tab-pane',true).removeClass('active');
21723 // technically we should have a deactivate event.. but maybe add later.
21724 // and it should not de-activate the selected tab...
21725 this.fireEvent('activatepane', pane);
21726 pane.el.addClass('active');
21727 pane.fireEvent('activate');
21732 getActivePane : function()
21735 Roo.each(this.panes, function(p) {
21736 if(p.el.hasClass('active')){
21757 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
21759 * @class Roo.bootstrap.TabPane
21760 * @extends Roo.bootstrap.Component
21761 * Bootstrap TabPane class
21762 * @cfg {Boolean} active (false | true) Default false
21763 * @cfg {String} title title of panel
21767 * Create a new TabPane
21768 * @param {Object} config The config object
21771 Roo.bootstrap.dash.TabPane = function(config){
21772 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
21778 * When a pane is activated
21779 * @param {Roo.bootstrap.dash.TabPane} pane
21786 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
21791 // the tabBox that this is attached to.
21794 getAutoCreate : function()
21802 cfg.cls += ' active';
21807 initEvents : function()
21809 //Roo.log('trigger add pane handler');
21810 this.parent().fireEvent('addpane', this)
21814 * Updates the tab title
21815 * @param {String} html to set the title to.
21817 setTitle: function(str)
21823 this.tab.select('a', true).first().dom.innerHTML = str;
21840 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
21843 * @class Roo.bootstrap.menu.Menu
21844 * @extends Roo.bootstrap.Component
21845 * Bootstrap Menu class - container for Menu
21846 * @cfg {String} html Text of the menu
21847 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
21848 * @cfg {String} icon Font awesome icon
21849 * @cfg {String} pos Menu align to (top | bottom) default bottom
21853 * Create a new Menu
21854 * @param {Object} config The config object
21858 Roo.bootstrap.menu.Menu = function(config){
21859 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
21863 * @event beforeshow
21864 * Fires before this menu is displayed
21865 * @param {Roo.bootstrap.menu.Menu} this
21869 * @event beforehide
21870 * Fires before this menu is hidden
21871 * @param {Roo.bootstrap.menu.Menu} this
21876 * Fires after this menu is displayed
21877 * @param {Roo.bootstrap.menu.Menu} this
21882 * Fires after this menu is hidden
21883 * @param {Roo.bootstrap.menu.Menu} this
21888 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
21889 * @param {Roo.bootstrap.menu.Menu} this
21890 * @param {Roo.EventObject} e
21897 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
21901 weight : 'default',
21906 getChildContainer : function() {
21907 if(this.isSubMenu){
21911 return this.el.select('ul.dropdown-menu', true).first();
21914 getAutoCreate : function()
21919 cls : 'roo-menu-text',
21927 cls : 'fa ' + this.icon
21938 cls : 'dropdown-button btn btn-' + this.weight,
21943 cls : 'dropdown-toggle btn btn-' + this.weight,
21953 cls : 'dropdown-menu'
21959 if(this.pos == 'top'){
21960 cfg.cls += ' dropup';
21963 if(this.isSubMenu){
21966 cls : 'dropdown-menu'
21973 onRender : function(ct, position)
21975 this.isSubMenu = ct.hasClass('dropdown-submenu');
21977 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
21980 initEvents : function()
21982 if(this.isSubMenu){
21986 this.hidden = true;
21988 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
21989 this.triggerEl.on('click', this.onTriggerPress, this);
21991 this.buttonEl = this.el.select('button.dropdown-button', true).first();
21992 this.buttonEl.on('click', this.onClick, this);
21998 if(this.isSubMenu){
22002 return this.el.select('ul.dropdown-menu', true).first();
22005 onClick : function(e)
22007 this.fireEvent("click", this, e);
22010 onTriggerPress : function(e)
22012 if (this.isVisible()) {
22019 isVisible : function(){
22020 return !this.hidden;
22025 this.fireEvent("beforeshow", this);
22027 this.hidden = false;
22028 this.el.addClass('open');
22030 Roo.get(document).on("mouseup", this.onMouseUp, this);
22032 this.fireEvent("show", this);
22039 this.fireEvent("beforehide", this);
22041 this.hidden = true;
22042 this.el.removeClass('open');
22044 Roo.get(document).un("mouseup", this.onMouseUp);
22046 this.fireEvent("hide", this);
22049 onMouseUp : function()
22063 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22066 * @class Roo.bootstrap.menu.Item
22067 * @extends Roo.bootstrap.Component
22068 * Bootstrap MenuItem class
22069 * @cfg {Boolean} submenu (true | false) default false
22070 * @cfg {String} html text of the item
22071 * @cfg {String} href the link
22072 * @cfg {Boolean} disable (true | false) default false
22073 * @cfg {Boolean} preventDefault (true | false) default true
22074 * @cfg {String} icon Font awesome icon
22075 * @cfg {String} pos Submenu align to (left | right) default right
22079 * Create a new Item
22080 * @param {Object} config The config object
22084 Roo.bootstrap.menu.Item = function(config){
22085 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
22089 * Fires when the mouse is hovering over this menu
22090 * @param {Roo.bootstrap.menu.Item} this
22091 * @param {Roo.EventObject} e
22096 * Fires when the mouse exits this menu
22097 * @param {Roo.bootstrap.menu.Item} this
22098 * @param {Roo.EventObject} e
22104 * The raw click event for the entire grid.
22105 * @param {Roo.EventObject} e
22111 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
22116 preventDefault: true,
22121 getAutoCreate : function()
22126 cls : 'roo-menu-item-text',
22134 cls : 'fa ' + this.icon
22143 href : this.href || '#',
22150 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
22154 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
22156 if(this.pos == 'left'){
22157 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
22164 initEvents : function()
22166 this.el.on('mouseover', this.onMouseOver, this);
22167 this.el.on('mouseout', this.onMouseOut, this);
22169 this.el.select('a', true).first().on('click', this.onClick, this);
22173 onClick : function(e)
22175 if(this.preventDefault){
22176 e.preventDefault();
22179 this.fireEvent("click", this, e);
22182 onMouseOver : function(e)
22184 if(this.submenu && this.pos == 'left'){
22185 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
22188 this.fireEvent("mouseover", this, e);
22191 onMouseOut : function(e)
22193 this.fireEvent("mouseout", this, e);
22205 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
22208 * @class Roo.bootstrap.menu.Separator
22209 * @extends Roo.bootstrap.Component
22210 * Bootstrap Separator class
22213 * Create a new Separator
22214 * @param {Object} config The config object
22218 Roo.bootstrap.menu.Separator = function(config){
22219 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
22222 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
22224 getAutoCreate : function(){
22245 * @class Roo.bootstrap.Tooltip
22246 * Bootstrap Tooltip class
22247 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
22248 * to determine which dom element triggers the tooltip.
22250 * It needs to add support for additional attributes like tooltip-position
22253 * Create a new Toolti
22254 * @param {Object} config The config object
22257 Roo.bootstrap.Tooltip = function(config){
22258 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
22261 Roo.apply(Roo.bootstrap.Tooltip, {
22263 * @function init initialize tooltip monitoring.
22267 currentTip : false,
22268 currentRegion : false,
22274 Roo.get(document).on('mouseover', this.enter ,this);
22275 Roo.get(document).on('mouseout', this.leave, this);
22278 this.currentTip = new Roo.bootstrap.Tooltip();
22281 enter : function(ev)
22283 var dom = ev.getTarget();
22285 //Roo.log(['enter',dom]);
22286 var el = Roo.fly(dom);
22287 if (this.currentEl) {
22289 //Roo.log(this.currentEl);
22290 //Roo.log(this.currentEl.contains(dom));
22291 if (this.currentEl == el) {
22294 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
22302 if (this.currentTip.el) {
22303 this.currentTip.el.hide(); // force hiding...
22308 // you can not look for children, as if el is the body.. then everythign is the child..
22309 if (!el.attr('tooltip')) { //
22310 if (!el.select("[tooltip]").elements.length) {
22313 // is the mouse over this child...?
22314 bindEl = el.select("[tooltip]").first();
22315 var xy = ev.getXY();
22316 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
22317 //Roo.log("not in region.");
22320 //Roo.log("child element over..");
22323 this.currentEl = bindEl;
22324 this.currentTip.bind(bindEl);
22325 this.currentRegion = Roo.lib.Region.getRegion(dom);
22326 this.currentTip.enter();
22329 leave : function(ev)
22331 var dom = ev.getTarget();
22332 //Roo.log(['leave',dom]);
22333 if (!this.currentEl) {
22338 if (dom != this.currentEl.dom) {
22341 var xy = ev.getXY();
22342 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
22345 // only activate leave if mouse cursor is outside... bounding box..
22350 if (this.currentTip) {
22351 this.currentTip.leave();
22353 //Roo.log('clear currentEl');
22354 this.currentEl = false;
22359 'left' : ['r-l', [-2,0], 'right'],
22360 'right' : ['l-r', [2,0], 'left'],
22361 'bottom' : ['t-b', [0,2], 'top'],
22362 'top' : [ 'b-t', [0,-2], 'bottom']
22368 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
22373 delay : null, // can be { show : 300 , hide: 500}
22377 hoverState : null, //???
22379 placement : 'bottom',
22381 getAutoCreate : function(){
22388 cls : 'tooltip-arrow'
22391 cls : 'tooltip-inner'
22398 bind : function(el)
22404 enter : function () {
22406 if (this.timeout != null) {
22407 clearTimeout(this.timeout);
22410 this.hoverState = 'in';
22411 //Roo.log("enter - show");
22412 if (!this.delay || !this.delay.show) {
22417 this.timeout = setTimeout(function () {
22418 if (_t.hoverState == 'in') {
22421 }, this.delay.show);
22425 clearTimeout(this.timeout);
22427 this.hoverState = 'out';
22428 if (!this.delay || !this.delay.hide) {
22434 this.timeout = setTimeout(function () {
22435 //Roo.log("leave - timeout");
22437 if (_t.hoverState == 'out') {
22439 Roo.bootstrap.Tooltip.currentEl = false;
22447 this.render(document.body);
22450 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
22452 var tip = this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
22454 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
22456 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
22458 var placement = typeof this.placement == 'function' ?
22459 this.placement.call(this, this.el, on_el) :
22462 var autoToken = /\s?auto?\s?/i;
22463 var autoPlace = autoToken.test(placement);
22465 placement = placement.replace(autoToken, '') || 'top';
22469 //this.el.setXY([0,0]);
22471 //this.el.dom.style.display='block';
22472 this.el.addClass(placement);
22474 //this.el.appendTo(on_el);
22476 var p = this.getPosition();
22477 var box = this.el.getBox();
22482 var align = Roo.bootstrap.Tooltip.alignment[placement];
22483 this.el.alignTo(this.bindEl, align[0],align[1]);
22484 //var arrow = this.el.select('.arrow',true).first();
22485 //arrow.set(align[2],
22487 this.el.addClass('in fade');
22488 this.hoverState = null;
22490 if (this.el.hasClass('fade')) {
22501 //this.el.setXY([0,0]);
22502 this.el.removeClass('in');
22518 * @class Roo.bootstrap.LocationPicker
22519 * @extends Roo.bootstrap.Component
22520 * Bootstrap LocationPicker class
22521 * @cfg {Number} latitude Position when init default 0
22522 * @cfg {Number} longitude Position when init default 0
22523 * @cfg {Number} zoom default 15
22524 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
22525 * @cfg {Boolean} mapTypeControl default false
22526 * @cfg {Boolean} disableDoubleClickZoom default false
22527 * @cfg {Boolean} scrollwheel default true
22528 * @cfg {Boolean} streetViewControl default false
22529 * @cfg {Number} radius default 0
22530 * @cfg {String} locationName
22531 * @cfg {Boolean} draggable default true
22532 * @cfg {Boolean} enableAutocomplete default false
22533 * @cfg {Boolean} enableReverseGeocode default true
22534 * @cfg {String} markerTitle
22537 * Create a new LocationPicker
22538 * @param {Object} config The config object
22542 Roo.bootstrap.LocationPicker = function(config){
22544 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
22549 * Fires when the picker initialized.
22550 * @param {Roo.bootstrap.LocationPicker} this
22551 * @param {Google Location} location
22555 * @event positionchanged
22556 * Fires when the picker position changed.
22557 * @param {Roo.bootstrap.LocationPicker} this
22558 * @param {Google Location} location
22560 positionchanged : true,
22563 * Fires when the map resize.
22564 * @param {Roo.bootstrap.LocationPicker} this
22569 * Fires when the map show.
22570 * @param {Roo.bootstrap.LocationPicker} this
22575 * Fires when the map hide.
22576 * @param {Roo.bootstrap.LocationPicker} this
22581 * Fires when click the map.
22582 * @param {Roo.bootstrap.LocationPicker} this
22583 * @param {Map event} e
22587 * @event mapRightClick
22588 * Fires when right click the map.
22589 * @param {Roo.bootstrap.LocationPicker} this
22590 * @param {Map event} e
22592 mapRightClick : true,
22594 * @event markerClick
22595 * Fires when click the marker.
22596 * @param {Roo.bootstrap.LocationPicker} this
22597 * @param {Map event} e
22599 markerClick : true,
22601 * @event markerRightClick
22602 * Fires when right click the marker.
22603 * @param {Roo.bootstrap.LocationPicker} this
22604 * @param {Map event} e
22606 markerRightClick : true,
22608 * @event OverlayViewDraw
22609 * Fires when OverlayView Draw
22610 * @param {Roo.bootstrap.LocationPicker} this
22612 OverlayViewDraw : true,
22614 * @event OverlayViewOnAdd
22615 * Fires when OverlayView Draw
22616 * @param {Roo.bootstrap.LocationPicker} this
22618 OverlayViewOnAdd : true,
22620 * @event OverlayViewOnRemove
22621 * Fires when OverlayView Draw
22622 * @param {Roo.bootstrap.LocationPicker} this
22624 OverlayViewOnRemove : true,
22626 * @event OverlayViewShow
22627 * Fires when OverlayView Draw
22628 * @param {Roo.bootstrap.LocationPicker} this
22629 * @param {Pixel} cpx
22631 OverlayViewShow : true,
22633 * @event OverlayViewHide
22634 * Fires when OverlayView Draw
22635 * @param {Roo.bootstrap.LocationPicker} this
22637 OverlayViewHide : true
22642 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
22644 gMapContext: false,
22650 mapTypeControl: false,
22651 disableDoubleClickZoom: false,
22653 streetViewControl: false,
22657 enableAutocomplete: false,
22658 enableReverseGeocode: true,
22661 getAutoCreate: function()
22666 cls: 'roo-location-picker'
22672 initEvents: function(ct, position)
22674 if(!this.el.getWidth() || this.isApplied()){
22678 this.el.setVisibilityMode(Roo.Element.DISPLAY);
22683 initial: function()
22685 if(!this.mapTypeId){
22686 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
22689 this.gMapContext = this.GMapContext();
22691 this.initOverlayView();
22693 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
22697 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
22698 _this.setPosition(_this.gMapContext.marker.position);
22701 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
22702 _this.fireEvent('mapClick', this, event);
22706 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
22707 _this.fireEvent('mapRightClick', this, event);
22711 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
22712 _this.fireEvent('markerClick', this, event);
22716 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
22717 _this.fireEvent('markerRightClick', this, event);
22721 this.setPosition(this.gMapContext.location);
22723 this.fireEvent('initial', this, this.gMapContext.location);
22726 initOverlayView: function()
22730 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
22734 _this.fireEvent('OverlayViewDraw', _this);
22739 _this.fireEvent('OverlayViewOnAdd', _this);
22742 onRemove: function()
22744 _this.fireEvent('OverlayViewOnRemove', _this);
22747 show: function(cpx)
22749 _this.fireEvent('OverlayViewShow', _this, cpx);
22754 _this.fireEvent('OverlayViewHide', _this);
22760 fromLatLngToContainerPixel: function(event)
22762 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
22765 isApplied: function()
22767 return this.getGmapContext() == false ? false : true;
22770 getGmapContext: function()
22772 return this.gMapContext
22775 GMapContext: function()
22777 var position = new google.maps.LatLng(this.latitude, this.longitude);
22779 var _map = new google.maps.Map(this.el.dom, {
22782 mapTypeId: this.mapTypeId,
22783 mapTypeControl: this.mapTypeControl,
22784 disableDoubleClickZoom: this.disableDoubleClickZoom,
22785 scrollwheel: this.scrollwheel,
22786 streetViewControl: this.streetViewControl,
22787 locationName: this.locationName,
22788 draggable: this.draggable,
22789 enableAutocomplete: this.enableAutocomplete,
22790 enableReverseGeocode: this.enableReverseGeocode
22793 var _marker = new google.maps.Marker({
22794 position: position,
22796 title: this.markerTitle,
22797 draggable: this.draggable
22804 location: position,
22805 radius: this.radius,
22806 locationName: this.locationName,
22807 addressComponents: {
22808 formatted_address: null,
22809 addressLine1: null,
22810 addressLine2: null,
22812 streetNumber: null,
22816 stateOrProvince: null
22819 domContainer: this.el.dom,
22820 geodecoder: new google.maps.Geocoder()
22824 drawCircle: function(center, radius, options)
22826 if (this.gMapContext.circle != null) {
22827 this.gMapContext.circle.setMap(null);
22831 options = Roo.apply({}, options, {
22832 strokeColor: "#0000FF",
22833 strokeOpacity: .35,
22835 fillColor: "#0000FF",
22839 options.map = this.gMapContext.map;
22840 options.radius = radius;
22841 options.center = center;
22842 this.gMapContext.circle = new google.maps.Circle(options);
22843 return this.gMapContext.circle;
22849 setPosition: function(location)
22851 this.gMapContext.location = location;
22852 this.gMapContext.marker.setPosition(location);
22853 this.gMapContext.map.panTo(location);
22854 this.drawCircle(location, this.gMapContext.radius, {});
22858 if (this.gMapContext.settings.enableReverseGeocode) {
22859 this.gMapContext.geodecoder.geocode({
22860 latLng: this.gMapContext.location
22861 }, function(results, status) {
22863 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
22864 _this.gMapContext.locationName = results[0].formatted_address;
22865 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
22867 _this.fireEvent('positionchanged', this, location);
22874 this.fireEvent('positionchanged', this, location);
22879 google.maps.event.trigger(this.gMapContext.map, "resize");
22881 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
22883 this.fireEvent('resize', this);
22886 setPositionByLatLng: function(latitude, longitude)
22888 this.setPosition(new google.maps.LatLng(latitude, longitude));
22891 getCurrentPosition: function()
22894 latitude: this.gMapContext.location.lat(),
22895 longitude: this.gMapContext.location.lng()
22899 getAddressName: function()
22901 return this.gMapContext.locationName;
22904 getAddressComponents: function()
22906 return this.gMapContext.addressComponents;
22909 address_component_from_google_geocode: function(address_components)
22913 for (var i = 0; i < address_components.length; i++) {
22914 var component = address_components[i];
22915 if (component.types.indexOf("postal_code") >= 0) {
22916 result.postalCode = component.short_name;
22917 } else if (component.types.indexOf("street_number") >= 0) {
22918 result.streetNumber = component.short_name;
22919 } else if (component.types.indexOf("route") >= 0) {
22920 result.streetName = component.short_name;
22921 } else if (component.types.indexOf("neighborhood") >= 0) {
22922 result.city = component.short_name;
22923 } else if (component.types.indexOf("locality") >= 0) {
22924 result.city = component.short_name;
22925 } else if (component.types.indexOf("sublocality") >= 0) {
22926 result.district = component.short_name;
22927 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
22928 result.stateOrProvince = component.short_name;
22929 } else if (component.types.indexOf("country") >= 0) {
22930 result.country = component.short_name;
22934 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
22935 result.addressLine2 = "";
22939 setZoomLevel: function(zoom)
22941 this.gMapContext.map.setZoom(zoom);
22954 this.fireEvent('show', this);
22965 this.fireEvent('hide', this);
22970 Roo.apply(Roo.bootstrap.LocationPicker, {
22972 OverlayView : function(map, options)
22974 options = options || {};
22988 * @class Roo.bootstrap.Alert
22989 * @extends Roo.bootstrap.Component
22990 * Bootstrap Alert class
22991 * @cfg {String} title The title of alert
22992 * @cfg {String} html The content of alert
22993 * @cfg {String} weight ( success | info | warning | danger )
22994 * @cfg {String} faicon font-awesomeicon
22997 * Create a new alert
22998 * @param {Object} config The config object
23002 Roo.bootstrap.Alert = function(config){
23003 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
23007 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
23014 getAutoCreate : function()
23023 cls : 'roo-alert-icon'
23028 cls : 'roo-alert-title',
23033 cls : 'roo-alert-text',
23040 cfg.cn[0].cls += ' fa ' + this.faicon;
23044 cfg.cls += ' alert-' + this.weight;
23050 initEvents: function()
23052 this.el.setVisibilityMode(Roo.Element.DISPLAY);
23055 setTitle : function(str)
23057 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
23060 setText : function(str)
23062 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
23065 setWeight : function(weight)
23068 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
23071 this.weight = weight;
23073 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
23076 setIcon : function(icon)
23079 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
23084 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);