2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets[0], function(s) {
10 if (s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 addxtype : function(tree,cntr)
179 cn = Roo.factory(tree);
180 //Roo.log(['addxtype', cn]);
182 cn.parentType = this.xtype; //??
183 cn.parentId = this.id;
185 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 if (typeof(cn.container_method) == 'string') {
187 cntr = cn.container_method;
191 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
193 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
195 var build_from_html = Roo.XComponent.build_from_html;
197 var is_body = (tree.xtype == 'Body') ;
199 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
201 var self_cntr_el = Roo.get(this[cntr](false));
203 // do not try and build conditional elements
204 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
208 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
209 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
210 return this.addxtypeChild(tree,cntr, is_body);
213 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
216 return this.addxtypeChild(Roo.apply({}, tree),cntr);
219 Roo.log('skipping render');
225 if (!build_from_html) {
229 // this i think handles overlaying multiple children of the same type
230 // with the sam eelement.. - which might be buggy..
232 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
238 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
242 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
249 addxtypeChild : function (tree, cntr, is_body)
251 Roo.debug && Roo.log('addxtypeChild:' + cntr);
253 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
256 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
257 (typeof(tree['flexy:foreach']) != 'undefined');
261 skip_children = false;
262 // render the element if it's not BODY.
265 // if parent was disabled, then do not try and create the children..
266 if(!this[cntr](true)){
271 cn = Roo.factory(tree);
273 cn.parentType = this.xtype; //??
274 cn.parentId = this.id;
276 var build_from_html = Roo.XComponent.build_from_html;
279 // does the container contain child eleemnts with 'xtype' attributes.
280 // that match this xtype..
281 // note - when we render we create these as well..
282 // so we should check to see if body has xtype set.
283 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
285 var self_cntr_el = Roo.get(this[cntr](false));
286 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
288 //Roo.log(Roo.XComponent.build_from_html);
289 //Roo.log("got echild:");
292 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
293 // and are not displayed -this causes this to use up the wrong element when matching.
294 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
297 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
298 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
304 //echild.dom.removeAttribute('xtype');
306 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
307 Roo.debug && Roo.log(self_cntr_el);
308 Roo.debug && Roo.log(echild);
309 Roo.debug && Roo.log(cn);
315 // if object has flexy:if - then it may or may not be rendered.
316 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
317 // skip a flexy if element.
318 Roo.debug && Roo.log('skipping render');
319 Roo.debug && Roo.log(tree);
321 Roo.debug && Roo.log('skipping all children');
322 skip_children = true;
327 // actually if flexy:foreach is found, we really want to create
328 // multiple copies here...
330 //Roo.log(this[cntr]());
331 // some elements do not have render methods.. like the layouts...
333 if(this[cntr](true) === false){
338 cn.render && cn.render(this[cntr](true));
341 // then add the element..
348 if (typeof (tree.menu) != 'undefined') {
349 tree.menu.parentType = cn.xtype;
350 tree.menu.triggerEl = cn.el;
351 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
355 if (!tree.items || !tree.items.length) {
357 //Roo.log(["no children", this]);
362 var items = tree.items;
365 //Roo.log(items.length);
367 if (!skip_children) {
368 for(var i =0;i < items.length;i++) {
369 // Roo.log(['add child', items[i]]);
370 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
376 //Roo.log("fire childrenrendered");
378 cn.fireEvent('childrenrendered', this);
384 * Set the element that will be used to show or hide
386 setVisibilityEl : function(el)
388 this.visibilityEl = el;
392 * Get the element that will be used to show or hide
394 getVisibilityEl : function()
396 if (typeof(this.visibilityEl) == 'object') {
397 return this.visibilityEl;
400 if (typeof(this.visibilityEl) == 'string') {
401 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
408 * Show a component - removes 'hidden' class
412 if(!this.getVisibilityEl()){
416 this.getVisibilityEl().removeClass('hidden');
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass('hidden');
433 this.fireEvent('hide', this);
446 * @class Roo.bootstrap.Body
447 * @extends Roo.bootstrap.Component
448 * Bootstrap Body class
452 * @param {Object} config The config object
455 Roo.bootstrap.Body = function(config){
457 config = config || {};
459 Roo.bootstrap.Body.superclass.constructor.call(this, config);
460 this.el = Roo.get(config.el ? config.el : document.body );
461 if (this.cls && this.cls.length) {
462 Roo.get(document.body).addClass(this.cls);
466 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
468 is_body : true,// just to make sure it's constructed?
473 onRender : function(ct, position)
475 /* Roo.log("Roo.bootstrap.Body - onRender");
476 if (this.cls && this.cls.length) {
477 Roo.get(document.body).addClass(this.cls);
496 * @class Roo.bootstrap.ButtonGroup
497 * @extends Roo.bootstrap.Component
498 * Bootstrap ButtonGroup class
499 * @cfg {String} size lg | sm | xs (default empty normal)
500 * @cfg {String} align vertical | justified (default none)
501 * @cfg {String} direction up | down (default down)
502 * @cfg {Boolean} toolbar false | true
503 * @cfg {Boolean} btn true | false
508 * @param {Object} config The config object
511 Roo.bootstrap.ButtonGroup = function(config){
512 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
515 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
523 getAutoCreate : function(){
529 cfg.html = this.html || cfg.html;
540 if (['vertical','justified'].indexOf(this.align)!==-1) {
541 cfg.cls = 'btn-group-' + this.align;
543 if (this.align == 'justified') {
544 console.log(this.items);
548 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
549 cfg.cls += ' btn-group-' + this.size;
552 if (this.direction == 'up') {
553 cfg.cls += ' dropup' ;
559 * Add a button to the group (similar to NavItem API.)
561 addItem : function(cfg)
563 var cn = new Roo.bootstrap.Button(cfg);
565 cn.parentId = this.id;
566 cn.onRender(this.el, null);
580 * @class Roo.bootstrap.Button
581 * @extends Roo.bootstrap.Component
582 * Bootstrap Button class
583 * @cfg {String} html The button content
584 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
585 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
586 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
587 * @cfg {String} size ( lg | sm | xs)
588 * @cfg {String} tag ( a | input | submit)
589 * @cfg {String} href empty or href
590 * @cfg {Boolean} disabled default false;
591 * @cfg {Boolean} isClose default false;
592 * @cfg {String} glyphicon depricated - use fa
593 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
594 * @cfg {String} badge text for badge
595 * @cfg {String} theme (default|glow)
596 * @cfg {Boolean} inverse dark themed version
597 * @cfg {Boolean} toggle is it a slidy toggle button
598 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
599 * @cfg {String} ontext text for on slidy toggle state
600 * @cfg {String} offtext text for off slidy toggle state
601 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
602 * @cfg {Boolean} removeClass remove the standard class..
603 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
606 * Create a new button
607 * @param {Object} config The config object
611 Roo.bootstrap.Button = function(config){
612 Roo.bootstrap.Button.superclass.constructor.call(this, config);
613 this.weightClass = ["btn-default btn-outline-secondary",
625 * When a butotn is pressed
626 * @param {Roo.bootstrap.Button} btn
627 * @param {Roo.EventObject} e
632 * After the button has been toggles
633 * @param {Roo.bootstrap.Button} btn
634 * @param {Roo.EventObject} e
635 * @param {boolean} pressed (also available as button.pressed)
641 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
662 preventDefault: true,
670 getAutoCreate : function(){
678 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
679 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
684 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
686 if (this.toggle == true) {
689 cls: 'slider-frame roo-button',
694 'data-off-text':'OFF',
695 cls: 'slider-button',
701 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
702 cfg.cls += ' '+this.weight;
711 cfg["aria-hidden"] = true;
713 cfg.html = "×";
719 if (this.theme==='default') {
720 cfg.cls = 'btn roo-button';
722 //if (this.parentType != 'Navbar') {
723 this.weight = this.weight.length ? this.weight : 'default';
725 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
727 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
728 var weight = this.weight == 'default' ? 'secondary' : this.weight;
729 cfg.cls += ' btn-' + outline + weight;
730 if (this.weight == 'default') {
732 cfg.cls += ' btn-' + this.weight;
735 } else if (this.theme==='glow') {
738 cfg.cls = 'btn-glow roo-button';
740 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
742 cfg.cls += ' ' + this.weight;
748 this.cls += ' inverse';
752 if (this.active || this.pressed === true) {
753 cfg.cls += ' active';
757 cfg.disabled = 'disabled';
761 Roo.log('changing to ul' );
763 this.glyphicon = 'caret';
764 if (Roo.bootstrap.version == 4) {
765 this.fa = 'caret-down';
770 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
772 //gsRoo.log(this.parentType);
773 if (this.parentType === 'Navbar' && !this.parent().bar) {
774 Roo.log('changing to li?');
783 href : this.href || '#'
786 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
787 cfg.cls += ' dropdown';
794 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
796 if (this.glyphicon) {
797 cfg.html = ' ' + cfg.html;
802 cls: 'glyphicon glyphicon-' + this.glyphicon
807 cfg.html = ' ' + cfg.html;
812 cls: 'fa fas fa-' + this.fa
822 // cfg.cls='btn roo-button';
826 var value = cfg.html;
831 cls: 'glyphicon glyphicon-' + this.glyphicon,
838 cls: 'fa fas fa-' + this.fa,
843 var bw = this.badge_weight.length ? this.badge_weight :
844 (this.weight.length ? this.weight : 'secondary');
845 bw = bw == 'default' ? 'secondary' : bw;
851 cls: 'badge badge-' + bw,
860 cfg.cls += ' dropdown';
861 cfg.html = typeof(cfg.html) != 'undefined' ?
862 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
865 if (cfg.tag !== 'a' && this.href !== '') {
866 throw "Tag must be a to set href.";
867 } else if (this.href.length > 0) {
868 cfg.href = this.href;
871 if(this.removeClass){
876 cfg.target = this.target;
881 initEvents: function() {
882 // Roo.log('init events?');
883 // Roo.log(this.el.dom);
886 if (typeof (this.menu) != 'undefined') {
887 this.menu.parentType = this.xtype;
888 this.menu.triggerEl = this.el;
889 this.addxtype(Roo.apply({}, this.menu));
893 if (this.el.hasClass('roo-button')) {
894 this.el.on('click', this.onClick, this);
896 this.el.select('.roo-button').on('click', this.onClick, this);
899 if(this.removeClass){
900 this.el.on('click', this.onClick, this);
903 this.el.enableDisplayMode();
906 onClick : function(e)
912 Roo.log('button on click ');
913 if(this.preventDefault){
917 if (this.pressed === true || this.pressed === false) {
918 this.toggleActive(e);
922 this.fireEvent('click', this, e);
926 * Enables this button
930 this.disabled = false;
931 this.el.removeClass('disabled');
935 * Disable this button
939 this.disabled = true;
940 this.el.addClass('disabled');
943 * sets the active state on/off,
944 * @param {Boolean} state (optional) Force a particular state
946 setActive : function(v) {
948 this.el[v ? 'addClass' : 'removeClass']('active');
952 * toggles the current active state
954 toggleActive : function(e)
956 this.setActive(!this.pressed);
957 this.fireEvent('toggle', this, e, !this.pressed);
960 * get the current active state
961 * @return {boolean} true if it's active
963 isActive : function()
965 return this.el.hasClass('active');
968 * set the text of the first selected button
970 setText : function(str)
972 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
975 * get the text of the first selected button
979 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
982 setWeight : function(str)
984 this.el.removeClass(this.weightClass);
986 var outline = this.outline ? 'outline-' : '';
987 if (str == 'default') {
988 this.el.addClass('btn-default btn-outline-secondary');
991 this.el.addClass('btn-' + outline + str);
1005 * @class Roo.bootstrap.Column
1006 * @extends Roo.bootstrap.Component
1007 * Bootstrap Column class
1008 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1009 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1010 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1011 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1012 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1013 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1014 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1015 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1018 * @cfg {Boolean} hidden (true|false) hide the element
1019 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1020 * @cfg {String} fa (ban|check|...) font awesome icon
1021 * @cfg {Number} fasize (1|2|....) font awsome size
1023 * @cfg {String} icon (info-sign|check|...) glyphicon name
1025 * @cfg {String} html content of column.
1028 * Create a new Column
1029 * @param {Object} config The config object
1032 Roo.bootstrap.Column = function(config){
1033 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1036 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1054 getAutoCreate : function(){
1055 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1063 ['xs','sm','md','lg'].map(function(size){
1064 //Roo.log( size + ':' + settings[size]);
1066 if (settings[size+'off'] !== false) {
1067 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1070 if (settings[size] === false) {
1074 if (!settings[size]) { // 0 = hidden
1075 cfg.cls += ' hidden-' + size;
1078 cfg.cls += ' col-' + size + '-' + settings[size];
1083 cfg.cls += ' hidden';
1086 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1087 cfg.cls +=' alert alert-' + this.alert;
1091 if (this.html.length) {
1092 cfg.html = this.html;
1096 if (this.fasize > 1) {
1097 fasize = ' fa-' + this.fasize + 'x';
1099 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1104 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1123 * @class Roo.bootstrap.Container
1124 * @extends Roo.bootstrap.Component
1125 * Bootstrap Container class
1126 * @cfg {Boolean} jumbotron is it a jumbotron element
1127 * @cfg {String} html content of element
1128 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1129 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1130 * @cfg {String} header content of header (for panel)
1131 * @cfg {String} footer content of footer (for panel)
1132 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1133 * @cfg {String} tag (header|aside|section) type of HTML tag.
1134 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1135 * @cfg {String} fa font awesome icon
1136 * @cfg {String} icon (info-sign|check|...) glyphicon name
1137 * @cfg {Boolean} hidden (true|false) hide the element
1138 * @cfg {Boolean} expandable (true|false) default false
1139 * @cfg {Boolean} expanded (true|false) default true
1140 * @cfg {String} rheader contet on the right of header
1141 * @cfg {Boolean} clickable (true|false) default false
1145 * Create a new Container
1146 * @param {Object} config The config object
1149 Roo.bootstrap.Container = function(config){
1150 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1156 * After the panel has been expand
1158 * @param {Roo.bootstrap.Container} this
1163 * After the panel has been collapsed
1165 * @param {Roo.bootstrap.Container} this
1170 * When a element is chick
1171 * @param {Roo.bootstrap.Container} this
1172 * @param {Roo.EventObject} e
1178 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1196 getChildContainer : function() {
1202 if (this.panel.length) {
1203 return this.el.select('.panel-body',true).first();
1210 getAutoCreate : function(){
1213 tag : this.tag || 'div',
1217 if (this.jumbotron) {
1218 cfg.cls = 'jumbotron';
1223 // - this is applied by the parent..
1225 // cfg.cls = this.cls + '';
1228 if (this.sticky.length) {
1230 var bd = Roo.get(document.body);
1231 if (!bd.hasClass('bootstrap-sticky')) {
1232 bd.addClass('bootstrap-sticky');
1233 Roo.select('html',true).setStyle('height', '100%');
1236 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1240 if (this.well.length) {
1241 switch (this.well) {
1244 cfg.cls +=' well well-' +this.well;
1253 cfg.cls += ' hidden';
1257 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1258 cfg.cls +=' alert alert-' + this.alert;
1263 if (this.panel.length) {
1264 cfg.cls += ' panel panel-' + this.panel;
1266 if (this.header.length) {
1270 if(this.expandable){
1272 cfg.cls = cfg.cls + ' expandable';
1276 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1284 cls : 'panel-title',
1285 html : (this.expandable ? ' ' : '') + this.header
1289 cls: 'panel-header-right',
1295 cls : 'panel-heading',
1296 style : this.expandable ? 'cursor: pointer' : '',
1304 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1309 if (this.footer.length) {
1311 cls : 'panel-footer',
1320 body.html = this.html || cfg.html;
1321 // prefix with the icons..
1323 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1326 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1331 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1332 cfg.cls = 'container';
1338 initEvents: function()
1340 if(this.expandable){
1341 var headerEl = this.headerEl();
1344 headerEl.on('click', this.onToggleClick, this);
1349 this.el.on('click', this.onClick, this);
1354 onToggleClick : function()
1356 var headerEl = this.headerEl();
1372 if(this.fireEvent('expand', this)) {
1374 this.expanded = true;
1376 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1378 this.el.select('.panel-body',true).first().removeClass('hide');
1380 var toggleEl = this.toggleEl();
1386 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1391 collapse : function()
1393 if(this.fireEvent('collapse', this)) {
1395 this.expanded = false;
1397 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1398 this.el.select('.panel-body',true).first().addClass('hide');
1400 var toggleEl = this.toggleEl();
1406 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1410 toggleEl : function()
1412 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1416 return this.el.select('.panel-heading .fa',true).first();
1419 headerEl : function()
1421 if(!this.el || !this.panel.length || !this.header.length){
1425 return this.el.select('.panel-heading',true).first()
1430 if(!this.el || !this.panel.length){
1434 return this.el.select('.panel-body',true).first()
1437 titleEl : function()
1439 if(!this.el || !this.panel.length || !this.header.length){
1443 return this.el.select('.panel-title',true).first();
1446 setTitle : function(v)
1448 var titleEl = this.titleEl();
1454 titleEl.dom.innerHTML = v;
1457 getTitle : function()
1460 var titleEl = this.titleEl();
1466 return titleEl.dom.innerHTML;
1469 setRightTitle : function(v)
1471 var t = this.el.select('.panel-header-right',true).first();
1477 t.dom.innerHTML = v;
1480 onClick : function(e)
1484 this.fireEvent('click', this, e);
1497 * @class Roo.bootstrap.Img
1498 * @extends Roo.bootstrap.Component
1499 * Bootstrap Img class
1500 * @cfg {Boolean} imgResponsive false | true
1501 * @cfg {String} border rounded | circle | thumbnail
1502 * @cfg {String} src image source
1503 * @cfg {String} alt image alternative text
1504 * @cfg {String} href a tag href
1505 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1506 * @cfg {String} xsUrl xs image source
1507 * @cfg {String} smUrl sm image source
1508 * @cfg {String} mdUrl md image source
1509 * @cfg {String} lgUrl lg image source
1512 * Create a new Input
1513 * @param {Object} config The config object
1516 Roo.bootstrap.Img = function(config){
1517 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1523 * The img click event for the img.
1524 * @param {Roo.EventObject} e
1530 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1532 imgResponsive: true,
1542 getAutoCreate : function()
1544 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1545 return this.createSingleImg();
1550 cls: 'roo-image-responsive-group',
1555 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1557 if(!_this[size + 'Url']){
1563 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1564 html: _this.html || cfg.html,
1565 src: _this[size + 'Url']
1568 img.cls += ' roo-image-responsive-' + size;
1570 var s = ['xs', 'sm', 'md', 'lg'];
1572 s.splice(s.indexOf(size), 1);
1574 Roo.each(s, function(ss){
1575 img.cls += ' hidden-' + ss;
1578 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1579 cfg.cls += ' img-' + _this.border;
1583 cfg.alt = _this.alt;
1596 a.target = _this.target;
1600 cfg.cn.push((_this.href) ? a : img);
1607 createSingleImg : function()
1611 cls: (this.imgResponsive) ? 'img-responsive' : '',
1613 src : 'about:blank' // just incase src get's set to undefined?!?
1616 cfg.html = this.html || cfg.html;
1618 cfg.src = this.src || cfg.src;
1620 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1621 cfg.cls += ' img-' + this.border;
1638 a.target = this.target;
1643 return (this.href) ? a : cfg;
1646 initEvents: function()
1649 this.el.on('click', this.onClick, this);
1654 onClick : function(e)
1656 Roo.log('img onclick');
1657 this.fireEvent('click', this, e);
1660 * Sets the url of the image - used to update it
1661 * @param {String} url the url of the image
1664 setSrc : function(url)
1668 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1669 this.el.dom.src = url;
1673 this.el.select('img', true).first().dom.src = url;
1689 * @class Roo.bootstrap.Link
1690 * @extends Roo.bootstrap.Component
1691 * Bootstrap Link Class
1692 * @cfg {String} alt image alternative text
1693 * @cfg {String} href a tag href
1694 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1695 * @cfg {String} html the content of the link.
1696 * @cfg {String} anchor name for the anchor link
1697 * @cfg {String} fa - favicon
1699 * @cfg {Boolean} preventDefault (true | false) default false
1703 * Create a new Input
1704 * @param {Object} config The config object
1707 Roo.bootstrap.Link = function(config){
1708 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1714 * The img click event for the img.
1715 * @param {Roo.EventObject} e
1721 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1725 preventDefault: false,
1731 getAutoCreate : function()
1733 var html = this.html || '';
1735 if (this.fa !== false) {
1736 html = '<i class="fa fa-' + this.fa + '"></i>';
1741 // anchor's do not require html/href...
1742 if (this.anchor === false) {
1744 cfg.href = this.href || '#';
1746 cfg.name = this.anchor;
1747 if (this.html !== false || this.fa !== false) {
1750 if (this.href !== false) {
1751 cfg.href = this.href;
1755 if(this.alt !== false){
1760 if(this.target !== false) {
1761 cfg.target = this.target;
1767 initEvents: function() {
1769 if(!this.href || this.preventDefault){
1770 this.el.on('click', this.onClick, this);
1774 onClick : function(e)
1776 if(this.preventDefault){
1779 //Roo.log('img onclick');
1780 this.fireEvent('click', this, e);
1793 * @class Roo.bootstrap.Header
1794 * @extends Roo.bootstrap.Component
1795 * Bootstrap Header class
1796 * @cfg {String} html content of header
1797 * @cfg {Number} level (1|2|3|4|5|6) default 1
1800 * Create a new Header
1801 * @param {Object} config The config object
1805 Roo.bootstrap.Header = function(config){
1806 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1809 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1817 getAutoCreate : function(){
1822 tag: 'h' + (1 *this.level),
1823 html: this.html || ''
1835 * Ext JS Library 1.1.1
1836 * Copyright(c) 2006-2007, Ext JS, LLC.
1838 * Originally Released Under LGPL - original licence link has changed is not relivant.
1841 * <script type="text/javascript">
1845 * @class Roo.bootstrap.MenuMgr
1846 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1849 Roo.bootstrap.MenuMgr = function(){
1850 var menus, active, groups = {}, attached = false, lastShow = new Date();
1852 // private - called when first menu is created
1855 active = new Roo.util.MixedCollection();
1856 Roo.get(document).addKeyListener(27, function(){
1857 if(active.length > 0){
1865 if(active && active.length > 0){
1866 var c = active.clone();
1876 if(active.length < 1){
1877 Roo.get(document).un("mouseup", onMouseDown);
1885 var last = active.last();
1886 lastShow = new Date();
1889 Roo.get(document).on("mouseup", onMouseDown);
1894 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1895 m.parentMenu.activeChild = m;
1896 }else if(last && last.isVisible()){
1897 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1902 function onBeforeHide(m){
1904 m.activeChild.hide();
1906 if(m.autoHideTimer){
1907 clearTimeout(m.autoHideTimer);
1908 delete m.autoHideTimer;
1913 function onBeforeShow(m){
1914 var pm = m.parentMenu;
1915 if(!pm && !m.allowOtherMenus){
1917 }else if(pm && pm.activeChild && active != m){
1918 pm.activeChild.hide();
1922 // private this should really trigger on mouseup..
1923 function onMouseDown(e){
1924 Roo.log("on Mouse Up");
1926 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1927 Roo.log("MenuManager hideAll");
1936 function onBeforeCheck(mi, state){
1938 var g = groups[mi.group];
1939 for(var i = 0, l = g.length; i < l; i++){
1941 g[i].setChecked(false);
1950 * Hides all menus that are currently visible
1952 hideAll : function(){
1957 register : function(menu){
1961 menus[menu.id] = menu;
1962 menu.on("beforehide", onBeforeHide);
1963 menu.on("hide", onHide);
1964 menu.on("beforeshow", onBeforeShow);
1965 menu.on("show", onShow);
1967 if(g && menu.events["checkchange"]){
1971 groups[g].push(menu);
1972 menu.on("checkchange", onCheck);
1977 * Returns a {@link Roo.menu.Menu} object
1978 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1979 * be used to generate and return a new Menu instance.
1981 get : function(menu){
1982 if(typeof menu == "string"){ // menu id
1984 }else if(menu.events){ // menu instance
1987 /*else if(typeof menu.length == 'number'){ // array of menu items?
1988 return new Roo.bootstrap.Menu({items:menu});
1989 }else{ // otherwise, must be a config
1990 return new Roo.bootstrap.Menu(menu);
1997 unregister : function(menu){
1998 delete menus[menu.id];
1999 menu.un("beforehide", onBeforeHide);
2000 menu.un("hide", onHide);
2001 menu.un("beforeshow", onBeforeShow);
2002 menu.un("show", onShow);
2004 if(g && menu.events["checkchange"]){
2005 groups[g].remove(menu);
2006 menu.un("checkchange", onCheck);
2011 registerCheckable : function(menuItem){
2012 var g = menuItem.group;
2017 groups[g].push(menuItem);
2018 menuItem.on("beforecheckchange", onBeforeCheck);
2023 unregisterCheckable : function(menuItem){
2024 var g = menuItem.group;
2026 groups[g].remove(menuItem);
2027 menuItem.un("beforecheckchange", onBeforeCheck);
2039 * @class Roo.bootstrap.Menu
2040 * @extends Roo.bootstrap.Component
2041 * Bootstrap Menu class - container for MenuItems
2042 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2043 * @cfg {bool} hidden if the menu should be hidden when rendered.
2044 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2045 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2049 * @param {Object} config The config object
2053 Roo.bootstrap.Menu = function(config){
2054 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2055 if (this.registerMenu && this.type != 'treeview') {
2056 Roo.bootstrap.MenuMgr.register(this);
2063 * Fires before this menu is displayed
2064 * @param {Roo.menu.Menu} this
2069 * Fires before this menu is hidden
2070 * @param {Roo.menu.Menu} this
2075 * Fires after this menu is displayed
2076 * @param {Roo.menu.Menu} this
2081 * Fires after this menu is hidden
2082 * @param {Roo.menu.Menu} this
2087 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2088 * @param {Roo.menu.Menu} this
2089 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2090 * @param {Roo.EventObject} e
2095 * Fires when the mouse is hovering over this menu
2096 * @param {Roo.menu.Menu} this
2097 * @param {Roo.EventObject} e
2098 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2103 * Fires when the mouse exits this menu
2104 * @param {Roo.menu.Menu} this
2105 * @param {Roo.EventObject} e
2106 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2111 * Fires when a menu item contained in this menu is clicked
2112 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2113 * @param {Roo.EventObject} e
2117 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2120 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2124 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2127 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2129 registerMenu : true,
2131 menuItems :false, // stores the menu items..
2141 getChildContainer : function() {
2145 getAutoCreate : function(){
2147 //if (['right'].indexOf(this.align)!==-1) {
2148 // cfg.cn[1].cls += ' pull-right'
2154 cls : 'dropdown-menu' ,
2155 style : 'z-index:1000'
2159 if (this.type === 'submenu') {
2160 cfg.cls = 'submenu active';
2162 if (this.type === 'treeview') {
2163 cfg.cls = 'treeview-menu';
2168 initEvents : function() {
2170 // Roo.log("ADD event");
2171 // Roo.log(this.triggerEl.dom);
2173 this.triggerEl.on('click', this.onTriggerClick, this);
2175 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2178 if (this.triggerEl.hasClass('nav-item')) {
2179 // dropdown toggle on the 'a' in BS4?
2180 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2182 this.triggerEl.addClass('dropdown-toggle');
2185 this.el.on('touchstart' , this.onTouch, this);
2187 this.el.on('click' , this.onClick, this);
2189 this.el.on("mouseover", this.onMouseOver, this);
2190 this.el.on("mouseout", this.onMouseOut, this);
2194 findTargetItem : function(e)
2196 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2200 //Roo.log(t); Roo.log(t.id);
2202 //Roo.log(this.menuitems);
2203 return this.menuitems.get(t.id);
2205 //return this.items.get(t.menuItemId);
2211 onTouch : function(e)
2213 Roo.log("menu.onTouch");
2214 //e.stopEvent(); this make the user popdown broken
2218 onClick : function(e)
2220 Roo.log("menu.onClick");
2222 var t = this.findTargetItem(e);
2223 if(!t || t.isContainer){
2228 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2229 if(t == this.activeItem && t.shouldDeactivate(e)){
2230 this.activeItem.deactivate();
2231 delete this.activeItem;
2235 this.setActiveItem(t, true);
2243 Roo.log('pass click event');
2247 this.fireEvent("click", this, t, e);
2251 if(!t.href.length || t.href == '#'){
2252 (function() { _this.hide(); }).defer(100);
2257 onMouseOver : function(e){
2258 var t = this.findTargetItem(e);
2261 // if(t.canActivate && !t.disabled){
2262 // this.setActiveItem(t, true);
2266 this.fireEvent("mouseover", this, e, t);
2268 isVisible : function(){
2269 return !this.hidden;
2271 onMouseOut : function(e){
2272 var t = this.findTargetItem(e);
2275 // if(t == this.activeItem && t.shouldDeactivate(e)){
2276 // this.activeItem.deactivate();
2277 // delete this.activeItem;
2280 this.fireEvent("mouseout", this, e, t);
2285 * Displays this menu relative to another element
2286 * @param {String/HTMLElement/Roo.Element} element The element to align to
2287 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2288 * the element (defaults to this.defaultAlign)
2289 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2291 show : function(el, pos, parentMenu){
2292 this.parentMenu = parentMenu;
2296 this.fireEvent("beforeshow", this);
2297 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2300 * Displays this menu at a specific xy position
2301 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2302 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2304 showAt : function(xy, parentMenu, /* private: */_e){
2305 this.parentMenu = parentMenu;
2310 this.fireEvent("beforeshow", this);
2311 //xy = this.el.adjustForConstraints(xy);
2315 this.hideMenuItems();
2316 this.hidden = false;
2317 this.triggerEl.addClass('open');
2318 this.el.addClass('show');
2320 // reassign x when hitting right
2321 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2322 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2325 // reassign y when hitting bottom
2326 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2327 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2330 // but the list may align on trigger left or trigger top... should it be a properity?
2332 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2337 this.fireEvent("show", this);
2343 this.doFocus.defer(50, this);
2347 doFocus : function(){
2349 this.focusEl.focus();
2354 * Hides this menu and optionally all parent menus
2355 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2357 hide : function(deep)
2360 this.hideMenuItems();
2361 if(this.el && this.isVisible()){
2362 this.fireEvent("beforehide", this);
2363 if(this.activeItem){
2364 this.activeItem.deactivate();
2365 this.activeItem = null;
2367 this.triggerEl.removeClass('open');;
2368 this.el.removeClass('show');
2370 this.fireEvent("hide", this);
2372 if(deep === true && this.parentMenu){
2373 this.parentMenu.hide(true);
2377 onTriggerClick : function(e)
2379 Roo.log('trigger click');
2381 var target = e.getTarget();
2383 Roo.log(target.nodeName.toLowerCase());
2385 if(target.nodeName.toLowerCase() === 'i'){
2391 onTriggerPress : function(e)
2393 Roo.log('trigger press');
2394 //Roo.log(e.getTarget());
2395 // Roo.log(this.triggerEl.dom);
2397 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2398 var pel = Roo.get(e.getTarget());
2399 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2400 Roo.log('is treeview or dropdown?');
2404 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2408 if (this.isVisible()) {
2413 this.show(this.triggerEl, false, false);
2416 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2423 hideMenuItems : function()
2425 Roo.log("hide Menu Items");
2429 //$(backdrop).remove()
2430 this.el.select('.open',true).each(function(aa) {
2432 aa.removeClass('open');
2433 //var parent = getParent($(this))
2434 //var relatedTarget = { relatedTarget: this }
2436 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2437 //if (e.isDefaultPrevented()) return
2438 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2441 addxtypeChild : function (tree, cntr) {
2442 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2444 this.menuitems.add(comp);
2456 this.getEl().dom.innerHTML = '';
2457 this.menuitems.clear();
2471 * @class Roo.bootstrap.MenuItem
2472 * @extends Roo.bootstrap.Component
2473 * Bootstrap MenuItem class
2474 * @cfg {String} html the menu label
2475 * @cfg {String} href the link
2476 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2477 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2478 * @cfg {Boolean} active used on sidebars to highlight active itesm
2479 * @cfg {String} fa favicon to show on left of menu item.
2480 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2484 * Create a new MenuItem
2485 * @param {Object} config The config object
2489 Roo.bootstrap.MenuItem = function(config){
2490 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2495 * The raw click event for the entire grid.
2496 * @param {Roo.bootstrap.MenuItem} this
2497 * @param {Roo.EventObject} e
2503 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2507 preventDefault: false,
2508 isContainer : false,
2512 getAutoCreate : function(){
2514 if(this.isContainer){
2517 cls: 'dropdown-menu-item '
2527 cls : 'dropdown-item',
2532 if (this.fa !== false) {
2535 cls : 'fa fa-' + this.fa
2544 cls: 'dropdown-menu-item',
2547 if (this.parent().type == 'treeview') {
2548 cfg.cls = 'treeview-menu';
2551 cfg.cls += ' active';
2556 anc.href = this.href || cfg.cn[0].href ;
2557 ctag.html = this.html || cfg.cn[0].html ;
2561 initEvents: function()
2563 if (this.parent().type == 'treeview') {
2564 this.el.select('a').on('click', this.onClick, this);
2568 this.menu.parentType = this.xtype;
2569 this.menu.triggerEl = this.el;
2570 this.menu = this.addxtype(Roo.apply({}, this.menu));
2574 onClick : function(e)
2576 Roo.log('item on click ');
2578 if(this.preventDefault){
2581 //this.parent().hideMenuItems();
2583 this.fireEvent('click', this, e);
2602 * @class Roo.bootstrap.MenuSeparator
2603 * @extends Roo.bootstrap.Component
2604 * Bootstrap MenuSeparator class
2607 * Create a new MenuItem
2608 * @param {Object} config The config object
2612 Roo.bootstrap.MenuSeparator = function(config){
2613 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2616 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2618 getAutoCreate : function(){
2637 * @class Roo.bootstrap.Modal
2638 * @extends Roo.bootstrap.Component
2639 * Bootstrap Modal class
2640 * @cfg {String} title Title of dialog
2641 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2642 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2643 * @cfg {Boolean} specificTitle default false
2644 * @cfg {Array} buttons Array of buttons or standard button set..
2645 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2646 * @cfg {Boolean} animate default true
2647 * @cfg {Boolean} allow_close default true
2648 * @cfg {Boolean} fitwindow default false
2649 * @cfg {String} size (sm|lg) default empty
2650 * @cfg {Number} max_width set the max width of modal
2654 * Create a new Modal Dialog
2655 * @param {Object} config The config object
2658 Roo.bootstrap.Modal = function(config){
2659 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2664 * The raw btnclick event for the button
2665 * @param {Roo.EventObject} e
2670 * Fire when dialog resize
2671 * @param {Roo.bootstrap.Modal} this
2672 * @param {Roo.EventObject} e
2676 this.buttons = this.buttons || [];
2679 this.tmpl = Roo.factory(this.tmpl);
2684 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2686 title : 'test dialog',
2696 specificTitle: false,
2698 buttonPosition: 'right',
2721 onRender : function(ct, position)
2723 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2726 var cfg = Roo.apply({}, this.getAutoCreate());
2729 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2731 //if (!cfg.name.length) {
2735 cfg.cls += ' ' + this.cls;
2738 cfg.style = this.style;
2740 this.el = Roo.get(document.body).createChild(cfg, position);
2742 //var type = this.el.dom.type;
2745 if(this.tabIndex !== undefined){
2746 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2749 this.dialogEl = this.el.select('.modal-dialog',true).first();
2750 this.bodyEl = this.el.select('.modal-body',true).first();
2751 this.closeEl = this.el.select('.modal-header .close', true).first();
2752 this.headerEl = this.el.select('.modal-header',true).first();
2753 this.titleEl = this.el.select('.modal-title',true).first();
2754 this.footerEl = this.el.select('.modal-footer',true).first();
2756 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2758 //this.el.addClass("x-dlg-modal");
2760 if (this.buttons.length) {
2761 Roo.each(this.buttons, function(bb) {
2762 var b = Roo.apply({}, bb);
2763 b.xns = b.xns || Roo.bootstrap;
2764 b.xtype = b.xtype || 'Button';
2765 if (typeof(b.listeners) == 'undefined') {
2766 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2769 var btn = Roo.factory(b);
2771 btn.render(this.getButtonContainer());
2775 // render the children.
2778 if(typeof(this.items) != 'undefined'){
2779 var items = this.items;
2782 for(var i =0;i < items.length;i++) {
2783 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2787 this.items = nitems;
2789 // where are these used - they used to be body/close/footer
2793 //this.el.addClass([this.fieldClass, this.cls]);
2797 getAutoCreate : function()
2801 html : this.html || ''
2806 cls : 'modal-title',
2810 if(this.specificTitle){
2816 if (this.allow_close && Roo.bootstrap.version == 3) {
2826 if (this.allow_close && Roo.bootstrap.version == 4) {
2836 if(this.size.length){
2837 size = 'modal-' + this.size;
2840 var footer = Roo.bootstrap.version == 3 ?
2842 cls : 'modal-footer',
2846 cls: 'btn-' + this.buttonPosition
2851 { // BS4 uses mr-auto on left buttons....
2852 cls : 'modal-footer'
2863 cls: "modal-dialog " + size,
2866 cls : "modal-content",
2869 cls : 'modal-header',
2884 modal.cls += ' fade';
2890 getChildContainer : function() {
2895 getButtonContainer : function() {
2897 return Roo.bootstrap.version == 4 ?
2898 this.el.select('.modal-footer',true).first()
2899 : this.el.select('.modal-footer div',true).first();
2902 initEvents : function()
2904 if (this.allow_close) {
2905 this.closeEl.on('click', this.hide, this);
2907 Roo.EventManager.onWindowResize(this.resize, this, true);
2914 this.maskEl.setSize(
2915 Roo.lib.Dom.getViewWidth(true),
2916 Roo.lib.Dom.getViewHeight(true)
2919 if (this.fitwindow) {
2921 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2922 this.height || Roo.lib.Dom.getViewportHeight(true) - 60
2927 if(this.max_width !== 0) {
2929 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2932 this.setSize(w, this.height);
2936 if(this.max_height) {
2937 this.setSize(w,Math.min(
2939 Roo.lib.Dom.getViewportHeight(true) - 60
2945 if(!this.fit_content) {
2946 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2950 this.setSize(w, Math.min(
2952 this.headerEl.getHeight() +
2953 this.footerEl.getHeight() +
2954 this.getChildHeight(this.bodyEl.dom.childNodes),
2955 Roo.lib.Dom.getViewportHeight(true) - 60)
2961 setSize : function(w,h)
2972 if (!this.rendered) {
2976 //this.el.setStyle('display', 'block');
2977 this.el.removeClass('hideing');
2978 this.el.dom.style.display='block';
2980 Roo.get(document.body).addClass('modal-open');
2982 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2985 this.el.addClass('show');
2986 this.el.addClass('in');
2989 this.el.addClass('show');
2990 this.el.addClass('in');
2993 // not sure how we can show data in here..
2995 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
2998 Roo.get(document.body).addClass("x-body-masked");
3000 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3001 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3002 this.maskEl.dom.style.display = 'block';
3003 this.maskEl.addClass('show');
3008 this.fireEvent('show', this);
3010 // set zindex here - otherwise it appears to be ignored...
3011 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3014 this.items.forEach( function(e) {
3015 e.layout ? e.layout() : false;
3023 if(this.fireEvent("beforehide", this) !== false){
3025 this.maskEl.removeClass('show');
3027 this.maskEl.dom.style.display = '';
3028 Roo.get(document.body).removeClass("x-body-masked");
3029 this.el.removeClass('in');
3030 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3032 if(this.animate){ // why
3033 this.el.addClass('hideing');
3034 this.el.removeClass('show');
3036 if (!this.el.hasClass('hideing')) {
3037 return; // it's been shown again...
3040 this.el.dom.style.display='';
3042 Roo.get(document.body).removeClass('modal-open');
3043 this.el.removeClass('hideing');
3047 this.el.removeClass('show');
3048 this.el.dom.style.display='';
3049 Roo.get(document.body).removeClass('modal-open');
3052 this.fireEvent('hide', this);
3055 isVisible : function()
3058 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3062 addButton : function(str, cb)
3066 var b = Roo.apply({}, { html : str } );
3067 b.xns = b.xns || Roo.bootstrap;
3068 b.xtype = b.xtype || 'Button';
3069 if (typeof(b.listeners) == 'undefined') {
3070 b.listeners = { click : cb.createDelegate(this) };
3073 var btn = Roo.factory(b);
3075 btn.render(this.getButtonContainer());
3081 setDefaultButton : function(btn)
3083 //this.el.select('.modal-footer').()
3087 resizeTo: function(w,h)
3091 this.dialogEl.setWidth(w);
3092 if (this.diff === false) {
3093 this.diff = this.dialogEl.getHeight() - this.bodyEl.getHeight();
3096 this.bodyEl.setHeight(h - this.diff);
3098 this.fireEvent('resize', this);
3101 setContentSize : function(w, h)
3105 onButtonClick: function(btn,e)
3108 this.fireEvent('btnclick', btn.name, e);
3111 * Set the title of the Dialog
3112 * @param {String} str new Title
3114 setTitle: function(str) {
3115 this.titleEl.dom.innerHTML = str;
3118 * Set the body of the Dialog
3119 * @param {String} str new Title
3121 setBody: function(str) {
3122 this.bodyEl.dom.innerHTML = str;
3125 * Set the body of the Dialog using the template
3126 * @param {Obj} data - apply this data to the template and replace the body contents.
3128 applyBody: function(obj)
3131 Roo.log("Error - using apply Body without a template");
3134 this.tmpl.overwrite(this.bodyEl, obj);
3137 getChildHeight : function(child_nodes)
3141 child_nodes.length == 0
3146 var child_height = 0;
3148 for(var i = 0; i < child_nodes.length; i++) {
3151 * for modal with tabs...
3152 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3154 var layout_childs = child_nodes[i].childNodes;
3156 for(var j = 0; j < layout_childs.length; j++) {
3158 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3160 var layout_body_childs = layout_childs[j].childNodes;
3162 for(var k = 0; k < layout_body_childs.length; k++) {
3164 if(layout_body_childs[k].classList.contains('navbar')) {
3165 child_height += layout_body_childs[k].offsetHeight;
3169 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3171 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3173 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3175 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3176 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3191 child_height += child_nodes[i].offsetHeight;
3192 // Roo.log(child_nodes[i].offsetHeight);
3195 return child_height;
3201 Roo.apply(Roo.bootstrap.Modal, {
3203 * Button config that displays a single OK button
3212 * Button config that displays Yes and No buttons
3228 * Button config that displays OK and Cancel buttons
3243 * Button config that displays Yes, No and Cancel buttons
3267 * messagebox - can be used as a replace
3271 * @class Roo.MessageBox
3272 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3276 Roo.Msg.alert('Status', 'Changes saved successfully.');
3278 // Prompt for user data:
3279 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3281 // process text value...
3285 // Show a dialog using config options:
3287 title:'Save Changes?',
3288 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3289 buttons: Roo.Msg.YESNOCANCEL,
3296 Roo.bootstrap.MessageBox = function(){
3297 var dlg, opt, mask, waitTimer;
3298 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3299 var buttons, activeTextEl, bwidth;
3303 var handleButton = function(button){
3305 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3309 var handleHide = function(){
3311 dlg.el.removeClass(opt.cls);
3314 // Roo.TaskMgr.stop(waitTimer);
3315 // waitTimer = null;
3320 var updateButtons = function(b){
3323 buttons["ok"].hide();
3324 buttons["cancel"].hide();
3325 buttons["yes"].hide();
3326 buttons["no"].hide();
3327 //dlg.footer.dom.style.display = 'none';
3330 dlg.footerEl.dom.style.display = '';
3331 for(var k in buttons){
3332 if(typeof buttons[k] != "function"){
3335 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3336 width += buttons[k].el.getWidth()+15;
3346 var handleEsc = function(d, k, e){
3347 if(opt && opt.closable !== false){
3357 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3358 * @return {Roo.BasicDialog} The BasicDialog element
3360 getDialog : function(){
3362 dlg = new Roo.bootstrap.Modal( {
3365 //constraintoviewport:false,
3367 //collapsible : false,
3372 //buttonAlign:"center",
3373 closeClick : function(){
3374 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3377 handleButton("cancel");
3382 dlg.on("hide", handleHide);
3384 //dlg.addKeyListener(27, handleEsc);
3386 this.buttons = buttons;
3387 var bt = this.buttonText;
3388 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3389 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3390 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3391 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3393 bodyEl = dlg.bodyEl.createChild({
3395 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3396 '<textarea class="roo-mb-textarea"></textarea>' +
3397 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3399 msgEl = bodyEl.dom.firstChild;
3400 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3401 textboxEl.enableDisplayMode();
3402 textboxEl.addKeyListener([10,13], function(){
3403 if(dlg.isVisible() && opt && opt.buttons){
3406 }else if(opt.buttons.yes){
3407 handleButton("yes");
3411 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3412 textareaEl.enableDisplayMode();
3413 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3414 progressEl.enableDisplayMode();
3416 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3417 var pf = progressEl.dom.firstChild;
3419 pp = Roo.get(pf.firstChild);
3420 pp.setHeight(pf.offsetHeight);
3428 * Updates the message box body text
3429 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3430 * the XHTML-compliant non-breaking space character '&#160;')
3431 * @return {Roo.MessageBox} This message box
3433 updateText : function(text)
3435 if(!dlg.isVisible() && !opt.width){
3436 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3437 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3439 msgEl.innerHTML = text || ' ';
3441 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3442 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3444 Math.min(opt.width || cw , this.maxWidth),
3445 Math.max(opt.minWidth || this.minWidth, bwidth)
3448 activeTextEl.setWidth(w);
3450 if(dlg.isVisible()){
3451 dlg.fixedcenter = false;
3453 // to big, make it scroll. = But as usual stupid IE does not support
3456 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3457 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3458 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3460 bodyEl.dom.style.height = '';
3461 bodyEl.dom.style.overflowY = '';
3464 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3466 bodyEl.dom.style.overflowX = '';
3469 dlg.setContentSize(w, bodyEl.getHeight());
3470 if(dlg.isVisible()){
3471 dlg.fixedcenter = true;
3477 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3478 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3479 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3480 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3481 * @return {Roo.MessageBox} This message box
3483 updateProgress : function(value, text){
3485 this.updateText(text);
3488 if (pp) { // weird bug on my firefox - for some reason this is not defined
3489 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3490 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3496 * Returns true if the message box is currently displayed
3497 * @return {Boolean} True if the message box is visible, else false
3499 isVisible : function(){
3500 return dlg && dlg.isVisible();
3504 * Hides the message box if it is displayed
3507 if(this.isVisible()){
3513 * Displays a new message box, or reinitializes an existing message box, based on the config options
3514 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3515 * The following config object properties are supported:
3517 Property Type Description
3518 ---------- --------------- ------------------------------------------------------------------------------------
3519 animEl String/Element An id or Element from which the message box should animate as it opens and
3520 closes (defaults to undefined)
3521 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3522 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3523 closable Boolean False to hide the top-right close button (defaults to true). Note that
3524 progress and wait dialogs will ignore this property and always hide the
3525 close button as they can only be closed programmatically.
3526 cls String A custom CSS class to apply to the message box element
3527 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3528 displayed (defaults to 75)
3529 fn Function A callback function to execute after closing the dialog. The arguments to the
3530 function will be btn (the name of the button that was clicked, if applicable,
3531 e.g. "ok"), and text (the value of the active text field, if applicable).
3532 Progress and wait dialogs will ignore this option since they do not respond to
3533 user actions and can only be closed programmatically, so any required function
3534 should be called by the same code after it closes the dialog.
3535 icon String A CSS class that provides a background image to be used as an icon for
3536 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3537 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3538 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3539 modal Boolean False to allow user interaction with the page while the message box is
3540 displayed (defaults to true)
3541 msg String A string that will replace the existing message box body text (defaults
3542 to the XHTML-compliant non-breaking space character ' ')
3543 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3544 progress Boolean True to display a progress bar (defaults to false)
3545 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3546 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3547 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3548 title String The title text
3549 value String The string value to set into the active textbox element if displayed
3550 wait Boolean True to display a progress bar (defaults to false)
3551 width Number The width of the dialog in pixels
3558 msg: 'Please enter your address:',
3560 buttons: Roo.MessageBox.OKCANCEL,
3563 animEl: 'addAddressBtn'
3566 * @param {Object} config Configuration options
3567 * @return {Roo.MessageBox} This message box
3569 show : function(options)
3572 // this causes nightmares if you show one dialog after another
3573 // especially on callbacks..
3575 if(this.isVisible()){
3578 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3579 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3580 Roo.log("New Dialog Message:" + options.msg )
3581 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3582 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3585 var d = this.getDialog();
3587 d.setTitle(opt.title || " ");
3588 d.closeEl.setDisplayed(opt.closable !== false);
3589 activeTextEl = textboxEl;
3590 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3595 textareaEl.setHeight(typeof opt.multiline == "number" ?
3596 opt.multiline : this.defaultTextHeight);
3597 activeTextEl = textareaEl;
3606 progressEl.setDisplayed(opt.progress === true);
3607 this.updateProgress(0);
3608 activeTextEl.dom.value = opt.value || "";
3610 dlg.setDefaultButton(activeTextEl);
3612 var bs = opt.buttons;
3616 }else if(bs && bs.yes){
3617 db = buttons["yes"];
3619 dlg.setDefaultButton(db);
3621 bwidth = updateButtons(opt.buttons);
3622 this.updateText(opt.msg);
3624 d.el.addClass(opt.cls);
3626 d.proxyDrag = opt.proxyDrag === true;
3627 d.modal = opt.modal !== false;
3628 d.mask = opt.modal !== false ? mask : false;
3630 // force it to the end of the z-index stack so it gets a cursor in FF
3631 document.body.appendChild(dlg.el.dom);
3632 d.animateTarget = null;
3633 d.show(options.animEl);
3639 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3640 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3641 * and closing the message box when the process is complete.
3642 * @param {String} title The title bar text
3643 * @param {String} msg The message box body text
3644 * @return {Roo.MessageBox} This message box
3646 progress : function(title, msg){
3653 minWidth: this.minProgressWidth,
3660 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3661 * If a callback function is passed it will be called after the user clicks the button, and the
3662 * id of the button that was clicked will be passed as the only parameter to the callback
3663 * (could also be the top-right close button).
3664 * @param {String} title The title bar text
3665 * @param {String} msg The message box body text
3666 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3667 * @param {Object} scope (optional) The scope of the callback function
3668 * @return {Roo.MessageBox} This message box
3670 alert : function(title, msg, fn, scope)
3685 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3686 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3687 * You are responsible for closing the message box when the process is complete.
3688 * @param {String} msg The message box body text
3689 * @param {String} title (optional) The title bar text
3690 * @return {Roo.MessageBox} This message box
3692 wait : function(msg, title){
3703 waitTimer = Roo.TaskMgr.start({
3705 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3713 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3714 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3715 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3716 * @param {String} title The title bar text
3717 * @param {String} msg The message box body text
3718 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3719 * @param {Object} scope (optional) The scope of the callback function
3720 * @return {Roo.MessageBox} This message box
3722 confirm : function(title, msg, fn, scope){
3726 buttons: this.YESNO,
3735 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3736 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3737 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3738 * (could also be the top-right close button) and the text that was entered will be passed as the two
3739 * parameters to the callback.
3740 * @param {String} title The title bar text
3741 * @param {String} msg The message box body text
3742 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3743 * @param {Object} scope (optional) The scope of the callback function
3744 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3745 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3746 * @return {Roo.MessageBox} This message box
3748 prompt : function(title, msg, fn, scope, multiline){
3752 buttons: this.OKCANCEL,
3757 multiline: multiline,
3764 * Button config that displays a single OK button
3769 * Button config that displays Yes and No buttons
3772 YESNO : {yes:true, no:true},
3774 * Button config that displays OK and Cancel buttons
3777 OKCANCEL : {ok:true, cancel:true},
3779 * Button config that displays Yes, No and Cancel buttons
3782 YESNOCANCEL : {yes:true, no:true, cancel:true},
3785 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3788 defaultTextHeight : 75,
3790 * The maximum width in pixels of the message box (defaults to 600)
3795 * The minimum width in pixels of the message box (defaults to 100)
3800 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3801 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3804 minProgressWidth : 250,
3806 * An object containing the default button text strings that can be overriden for localized language support.
3807 * Supported properties are: ok, cancel, yes and no.
3808 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3821 * Shorthand for {@link Roo.MessageBox}
3823 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3824 Roo.Msg = Roo.Msg || Roo.MessageBox;
3833 * @class Roo.bootstrap.Navbar
3834 * @extends Roo.bootstrap.Component
3835 * Bootstrap Navbar class
3838 * Create a new Navbar
3839 * @param {Object} config The config object
3843 Roo.bootstrap.Navbar = function(config){
3844 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3848 * @event beforetoggle
3849 * Fire before toggle the menu
3850 * @param {Roo.EventObject} e
3852 "beforetoggle" : true
3856 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3865 getAutoCreate : function(){
3868 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3872 initEvents :function ()
3874 //Roo.log(this.el.select('.navbar-toggle',true));
3875 this.el.select('.navbar-toggle',true).on('click', function() {
3876 if(this.fireEvent('beforetoggle', this) !== false){
3877 var ce = this.el.select('.navbar-collapse',true).first();
3878 ce.toggleClass('in'); // old...
3879 if (ce.hasClass('collapse')) {
3881 ce.removeClass('collapse');
3882 ce.addClass('show');
3883 var h = ce.getHeight();
3885 ce.removeClass('show');
3886 // at this point we should be able to see it..
3887 ce.addClass('collapsing');
3889 ce.setHeight(0); // resize it ...
3890 ce.on('transitionend', function() {
3891 Roo.log('done transition');
3892 ce.removeClass('collapsing');
3893 ce.addClass('show');
3894 ce.removeClass('collapse');
3896 ce.dom.style.height = '';
3897 }, this, { single: true} );
3901 ce.setHeight(ce.getHeight());
3902 ce.removeClass('show');
3903 ce.addClass('collapsing');
3905 ce.on('transitionend', function() {
3906 ce.dom.style.height = '';
3907 ce.removeClass('collapsing');
3908 ce.addClass('collapse');
3909 }, this, { single: true} );
3921 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3923 var size = this.el.getSize();
3924 this.maskEl.setSize(size.width, size.height);
3925 this.maskEl.enableDisplayMode("block");
3934 getChildContainer : function()
3936 if (this.el.select('.collapse').getCount()) {
3937 return this.el.select('.collapse',true).first();
3970 * @class Roo.bootstrap.NavSimplebar
3971 * @extends Roo.bootstrap.Navbar
3972 * Bootstrap Sidebar class
3974 * @cfg {Boolean} inverse is inverted color
3976 * @cfg {String} type (nav | pills | tabs)
3977 * @cfg {Boolean} arrangement stacked | justified
3978 * @cfg {String} align (left | right) alignment
3980 * @cfg {Boolean} main (true|false) main nav bar? default false
3981 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3983 * @cfg {String} tag (header|footer|nav|div) default is nav
3985 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
3989 * Create a new Sidebar
3990 * @param {Object} config The config object
3994 Roo.bootstrap.NavSimplebar = function(config){
3995 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
3998 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4014 getAutoCreate : function(){
4018 tag : this.tag || 'div',
4019 cls : 'navbar navbar-expand-lg'
4021 if (['light','white'].indexOf(this.weight) > -1) {
4022 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4024 cfg.cls += ' bg-' + this.weight;
4027 cfg.cls += ' navbar-inverse';
4031 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4033 if (Roo.bootstrap.version == 4) {
4045 this.type = this.type || 'nav';
4046 if (['tabs','pills'].indexOf(this.type)!==-1) {
4047 cfg.cn[0].cls += ' nav-' + this.type
4051 if (this.type!=='nav') {
4052 Roo.log('nav type must be nav/tabs/pills')
4054 cfg.cn[0].cls += ' navbar-nav'
4060 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
4061 cfg.cn[0].cls += ' nav-' + this.arrangement;
4065 if (this.align === 'right') {
4066 cfg.cn[0].cls += ' navbar-right';
4091 * navbar-expand-md fixed-top
4095 * @class Roo.bootstrap.NavHeaderbar
4096 * @extends Roo.bootstrap.NavSimplebar
4097 * Bootstrap Sidebar class
4099 * @cfg {String} brand what is brand
4100 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4101 * @cfg {String} brand_href href of the brand
4102 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4103 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4104 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4105 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4108 * Create a new Sidebar
4109 * @param {Object} config The config object
4113 Roo.bootstrap.NavHeaderbar = function(config){
4114 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4118 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4125 desktopCenter : false,
4128 getAutoCreate : function(){
4131 tag: this.nav || 'nav',
4132 cls: 'navbar navbar-expand-md',
4138 if (this.desktopCenter) {
4139 cn.push({cls : 'container', cn : []});
4147 cls: 'navbar-toggle navbar-toggler',
4148 'data-toggle': 'collapse',
4153 html: 'Toggle navigation'
4157 cls: 'icon-bar navbar-toggler-icon'
4170 cn.push( Roo.bootstrap.version == 4 ? btn : {
4172 cls: 'navbar-header',
4181 cls: 'collapse navbar-collapse',
4185 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4187 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4188 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4190 // tag can override this..
4192 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4195 if (this.brand !== '') {
4196 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4197 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4199 href: this.brand_href ? this.brand_href : '#',
4200 cls: 'navbar-brand',
4208 cfg.cls += ' main-nav';
4216 getHeaderChildContainer : function()
4218 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4219 return this.el.select('.navbar-header',true).first();
4222 return this.getChildContainer();
4226 initEvents : function()
4228 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4230 if (this.autohide) {
4235 Roo.get(document).on('scroll',function(e) {
4236 var ns = Roo.get(document).getScroll().top;
4237 var os = prevScroll;
4241 ft.removeClass('slideDown');
4242 ft.addClass('slideUp');
4245 ft.removeClass('slideUp');
4246 ft.addClass('slideDown');
4267 * @class Roo.bootstrap.NavSidebar
4268 * @extends Roo.bootstrap.Navbar
4269 * Bootstrap Sidebar class
4272 * Create a new Sidebar
4273 * @param {Object} config The config object
4277 Roo.bootstrap.NavSidebar = function(config){
4278 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4281 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4283 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4285 getAutoCreate : function(){
4290 cls: 'sidebar sidebar-nav'
4312 * @class Roo.bootstrap.NavGroup
4313 * @extends Roo.bootstrap.Component
4314 * Bootstrap NavGroup class
4315 * @cfg {String} align (left|right)
4316 * @cfg {Boolean} inverse
4317 * @cfg {String} type (nav|pills|tab) default nav
4318 * @cfg {String} navId - reference Id for navbar.
4322 * Create a new nav group
4323 * @param {Object} config The config object
4326 Roo.bootstrap.NavGroup = function(config){
4327 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4330 Roo.bootstrap.NavGroup.register(this);
4334 * Fires when the active item changes
4335 * @param {Roo.bootstrap.NavGroup} this
4336 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4337 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4344 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4355 getAutoCreate : function()
4357 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4364 if (['tabs','pills'].indexOf(this.type)!==-1) {
4365 cfg.cls += ' nav-' + this.type
4367 if (this.type!=='nav') {
4368 Roo.log('nav type must be nav/tabs/pills')
4370 cfg.cls += ' navbar-nav'
4373 if (this.parent() && this.parent().sidebar) {
4376 cls: 'dashboard-menu sidebar-menu'
4382 if (this.form === true) {
4388 if (this.align === 'right') {
4389 cfg.cls += ' navbar-right ml-md-auto';
4391 cfg.cls += ' navbar-left';
4395 if (this.align === 'right') {
4396 cfg.cls += ' navbar-right ml-md-auto';
4398 cfg.cls += ' mr-auto';
4402 cfg.cls += ' navbar-inverse';
4410 * sets the active Navigation item
4411 * @param {Roo.bootstrap.NavItem} the new current navitem
4413 setActiveItem : function(item)
4416 Roo.each(this.navItems, function(v){
4421 v.setActive(false, true);
4428 item.setActive(true, true);
4429 this.fireEvent('changed', this, item, prev);
4434 * gets the active Navigation item
4435 * @return {Roo.bootstrap.NavItem} the current navitem
4437 getActive : function()
4441 Roo.each(this.navItems, function(v){
4452 indexOfNav : function()
4456 Roo.each(this.navItems, function(v,i){
4467 * adds a Navigation item
4468 * @param {Roo.bootstrap.NavItem} the navitem to add
4470 addItem : function(cfg)
4472 var cn = new Roo.bootstrap.NavItem(cfg);
4474 cn.parentId = this.id;
4475 cn.onRender(this.el, null);
4479 * register a Navigation item
4480 * @param {Roo.bootstrap.NavItem} the navitem to add
4482 register : function(item)
4484 this.navItems.push( item);
4485 item.navId = this.navId;
4490 * clear all the Navigation item
4493 clearAll : function()
4496 this.el.dom.innerHTML = '';
4499 getNavItem: function(tabId)
4502 Roo.each(this.navItems, function(e) {
4503 if (e.tabId == tabId) {
4513 setActiveNext : function()
4515 var i = this.indexOfNav(this.getActive());
4516 if (i > this.navItems.length) {
4519 this.setActiveItem(this.navItems[i+1]);
4521 setActivePrev : function()
4523 var i = this.indexOfNav(this.getActive());
4527 this.setActiveItem(this.navItems[i-1]);
4529 clearWasActive : function(except) {
4530 Roo.each(this.navItems, function(e) {
4531 if (e.tabId != except.tabId && e.was_active) {
4532 e.was_active = false;
4539 getWasActive : function ()
4542 Roo.each(this.navItems, function(e) {
4557 Roo.apply(Roo.bootstrap.NavGroup, {
4561 * register a Navigation Group
4562 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4564 register : function(navgrp)
4566 this.groups[navgrp.navId] = navgrp;
4570 * fetch a Navigation Group based on the navigation ID
4571 * @param {string} the navgroup to add
4572 * @returns {Roo.bootstrap.NavGroup} the navgroup
4574 get: function(navId) {
4575 if (typeof(this.groups[navId]) == 'undefined') {
4577 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4579 return this.groups[navId] ;
4594 * @class Roo.bootstrap.NavItem
4595 * @extends Roo.bootstrap.Component
4596 * Bootstrap Navbar.NavItem class
4597 * @cfg {String} href link to
4598 * @cfg {String} html content of button
4599 * @cfg {String} badge text inside badge
4600 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4601 * @cfg {String} glyphicon DEPRICATED - use fa
4602 * @cfg {String} icon DEPRICATED - use fa
4603 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4604 * @cfg {Boolean} active Is item active
4605 * @cfg {Boolean} disabled Is item disabled
4607 * @cfg {Boolean} preventDefault (true | false) default false
4608 * @cfg {String} tabId the tab that this item activates.
4609 * @cfg {String} tagtype (a|span) render as a href or span?
4610 * @cfg {Boolean} animateRef (true|false) link to element default false
4613 * Create a new Navbar Item
4614 * @param {Object} config The config object
4616 Roo.bootstrap.NavItem = function(config){
4617 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4622 * The raw click event for the entire grid.
4623 * @param {Roo.EventObject} e
4628 * Fires when the active item active state changes
4629 * @param {Roo.bootstrap.NavItem} this
4630 * @param {boolean} state the new state
4636 * Fires when scroll to element
4637 * @param {Roo.bootstrap.NavItem} this
4638 * @param {Object} options
4639 * @param {Roo.EventObject} e
4647 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4656 preventDefault : false,
4663 getAutoCreate : function(){
4672 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4674 if (this.disabled) {
4675 cfg.cls += ' disabled';
4678 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4682 href : this.href || "#",
4683 html: this.html || ''
4686 if (this.tagtype == 'a') {
4687 cfg.cn[0].cls = 'nav-link';
4690 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4693 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>'
4695 if(this.glyphicon) {
4696 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4701 cfg.cn[0].html += " <span class='caret'></span>";
4705 if (this.badge !== '') {
4707 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4715 initEvents: function()
4717 if (typeof (this.menu) != 'undefined') {
4718 this.menu.parentType = this.xtype;
4719 this.menu.triggerEl = this.el;
4720 this.menu = this.addxtype(Roo.apply({}, this.menu));
4723 this.el.select('a',true).on('click', this.onClick, this);
4725 if(this.tagtype == 'span'){
4726 this.el.select('span',true).on('click', this.onClick, this);
4729 // at this point parent should be available..
4730 this.parent().register(this);
4733 onClick : function(e)
4735 if (e.getTarget('.dropdown-menu-item')) {
4736 // did you click on a menu itemm.... - then don't trigger onclick..
4741 this.preventDefault ||
4744 Roo.log("NavItem - prevent Default?");
4748 if (this.disabled) {
4752 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4753 if (tg && tg.transition) {
4754 Roo.log("waiting for the transitionend");
4760 //Roo.log("fire event clicked");
4761 if(this.fireEvent('click', this, e) === false){
4765 if(this.tagtype == 'span'){
4769 //Roo.log(this.href);
4770 var ael = this.el.select('a',true).first();
4773 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4774 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4775 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4776 return; // ignore... - it's a 'hash' to another page.
4778 Roo.log("NavItem - prevent Default?");
4780 this.scrollToElement(e);
4784 var p = this.parent();
4786 if (['tabs','pills'].indexOf(p.type)!==-1) {
4787 if (typeof(p.setActiveItem) !== 'undefined') {
4788 p.setActiveItem(this);
4792 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4793 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4794 // remove the collapsed menu expand...
4795 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4799 isActive: function () {
4802 setActive : function(state, fire, is_was_active)
4804 if (this.active && !state && this.navId) {
4805 this.was_active = true;
4806 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4808 nv.clearWasActive(this);
4812 this.active = state;
4815 this.el.removeClass('active');
4816 } else if (!this.el.hasClass('active')) {
4817 this.el.addClass('active');
4820 this.fireEvent('changed', this, state);
4823 // show a panel if it's registered and related..
4825 if (!this.navId || !this.tabId || !state || is_was_active) {
4829 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4833 var pan = tg.getPanelByName(this.tabId);
4837 // if we can not flip to new panel - go back to old nav highlight..
4838 if (false == tg.showPanel(pan)) {
4839 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4841 var onav = nv.getWasActive();
4843 onav.setActive(true, false, true);
4852 // this should not be here...
4853 setDisabled : function(state)
4855 this.disabled = state;
4857 this.el.removeClass('disabled');
4858 } else if (!this.el.hasClass('disabled')) {
4859 this.el.addClass('disabled');
4865 * Fetch the element to display the tooltip on.
4866 * @return {Roo.Element} defaults to this.el
4868 tooltipEl : function()
4870 return this.el.select('' + this.tagtype + '', true).first();
4873 scrollToElement : function(e)
4875 var c = document.body;
4878 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4880 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4881 c = document.documentElement;
4884 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4890 var o = target.calcOffsetsTo(c);
4897 this.fireEvent('scrollto', this, options, e);
4899 Roo.get(c).scrollTo('top', options.value, true);
4912 * <span> icon </span>
4913 * <span> text </span>
4914 * <span>badge </span>
4918 * @class Roo.bootstrap.NavSidebarItem
4919 * @extends Roo.bootstrap.NavItem
4920 * Bootstrap Navbar.NavSidebarItem class
4921 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4922 * {Boolean} open is the menu open
4923 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4924 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4925 * {String} buttonSize (sm|md|lg)the extra classes for the button
4926 * {Boolean} showArrow show arrow next to the text (default true)
4928 * Create a new Navbar Button
4929 * @param {Object} config The config object
4931 Roo.bootstrap.NavSidebarItem = function(config){
4932 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4937 * The raw click event for the entire grid.
4938 * @param {Roo.EventObject} e
4943 * Fires when the active item active state changes
4944 * @param {Roo.bootstrap.NavSidebarItem} this
4945 * @param {boolean} state the new state
4953 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4955 badgeWeight : 'default',
4961 buttonWeight : 'default',
4967 getAutoCreate : function(){
4972 href : this.href || '#',
4978 if(this.buttonView){
4981 href : this.href || '#',
4982 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
4995 cfg.cls += ' active';
4998 if (this.disabled) {
4999 cfg.cls += ' disabled';
5002 cfg.cls += ' open x-open';
5005 if (this.glyphicon || this.icon) {
5006 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5007 a.cn.push({ tag : 'i', cls : c }) ;
5010 if(!this.buttonView){
5013 html : this.html || ''
5020 if (this.badge !== '') {
5021 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5027 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5030 a.cls += ' dropdown-toggle treeview' ;
5036 initEvents : function()
5038 if (typeof (this.menu) != 'undefined') {
5039 this.menu.parentType = this.xtype;
5040 this.menu.triggerEl = this.el;
5041 this.menu = this.addxtype(Roo.apply({}, this.menu));
5044 this.el.on('click', this.onClick, this);
5046 if(this.badge !== ''){
5047 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5052 onClick : function(e)
5059 if(this.preventDefault){
5063 this.fireEvent('click', this);
5066 disable : function()
5068 this.setDisabled(true);
5073 this.setDisabled(false);
5076 setDisabled : function(state)
5078 if(this.disabled == state){
5082 this.disabled = state;
5085 this.el.addClass('disabled');
5089 this.el.removeClass('disabled');
5094 setActive : function(state)
5096 if(this.active == state){
5100 this.active = state;
5103 this.el.addClass('active');
5107 this.el.removeClass('active');
5112 isActive: function ()
5117 setBadge : function(str)
5123 this.badgeEl.dom.innerHTML = str;
5140 * @class Roo.bootstrap.Row
5141 * @extends Roo.bootstrap.Component
5142 * Bootstrap Row class (contains columns...)
5146 * @param {Object} config The config object
5149 Roo.bootstrap.Row = function(config){
5150 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5153 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5155 getAutoCreate : function(){
5174 * @class Roo.bootstrap.Element
5175 * @extends Roo.bootstrap.Component
5176 * Bootstrap Element class
5177 * @cfg {String} html contents of the element
5178 * @cfg {String} tag tag of the element
5179 * @cfg {String} cls class of the element
5180 * @cfg {Boolean} preventDefault (true|false) default false
5181 * @cfg {Boolean} clickable (true|false) default false
5184 * Create a new Element
5185 * @param {Object} config The config object
5188 Roo.bootstrap.Element = function(config){
5189 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5195 * When a element is chick
5196 * @param {Roo.bootstrap.Element} this
5197 * @param {Roo.EventObject} e
5203 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5208 preventDefault: false,
5211 getAutoCreate : function(){
5215 // cls: this.cls, double assign in parent class Component.js :: onRender
5222 initEvents: function()
5224 Roo.bootstrap.Element.superclass.initEvents.call(this);
5227 this.el.on('click', this.onClick, this);
5232 onClick : function(e)
5234 if(this.preventDefault){
5238 this.fireEvent('click', this, e);
5241 getValue : function()
5243 return this.el.dom.innerHTML;
5246 setValue : function(value)
5248 this.el.dom.innerHTML = value;
5263 * @class Roo.bootstrap.Pagination
5264 * @extends Roo.bootstrap.Component
5265 * Bootstrap Pagination class
5266 * @cfg {String} size xs | sm | md | lg
5267 * @cfg {Boolean} inverse false | true
5270 * Create a new Pagination
5271 * @param {Object} config The config object
5274 Roo.bootstrap.Pagination = function(config){
5275 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5278 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5284 getAutoCreate : function(){
5290 cfg.cls += ' inverse';
5296 cfg.cls += " " + this.cls;
5314 * @class Roo.bootstrap.PaginationItem
5315 * @extends Roo.bootstrap.Component
5316 * Bootstrap PaginationItem class
5317 * @cfg {String} html text
5318 * @cfg {String} href the link
5319 * @cfg {Boolean} preventDefault (true | false) default true
5320 * @cfg {Boolean} active (true | false) default false
5321 * @cfg {Boolean} disabled default false
5325 * Create a new PaginationItem
5326 * @param {Object} config The config object
5330 Roo.bootstrap.PaginationItem = function(config){
5331 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5336 * The raw click event for the entire grid.
5337 * @param {Roo.EventObject} e
5343 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5347 preventDefault: true,
5352 getAutoCreate : function(){
5358 href : this.href ? this.href : '#',
5359 html : this.html ? this.html : ''
5369 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5373 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5379 initEvents: function() {
5381 this.el.on('click', this.onClick, this);
5384 onClick : function(e)
5386 Roo.log('PaginationItem on click ');
5387 if(this.preventDefault){
5395 this.fireEvent('click', this, e);
5411 * @class Roo.bootstrap.Slider
5412 * @extends Roo.bootstrap.Component
5413 * Bootstrap Slider class
5416 * Create a new Slider
5417 * @param {Object} config The config object
5420 Roo.bootstrap.Slider = function(config){
5421 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5424 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5426 getAutoCreate : function(){
5430 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5434 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5446 * Ext JS Library 1.1.1
5447 * Copyright(c) 2006-2007, Ext JS, LLC.
5449 * Originally Released Under LGPL - original licence link has changed is not relivant.
5452 * <script type="text/javascript">
5457 * @class Roo.grid.ColumnModel
5458 * @extends Roo.util.Observable
5459 * This is the default implementation of a ColumnModel used by the Grid. It defines
5460 * the columns in the grid.
5463 var colModel = new Roo.grid.ColumnModel([
5464 {header: "Ticker", width: 60, sortable: true, locked: true},
5465 {header: "Company Name", width: 150, sortable: true},
5466 {header: "Market Cap.", width: 100, sortable: true},
5467 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5468 {header: "Employees", width: 100, sortable: true, resizable: false}
5473 * The config options listed for this class are options which may appear in each
5474 * individual column definition.
5475 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5477 * @param {Object} config An Array of column config objects. See this class's
5478 * config objects for details.
5480 Roo.grid.ColumnModel = function(config){
5482 * The config passed into the constructor
5484 this.config = config;
5487 // if no id, create one
5488 // if the column does not have a dataIndex mapping,
5489 // map it to the order it is in the config
5490 for(var i = 0, len = config.length; i < len; i++){
5492 if(typeof c.dataIndex == "undefined"){
5495 if(typeof c.renderer == "string"){
5496 c.renderer = Roo.util.Format[c.renderer];
5498 if(typeof c.id == "undefined"){
5501 if(c.editor && c.editor.xtype){
5502 c.editor = Roo.factory(c.editor, Roo.grid);
5504 if(c.editor && c.editor.isFormField){
5505 c.editor = new Roo.grid.GridEditor(c.editor);
5507 this.lookup[c.id] = c;
5511 * The width of columns which have no width specified (defaults to 100)
5514 this.defaultWidth = 100;
5517 * Default sortable of columns which have no sortable specified (defaults to false)
5520 this.defaultSortable = false;
5524 * @event widthchange
5525 * Fires when the width of a column changes.
5526 * @param {ColumnModel} this
5527 * @param {Number} columnIndex The column index
5528 * @param {Number} newWidth The new width
5530 "widthchange": true,
5532 * @event headerchange
5533 * Fires when the text of a header changes.
5534 * @param {ColumnModel} this
5535 * @param {Number} columnIndex The column index
5536 * @param {Number} newText The new header text
5538 "headerchange": true,
5540 * @event hiddenchange
5541 * Fires when a column is hidden or "unhidden".
5542 * @param {ColumnModel} this
5543 * @param {Number} columnIndex The column index
5544 * @param {Boolean} hidden true if hidden, false otherwise
5546 "hiddenchange": true,
5548 * @event columnmoved
5549 * Fires when a column is moved.
5550 * @param {ColumnModel} this
5551 * @param {Number} oldIndex
5552 * @param {Number} newIndex
5554 "columnmoved" : true,
5556 * @event columlockchange
5557 * Fires when a column's locked state is changed
5558 * @param {ColumnModel} this
5559 * @param {Number} colIndex
5560 * @param {Boolean} locked true if locked
5562 "columnlockchange" : true
5564 Roo.grid.ColumnModel.superclass.constructor.call(this);
5566 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5568 * @cfg {String} header The header text to display in the Grid view.
5571 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5572 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5573 * specified, the column's index is used as an index into the Record's data Array.
5576 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5577 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5580 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5581 * Defaults to the value of the {@link #defaultSortable} property.
5582 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5585 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5588 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5591 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5594 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5597 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5598 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5599 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5600 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5603 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5606 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5609 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5612 * @cfg {String} cursor (Optional)
5615 * @cfg {String} tooltip (Optional)
5618 * @cfg {Number} xs (Optional)
5621 * @cfg {Number} sm (Optional)
5624 * @cfg {Number} md (Optional)
5627 * @cfg {Number} lg (Optional)
5630 * Returns the id of the column at the specified index.
5631 * @param {Number} index The column index
5632 * @return {String} the id
5634 getColumnId : function(index){
5635 return this.config[index].id;
5639 * Returns the column for a specified id.
5640 * @param {String} id The column id
5641 * @return {Object} the column
5643 getColumnById : function(id){
5644 return this.lookup[id];
5649 * Returns the column for a specified dataIndex.
5650 * @param {String} dataIndex The column dataIndex
5651 * @return {Object|Boolean} the column or false if not found
5653 getColumnByDataIndex: function(dataIndex){
5654 var index = this.findColumnIndex(dataIndex);
5655 return index > -1 ? this.config[index] : false;
5659 * Returns the index for a specified column id.
5660 * @param {String} id The column id
5661 * @return {Number} the index, or -1 if not found
5663 getIndexById : function(id){
5664 for(var i = 0, len = this.config.length; i < len; i++){
5665 if(this.config[i].id == id){
5673 * Returns the index for a specified column dataIndex.
5674 * @param {String} dataIndex The column dataIndex
5675 * @return {Number} the index, or -1 if not found
5678 findColumnIndex : function(dataIndex){
5679 for(var i = 0, len = this.config.length; i < len; i++){
5680 if(this.config[i].dataIndex == dataIndex){
5688 moveColumn : function(oldIndex, newIndex){
5689 var c = this.config[oldIndex];
5690 this.config.splice(oldIndex, 1);
5691 this.config.splice(newIndex, 0, c);
5692 this.dataMap = null;
5693 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5696 isLocked : function(colIndex){
5697 return this.config[colIndex].locked === true;
5700 setLocked : function(colIndex, value, suppressEvent){
5701 if(this.isLocked(colIndex) == value){
5704 this.config[colIndex].locked = value;
5706 this.fireEvent("columnlockchange", this, colIndex, value);
5710 getTotalLockedWidth : function(){
5712 for(var i = 0; i < this.config.length; i++){
5713 if(this.isLocked(i) && !this.isHidden(i)){
5714 this.totalWidth += this.getColumnWidth(i);
5720 getLockedCount : function(){
5721 for(var i = 0, len = this.config.length; i < len; i++){
5722 if(!this.isLocked(i)){
5727 return this.config.length;
5731 * Returns the number of columns.
5734 getColumnCount : function(visibleOnly){
5735 if(visibleOnly === true){
5737 for(var i = 0, len = this.config.length; i < len; i++){
5738 if(!this.isHidden(i)){
5744 return this.config.length;
5748 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5749 * @param {Function} fn
5750 * @param {Object} scope (optional)
5751 * @return {Array} result
5753 getColumnsBy : function(fn, scope){
5755 for(var i = 0, len = this.config.length; i < len; i++){
5756 var c = this.config[i];
5757 if(fn.call(scope||this, c, i) === true){
5765 * Returns true if the specified column is sortable.
5766 * @param {Number} col The column index
5769 isSortable : function(col){
5770 if(typeof this.config[col].sortable == "undefined"){
5771 return this.defaultSortable;
5773 return this.config[col].sortable;
5777 * Returns the rendering (formatting) function defined for the column.
5778 * @param {Number} col The column index.
5779 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5781 getRenderer : function(col){
5782 if(!this.config[col].renderer){
5783 return Roo.grid.ColumnModel.defaultRenderer;
5785 return this.config[col].renderer;
5789 * Sets the rendering (formatting) function for a column.
5790 * @param {Number} col The column index
5791 * @param {Function} fn The function to use to process the cell's raw data
5792 * to return HTML markup for the grid view. The render function is called with
5793 * the following parameters:<ul>
5794 * <li>Data value.</li>
5795 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5796 * <li>css A CSS style string to apply to the table cell.</li>
5797 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5798 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5799 * <li>Row index</li>
5800 * <li>Column index</li>
5801 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5803 setRenderer : function(col, fn){
5804 this.config[col].renderer = fn;
5808 * Returns the width for the specified column.
5809 * @param {Number} col The column index
5812 getColumnWidth : function(col){
5813 return this.config[col].width * 1 || this.defaultWidth;
5817 * Sets the width for a column.
5818 * @param {Number} col The column index
5819 * @param {Number} width The new width
5821 setColumnWidth : function(col, width, suppressEvent){
5822 this.config[col].width = width;
5823 this.totalWidth = null;
5825 this.fireEvent("widthchange", this, col, width);
5830 * Returns the total width of all columns.
5831 * @param {Boolean} includeHidden True to include hidden column widths
5834 getTotalWidth : function(includeHidden){
5835 if(!this.totalWidth){
5836 this.totalWidth = 0;
5837 for(var i = 0, len = this.config.length; i < len; i++){
5838 if(includeHidden || !this.isHidden(i)){
5839 this.totalWidth += this.getColumnWidth(i);
5843 return this.totalWidth;
5847 * Returns the header for the specified column.
5848 * @param {Number} col The column index
5851 getColumnHeader : function(col){
5852 return this.config[col].header;
5856 * Sets the header for a column.
5857 * @param {Number} col The column index
5858 * @param {String} header The new header
5860 setColumnHeader : function(col, header){
5861 this.config[col].header = header;
5862 this.fireEvent("headerchange", this, col, header);
5866 * Returns the tooltip for the specified column.
5867 * @param {Number} col The column index
5870 getColumnTooltip : function(col){
5871 return this.config[col].tooltip;
5874 * Sets the tooltip for a column.
5875 * @param {Number} col The column index
5876 * @param {String} tooltip The new tooltip
5878 setColumnTooltip : function(col, tooltip){
5879 this.config[col].tooltip = tooltip;
5883 * Returns the dataIndex for the specified column.
5884 * @param {Number} col The column index
5887 getDataIndex : function(col){
5888 return this.config[col].dataIndex;
5892 * Sets the dataIndex for a column.
5893 * @param {Number} col The column index
5894 * @param {Number} dataIndex The new dataIndex
5896 setDataIndex : function(col, dataIndex){
5897 this.config[col].dataIndex = dataIndex;
5903 * Returns true if the cell is editable.
5904 * @param {Number} colIndex The column index
5905 * @param {Number} rowIndex The row index - this is nto actually used..?
5908 isCellEditable : function(colIndex, rowIndex){
5909 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5913 * Returns the editor defined for the cell/column.
5914 * return false or null to disable editing.
5915 * @param {Number} colIndex The column index
5916 * @param {Number} rowIndex The row index
5919 getCellEditor : function(colIndex, rowIndex){
5920 return this.config[colIndex].editor;
5924 * Sets if a column is editable.
5925 * @param {Number} col The column index
5926 * @param {Boolean} editable True if the column is editable
5928 setEditable : function(col, editable){
5929 this.config[col].editable = editable;
5934 * Returns true if the column is hidden.
5935 * @param {Number} colIndex The column index
5938 isHidden : function(colIndex){
5939 return this.config[colIndex].hidden;
5944 * Returns true if the column width cannot be changed
5946 isFixed : function(colIndex){
5947 return this.config[colIndex].fixed;
5951 * Returns true if the column can be resized
5954 isResizable : function(colIndex){
5955 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5958 * Sets if a column is hidden.
5959 * @param {Number} colIndex The column index
5960 * @param {Boolean} hidden True if the column is hidden
5962 setHidden : function(colIndex, hidden){
5963 this.config[colIndex].hidden = hidden;
5964 this.totalWidth = null;
5965 this.fireEvent("hiddenchange", this, colIndex, hidden);
5969 * Sets the editor for a column.
5970 * @param {Number} col The column index
5971 * @param {Object} editor The editor object
5973 setEditor : function(col, editor){
5974 this.config[col].editor = editor;
5978 Roo.grid.ColumnModel.defaultRenderer = function(value)
5980 if(typeof value == "object") {
5983 if(typeof value == "string" && value.length < 1){
5987 return String.format("{0}", value);
5990 // Alias for backwards compatibility
5991 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
5994 * Ext JS Library 1.1.1
5995 * Copyright(c) 2006-2007, Ext JS, LLC.
5997 * Originally Released Under LGPL - original licence link has changed is not relivant.
6000 * <script type="text/javascript">
6004 * @class Roo.LoadMask
6005 * A simple utility class for generically masking elements while loading data. If the element being masked has
6006 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6007 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6008 * element's UpdateManager load indicator and will be destroyed after the initial load.
6010 * Create a new LoadMask
6011 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6012 * @param {Object} config The config object
6014 Roo.LoadMask = function(el, config){
6015 this.el = Roo.get(el);
6016 Roo.apply(this, config);
6018 this.store.on('beforeload', this.onBeforeLoad, this);
6019 this.store.on('load', this.onLoad, this);
6020 this.store.on('loadexception', this.onLoadException, this);
6021 this.removeMask = false;
6023 var um = this.el.getUpdateManager();
6024 um.showLoadIndicator = false; // disable the default indicator
6025 um.on('beforeupdate', this.onBeforeLoad, this);
6026 um.on('update', this.onLoad, this);
6027 um.on('failure', this.onLoad, this);
6028 this.removeMask = true;
6032 Roo.LoadMask.prototype = {
6034 * @cfg {Boolean} removeMask
6035 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6036 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6040 * The text to display in a centered loading message box (defaults to 'Loading...')
6044 * @cfg {String} msgCls
6045 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6047 msgCls : 'x-mask-loading',
6050 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6056 * Disables the mask to prevent it from being displayed
6058 disable : function(){
6059 this.disabled = true;
6063 * Enables the mask so that it can be displayed
6065 enable : function(){
6066 this.disabled = false;
6069 onLoadException : function()
6073 if (typeof(arguments[3]) != 'undefined') {
6074 Roo.MessageBox.alert("Error loading",arguments[3]);
6078 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6079 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6086 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6091 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6095 onBeforeLoad : function(){
6097 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6102 destroy : function(){
6104 this.store.un('beforeload', this.onBeforeLoad, this);
6105 this.store.un('load', this.onLoad, this);
6106 this.store.un('loadexception', this.onLoadException, this);
6108 var um = this.el.getUpdateManager();
6109 um.un('beforeupdate', this.onBeforeLoad, this);
6110 um.un('update', this.onLoad, this);
6111 um.un('failure', this.onLoad, this);
6122 * @class Roo.bootstrap.Table
6123 * @extends Roo.bootstrap.Component
6124 * Bootstrap Table class
6125 * @cfg {String} cls table class
6126 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6127 * @cfg {String} bgcolor Specifies the background color for a table
6128 * @cfg {Number} border Specifies whether the table cells should have borders or not
6129 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6130 * @cfg {Number} cellspacing Specifies the space between cells
6131 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6132 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6133 * @cfg {String} sortable Specifies that the table should be sortable
6134 * @cfg {String} summary Specifies a summary of the content of a table
6135 * @cfg {Number} width Specifies the width of a table
6136 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6138 * @cfg {boolean} striped Should the rows be alternative striped
6139 * @cfg {boolean} bordered Add borders to the table
6140 * @cfg {boolean} hover Add hover highlighting
6141 * @cfg {boolean} condensed Format condensed
6142 * @cfg {boolean} responsive Format condensed
6143 * @cfg {Boolean} loadMask (true|false) default false
6144 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6145 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6146 * @cfg {Boolean} rowSelection (true|false) default false
6147 * @cfg {Boolean} cellSelection (true|false) default false
6148 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6149 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6150 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6151 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6155 * Create a new Table
6156 * @param {Object} config The config object
6159 Roo.bootstrap.Table = function(config){
6160 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6165 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6166 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6167 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6168 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6170 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6172 this.sm.grid = this;
6173 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6174 this.sm = this.selModel;
6175 this.sm.xmodule = this.xmodule || false;
6178 if (this.cm && typeof(this.cm.config) == 'undefined') {
6179 this.colModel = new Roo.grid.ColumnModel(this.cm);
6180 this.cm = this.colModel;
6181 this.cm.xmodule = this.xmodule || false;
6184 this.store= Roo.factory(this.store, Roo.data);
6185 this.ds = this.store;
6186 this.ds.xmodule = this.xmodule || false;
6189 if (this.footer && this.store) {
6190 this.footer.dataSource = this.ds;
6191 this.footer = Roo.factory(this.footer);
6198 * Fires when a cell is clicked
6199 * @param {Roo.bootstrap.Table} this
6200 * @param {Roo.Element} el
6201 * @param {Number} rowIndex
6202 * @param {Number} columnIndex
6203 * @param {Roo.EventObject} e
6207 * @event celldblclick
6208 * Fires when a cell is double clicked
6209 * @param {Roo.bootstrap.Table} this
6210 * @param {Roo.Element} el
6211 * @param {Number} rowIndex
6212 * @param {Number} columnIndex
6213 * @param {Roo.EventObject} e
6215 "celldblclick" : true,
6218 * Fires when a row is clicked
6219 * @param {Roo.bootstrap.Table} this
6220 * @param {Roo.Element} el
6221 * @param {Number} rowIndex
6222 * @param {Roo.EventObject} e
6226 * @event rowdblclick
6227 * Fires when a row is double clicked
6228 * @param {Roo.bootstrap.Table} this
6229 * @param {Roo.Element} el
6230 * @param {Number} rowIndex
6231 * @param {Roo.EventObject} e
6233 "rowdblclick" : true,
6236 * Fires when a mouseover occur
6237 * @param {Roo.bootstrap.Table} this
6238 * @param {Roo.Element} el
6239 * @param {Number} rowIndex
6240 * @param {Number} columnIndex
6241 * @param {Roo.EventObject} e
6246 * Fires when a mouseout occur
6247 * @param {Roo.bootstrap.Table} this
6248 * @param {Roo.Element} el
6249 * @param {Number} rowIndex
6250 * @param {Number} columnIndex
6251 * @param {Roo.EventObject} e
6256 * Fires when a row is rendered, so you can change add a style to it.
6257 * @param {Roo.bootstrap.Table} this
6258 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6262 * @event rowsrendered
6263 * Fires when all the rows have been rendered
6264 * @param {Roo.bootstrap.Table} this
6266 'rowsrendered' : true,
6268 * @event contextmenu
6269 * The raw contextmenu event for the entire grid.
6270 * @param {Roo.EventObject} e
6272 "contextmenu" : true,
6274 * @event rowcontextmenu
6275 * Fires when a row is right clicked
6276 * @param {Roo.bootstrap.Table} this
6277 * @param {Number} rowIndex
6278 * @param {Roo.EventObject} e
6280 "rowcontextmenu" : true,
6282 * @event cellcontextmenu
6283 * Fires when a cell is right clicked
6284 * @param {Roo.bootstrap.Table} this
6285 * @param {Number} rowIndex
6286 * @param {Number} cellIndex
6287 * @param {Roo.EventObject} e
6289 "cellcontextmenu" : true,
6291 * @event headercontextmenu
6292 * Fires when a header is right clicked
6293 * @param {Roo.bootstrap.Table} this
6294 * @param {Number} columnIndex
6295 * @param {Roo.EventObject} e
6297 "headercontextmenu" : true
6301 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6327 rowSelection : false,
6328 cellSelection : false,
6331 // Roo.Element - the tbody
6333 // Roo.Element - thead element
6336 container: false, // used by gridpanel...
6342 auto_hide_footer : false,
6344 getAutoCreate : function()
6346 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6353 if (this.scrollBody) {
6354 cfg.cls += ' table-body-fixed';
6357 cfg.cls += ' table-striped';
6361 cfg.cls += ' table-hover';
6363 if (this.bordered) {
6364 cfg.cls += ' table-bordered';
6366 if (this.condensed) {
6367 cfg.cls += ' table-condensed';
6369 if (this.responsive) {
6370 cfg.cls += ' table-responsive';
6374 cfg.cls+= ' ' +this.cls;
6377 // this lot should be simplifed...
6390 ].forEach(function(k) {
6398 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6401 if(this.store || this.cm){
6402 if(this.headerShow){
6403 cfg.cn.push(this.renderHeader());
6406 cfg.cn.push(this.renderBody());
6408 if(this.footerShow){
6409 cfg.cn.push(this.renderFooter());
6411 // where does this come from?
6412 //cfg.cls+= ' TableGrid';
6415 return { cn : [ cfg ] };
6418 initEvents : function()
6420 if(!this.store || !this.cm){
6423 if (this.selModel) {
6424 this.selModel.initEvents();
6428 //Roo.log('initEvents with ds!!!!');
6430 this.mainBody = this.el.select('tbody', true).first();
6431 this.mainHead = this.el.select('thead', true).first();
6432 this.mainFoot = this.el.select('tfoot', true).first();
6438 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6439 e.on('click', _this.sort, _this);
6442 this.mainBody.on("click", this.onClick, this);
6443 this.mainBody.on("dblclick", this.onDblClick, this);
6445 // why is this done????? = it breaks dialogs??
6446 //this.parent().el.setStyle('position', 'relative');
6450 this.footer.parentId = this.id;
6451 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6454 this.el.select('tfoot tr td').first().addClass('hide');
6459 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6462 this.store.on('load', this.onLoad, this);
6463 this.store.on('beforeload', this.onBeforeLoad, this);
6464 this.store.on('update', this.onUpdate, this);
6465 this.store.on('add', this.onAdd, this);
6466 this.store.on("clear", this.clear, this);
6468 this.el.on("contextmenu", this.onContextMenu, this);
6470 this.mainBody.on('scroll', this.onBodyScroll, this);
6472 this.cm.on("headerchange", this.onHeaderChange, this);
6474 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6478 onContextMenu : function(e, t)
6480 this.processEvent("contextmenu", e);
6483 processEvent : function(name, e)
6485 if (name != 'touchstart' ) {
6486 this.fireEvent(name, e);
6489 var t = e.getTarget();
6491 var cell = Roo.get(t);
6497 if(cell.findParent('tfoot', false, true)){
6501 if(cell.findParent('thead', false, true)){
6503 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6504 cell = Roo.get(t).findParent('th', false, true);
6506 Roo.log("failed to find th in thead?");
6507 Roo.log(e.getTarget());
6512 var cellIndex = cell.dom.cellIndex;
6514 var ename = name == 'touchstart' ? 'click' : name;
6515 this.fireEvent("header" + ename, this, cellIndex, e);
6520 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6521 cell = Roo.get(t).findParent('td', false, true);
6523 Roo.log("failed to find th in tbody?");
6524 Roo.log(e.getTarget());
6529 var row = cell.findParent('tr', false, true);
6530 var cellIndex = cell.dom.cellIndex;
6531 var rowIndex = row.dom.rowIndex - 1;
6535 this.fireEvent("row" + name, this, rowIndex, e);
6539 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6545 onMouseover : function(e, el)
6547 var cell = Roo.get(el);
6553 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6554 cell = cell.findParent('td', false, true);
6557 var row = cell.findParent('tr', false, true);
6558 var cellIndex = cell.dom.cellIndex;
6559 var rowIndex = row.dom.rowIndex - 1; // start from 0
6561 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6565 onMouseout : function(e, el)
6567 var cell = Roo.get(el);
6573 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6574 cell = cell.findParent('td', false, true);
6577 var row = cell.findParent('tr', false, true);
6578 var cellIndex = cell.dom.cellIndex;
6579 var rowIndex = row.dom.rowIndex - 1; // start from 0
6581 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6585 onClick : function(e, el)
6587 var cell = Roo.get(el);
6589 if(!cell || (!this.cellSelection && !this.rowSelection)){
6593 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6594 cell = cell.findParent('td', false, true);
6597 if(!cell || typeof(cell) == 'undefined'){
6601 var row = cell.findParent('tr', false, true);
6603 if(!row || typeof(row) == 'undefined'){
6607 var cellIndex = cell.dom.cellIndex;
6608 var rowIndex = this.getRowIndex(row);
6610 // why??? - should these not be based on SelectionModel?
6611 if(this.cellSelection){
6612 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6615 if(this.rowSelection){
6616 this.fireEvent('rowclick', this, row, rowIndex, e);
6622 onDblClick : function(e,el)
6624 var cell = Roo.get(el);
6626 if(!cell || (!this.cellSelection && !this.rowSelection)){
6630 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6631 cell = cell.findParent('td', false, true);
6634 if(!cell || typeof(cell) == 'undefined'){
6638 var row = cell.findParent('tr', false, true);
6640 if(!row || typeof(row) == 'undefined'){
6644 var cellIndex = cell.dom.cellIndex;
6645 var rowIndex = this.getRowIndex(row);
6647 if(this.cellSelection){
6648 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6651 if(this.rowSelection){
6652 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6656 sort : function(e,el)
6658 var col = Roo.get(el);
6660 if(!col.hasClass('sortable')){
6664 var sort = col.attr('sort');
6667 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6671 this.store.sortInfo = {field : sort, direction : dir};
6674 Roo.log("calling footer first");
6675 this.footer.onClick('first');
6678 this.store.load({ params : { start : 0 } });
6682 renderHeader : function()
6690 this.totalWidth = 0;
6692 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6694 var config = cm.config[i];
6698 cls : 'x-hcol-' + i,
6700 html: cm.getColumnHeader(i)
6705 if(typeof(config.sortable) != 'undefined' && config.sortable){
6707 c.html = '<i class="glyphicon"></i>' + c.html;
6710 if(typeof(config.lgHeader) != 'undefined'){
6711 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6714 if(typeof(config.mdHeader) != 'undefined'){
6715 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6718 if(typeof(config.smHeader) != 'undefined'){
6719 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6722 if(typeof(config.xsHeader) != 'undefined'){
6723 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6730 if(typeof(config.tooltip) != 'undefined'){
6731 c.tooltip = config.tooltip;
6734 if(typeof(config.colspan) != 'undefined'){
6735 c.colspan = config.colspan;
6738 if(typeof(config.hidden) != 'undefined' && config.hidden){
6739 c.style += ' display:none;';
6742 if(typeof(config.dataIndex) != 'undefined'){
6743 c.sort = config.dataIndex;
6748 if(typeof(config.align) != 'undefined' && config.align.length){
6749 c.style += ' text-align:' + config.align + ';';
6752 if(typeof(config.width) != 'undefined'){
6753 c.style += ' width:' + config.width + 'px;';
6754 this.totalWidth += config.width;
6756 this.totalWidth += 100; // assume minimum of 100 per column?
6759 if(typeof(config.cls) != 'undefined'){
6760 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6763 ['xs','sm','md','lg'].map(function(size){
6765 if(typeof(config[size]) == 'undefined'){
6769 if (!config[size]) { // 0 = hidden
6770 c.cls += ' hidden-' + size;
6774 c.cls += ' col-' + size + '-' + config[size];
6784 renderBody : function()
6794 colspan : this.cm.getColumnCount()
6804 renderFooter : function()
6814 colspan : this.cm.getColumnCount()
6828 // Roo.log('ds onload');
6833 var ds = this.store;
6835 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6836 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6837 if (_this.store.sortInfo) {
6839 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6840 e.select('i', true).addClass(['glyphicon-arrow-up']);
6843 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6844 e.select('i', true).addClass(['glyphicon-arrow-down']);
6849 var tbody = this.mainBody;
6851 if(ds.getCount() > 0){
6852 ds.data.each(function(d,rowIndex){
6853 var row = this.renderRow(cm, ds, rowIndex);
6855 tbody.createChild(row);
6859 if(row.cellObjects.length){
6860 Roo.each(row.cellObjects, function(r){
6861 _this.renderCellObject(r);
6868 var tfoot = this.el.select('tfoot', true).first();
6870 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6872 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6874 var total = this.ds.getTotalCount();
6876 if(this.footer.pageSize < total){
6877 this.mainFoot.show();
6881 Roo.each(this.el.select('tbody td', true).elements, function(e){
6882 e.on('mouseover', _this.onMouseover, _this);
6885 Roo.each(this.el.select('tbody td', true).elements, function(e){
6886 e.on('mouseout', _this.onMouseout, _this);
6888 this.fireEvent('rowsrendered', this);
6894 onUpdate : function(ds,record)
6896 this.refreshRow(record);
6900 onRemove : function(ds, record, index, isUpdate){
6901 if(isUpdate !== true){
6902 this.fireEvent("beforerowremoved", this, index, record);
6904 var bt = this.mainBody.dom;
6906 var rows = this.el.select('tbody > tr', true).elements;
6908 if(typeof(rows[index]) != 'undefined'){
6909 bt.removeChild(rows[index].dom);
6912 // if(bt.rows[index]){
6913 // bt.removeChild(bt.rows[index]);
6916 if(isUpdate !== true){
6917 //this.stripeRows(index);
6918 //this.syncRowHeights(index, index);
6920 this.fireEvent("rowremoved", this, index, record);
6924 onAdd : function(ds, records, rowIndex)
6926 //Roo.log('on Add called');
6927 // - note this does not handle multiple adding very well..
6928 var bt = this.mainBody.dom;
6929 for (var i =0 ; i < records.length;i++) {
6930 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6931 //Roo.log(records[i]);
6932 //Roo.log(this.store.getAt(rowIndex+i));
6933 this.insertRow(this.store, rowIndex + i, false);
6940 refreshRow : function(record){
6941 var ds = this.store, index;
6942 if(typeof record == 'number'){
6944 record = ds.getAt(index);
6946 index = ds.indexOf(record);
6948 this.insertRow(ds, index, true);
6950 this.onRemove(ds, record, index+1, true);
6952 //this.syncRowHeights(index, index);
6954 this.fireEvent("rowupdated", this, index, record);
6957 insertRow : function(dm, rowIndex, isUpdate){
6960 this.fireEvent("beforerowsinserted", this, rowIndex);
6962 //var s = this.getScrollState();
6963 var row = this.renderRow(this.cm, this.store, rowIndex);
6964 // insert before rowIndex..
6965 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6969 if(row.cellObjects.length){
6970 Roo.each(row.cellObjects, function(r){
6971 _this.renderCellObject(r);
6976 this.fireEvent("rowsinserted", this, rowIndex);
6977 //this.syncRowHeights(firstRow, lastRow);
6978 //this.stripeRows(firstRow);
6985 getRowDom : function(rowIndex)
6987 var rows = this.el.select('tbody > tr', true).elements;
6989 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
6992 // returns the object tree for a tr..
6995 renderRow : function(cm, ds, rowIndex)
6997 var d = ds.getAt(rowIndex);
7001 cls : 'x-row-' + rowIndex,
7005 var cellObjects = [];
7007 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7008 var config = cm.config[i];
7010 var renderer = cm.getRenderer(i);
7014 if(typeof(renderer) !== 'undefined'){
7015 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7017 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7018 // and are rendered into the cells after the row is rendered - using the id for the element.
7020 if(typeof(value) === 'object'){
7030 rowIndex : rowIndex,
7035 this.fireEvent('rowclass', this, rowcfg);
7039 cls : rowcfg.rowClass + ' x-col-' + i,
7041 html: (typeof(value) === 'object') ? '' : value
7048 if(typeof(config.colspan) != 'undefined'){
7049 td.colspan = config.colspan;
7052 if(typeof(config.hidden) != 'undefined' && config.hidden){
7053 td.style += ' display:none;';
7056 if(typeof(config.align) != 'undefined' && config.align.length){
7057 td.style += ' text-align:' + config.align + ';';
7059 if(typeof(config.valign) != 'undefined' && config.valign.length){
7060 td.style += ' vertical-align:' + config.valign + ';';
7063 if(typeof(config.width) != 'undefined'){
7064 td.style += ' width:' + config.width + 'px;';
7067 if(typeof(config.cursor) != 'undefined'){
7068 td.style += ' cursor:' + config.cursor + ';';
7071 if(typeof(config.cls) != 'undefined'){
7072 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7075 ['xs','sm','md','lg'].map(function(size){
7077 if(typeof(config[size]) == 'undefined'){
7081 if (!config[size]) { // 0 = hidden
7082 td.cls += ' hidden-' + size;
7086 td.cls += ' col-' + size + '-' + config[size];
7094 row.cellObjects = cellObjects;
7102 onBeforeLoad : function()
7111 this.el.select('tbody', true).first().dom.innerHTML = '';
7114 * Show or hide a row.
7115 * @param {Number} rowIndex to show or hide
7116 * @param {Boolean} state hide
7118 setRowVisibility : function(rowIndex, state)
7120 var bt = this.mainBody.dom;
7122 var rows = this.el.select('tbody > tr', true).elements;
7124 if(typeof(rows[rowIndex]) == 'undefined'){
7127 rows[rowIndex].dom.style.display = state ? '' : 'none';
7131 getSelectionModel : function(){
7133 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7135 return this.selModel;
7138 * Render the Roo.bootstrap object from renderder
7140 renderCellObject : function(r)
7144 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7146 var t = r.cfg.render(r.container);
7149 Roo.each(r.cfg.cn, function(c){
7151 container: t.getChildContainer(),
7154 _this.renderCellObject(child);
7159 getRowIndex : function(row)
7163 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7174 * Returns the grid's underlying element = used by panel.Grid
7175 * @return {Element} The element
7177 getGridEl : function(){
7181 * Forces a resize - used by panel.Grid
7182 * @return {Element} The element
7184 autoSize : function()
7186 //var ctr = Roo.get(this.container.dom.parentElement);
7187 var ctr = Roo.get(this.el.dom);
7189 var thd = this.getGridEl().select('thead',true).first();
7190 var tbd = this.getGridEl().select('tbody', true).first();
7191 var tfd = this.getGridEl().select('tfoot', true).first();
7193 var cw = ctr.getWidth();
7197 tbd.setSize(ctr.getWidth(),
7198 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7200 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7203 cw = Math.max(cw, this.totalWidth);
7204 this.getGridEl().select('tr',true).setWidth(cw);
7205 // resize 'expandable coloumn?
7207 return; // we doe not have a view in this design..
7210 onBodyScroll: function()
7212 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7214 this.mainHead.setStyle({
7215 'position' : 'relative',
7216 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7222 var scrollHeight = this.mainBody.dom.scrollHeight;
7224 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7226 var height = this.mainBody.getHeight();
7228 if(scrollHeight - height == scrollTop) {
7230 var total = this.ds.getTotalCount();
7232 if(this.footer.cursor + this.footer.pageSize < total){
7234 this.footer.ds.load({
7236 start : this.footer.cursor + this.footer.pageSize,
7237 limit : this.footer.pageSize
7247 onHeaderChange : function()
7249 var header = this.renderHeader();
7250 var table = this.el.select('table', true).first();
7252 this.mainHead.remove();
7253 this.mainHead = table.createChild(header, this.mainBody, false);
7256 onHiddenChange : function(colModel, colIndex, hidden)
7258 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7259 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7261 this.CSS.updateRule(thSelector, "display", "");
7262 this.CSS.updateRule(tdSelector, "display", "");
7265 this.CSS.updateRule(thSelector, "display", "none");
7266 this.CSS.updateRule(tdSelector, "display", "none");
7269 this.onHeaderChange();
7273 setColumnWidth: function(col_index, width)
7275 // width = "md-2 xs-2..."
7276 if(!this.colModel.config[col_index]) {
7280 var w = width.split(" ");
7282 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7284 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7287 for(var j = 0; j < w.length; j++) {
7293 var size_cls = w[j].split("-");
7295 if(!Number.isInteger(size_cls[1] * 1)) {
7299 if(!this.colModel.config[col_index][size_cls[0]]) {
7303 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7307 h_row[0].classList.replace(
7308 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7309 "col-"+size_cls[0]+"-"+size_cls[1]
7312 for(var i = 0; i < rows.length; i++) {
7314 var size_cls = w[j].split("-");
7316 if(!Number.isInteger(size_cls[1] * 1)) {
7320 if(!this.colModel.config[col_index][size_cls[0]]) {
7324 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7328 rows[i].classList.replace(
7329 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7330 "col-"+size_cls[0]+"-"+size_cls[1]
7334 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7349 * @class Roo.bootstrap.TableCell
7350 * @extends Roo.bootstrap.Component
7351 * Bootstrap TableCell class
7352 * @cfg {String} html cell contain text
7353 * @cfg {String} cls cell class
7354 * @cfg {String} tag cell tag (td|th) default td
7355 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7356 * @cfg {String} align Aligns the content in a cell
7357 * @cfg {String} axis Categorizes cells
7358 * @cfg {String} bgcolor Specifies the background color of a cell
7359 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7360 * @cfg {Number} colspan Specifies the number of columns a cell should span
7361 * @cfg {String} headers Specifies one or more header cells a cell is related to
7362 * @cfg {Number} height Sets the height of a cell
7363 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7364 * @cfg {Number} rowspan Sets the number of rows a cell should span
7365 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7366 * @cfg {String} valign Vertical aligns the content in a cell
7367 * @cfg {Number} width Specifies the width of a cell
7370 * Create a new TableCell
7371 * @param {Object} config The config object
7374 Roo.bootstrap.TableCell = function(config){
7375 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7378 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7398 getAutoCreate : function(){
7399 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7419 cfg.align=this.align
7425 cfg.bgcolor=this.bgcolor
7428 cfg.charoff=this.charoff
7431 cfg.colspan=this.colspan
7434 cfg.headers=this.headers
7437 cfg.height=this.height
7440 cfg.nowrap=this.nowrap
7443 cfg.rowspan=this.rowspan
7446 cfg.scope=this.scope
7449 cfg.valign=this.valign
7452 cfg.width=this.width
7471 * @class Roo.bootstrap.TableRow
7472 * @extends Roo.bootstrap.Component
7473 * Bootstrap TableRow class
7474 * @cfg {String} cls row class
7475 * @cfg {String} align Aligns the content in a table row
7476 * @cfg {String} bgcolor Specifies a background color for a table row
7477 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7478 * @cfg {String} valign Vertical aligns the content in a table row
7481 * Create a new TableRow
7482 * @param {Object} config The config object
7485 Roo.bootstrap.TableRow = function(config){
7486 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7489 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7497 getAutoCreate : function(){
7498 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7508 cfg.align = this.align;
7511 cfg.bgcolor = this.bgcolor;
7514 cfg.charoff = this.charoff;
7517 cfg.valign = this.valign;
7535 * @class Roo.bootstrap.TableBody
7536 * @extends Roo.bootstrap.Component
7537 * Bootstrap TableBody class
7538 * @cfg {String} cls element class
7539 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7540 * @cfg {String} align Aligns the content inside the element
7541 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7542 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7545 * Create a new TableBody
7546 * @param {Object} config The config object
7549 Roo.bootstrap.TableBody = function(config){
7550 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7553 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7561 getAutoCreate : function(){
7562 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7576 cfg.align = this.align;
7579 cfg.charoff = this.charoff;
7582 cfg.valign = this.valign;
7589 // initEvents : function()
7596 // this.store = Roo.factory(this.store, Roo.data);
7597 // this.store.on('load', this.onLoad, this);
7599 // this.store.load();
7603 // onLoad: function ()
7605 // this.fireEvent('load', this);
7615 * Ext JS Library 1.1.1
7616 * Copyright(c) 2006-2007, Ext JS, LLC.
7618 * Originally Released Under LGPL - original licence link has changed is not relivant.
7621 * <script type="text/javascript">
7624 // as we use this in bootstrap.
7625 Roo.namespace('Roo.form');
7627 * @class Roo.form.Action
7628 * Internal Class used to handle form actions
7630 * @param {Roo.form.BasicForm} el The form element or its id
7631 * @param {Object} config Configuration options
7636 // define the action interface
7637 Roo.form.Action = function(form, options){
7639 this.options = options || {};
7642 * Client Validation Failed
7645 Roo.form.Action.CLIENT_INVALID = 'client';
7647 * Server Validation Failed
7650 Roo.form.Action.SERVER_INVALID = 'server';
7652 * Connect to Server Failed
7655 Roo.form.Action.CONNECT_FAILURE = 'connect';
7657 * Reading Data from Server Failed
7660 Roo.form.Action.LOAD_FAILURE = 'load';
7662 Roo.form.Action.prototype = {
7664 failureType : undefined,
7665 response : undefined,
7669 run : function(options){
7674 success : function(response){
7679 handleResponse : function(response){
7683 // default connection failure
7684 failure : function(response){
7686 this.response = response;
7687 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7688 this.form.afterAction(this, false);
7691 processResponse : function(response){
7692 this.response = response;
7693 if(!response.responseText){
7696 this.result = this.handleResponse(response);
7700 // utility functions used internally
7701 getUrl : function(appendParams){
7702 var url = this.options.url || this.form.url || this.form.el.dom.action;
7704 var p = this.getParams();
7706 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7712 getMethod : function(){
7713 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7716 getParams : function(){
7717 var bp = this.form.baseParams;
7718 var p = this.options.params;
7720 if(typeof p == "object"){
7721 p = Roo.urlEncode(Roo.applyIf(p, bp));
7722 }else if(typeof p == 'string' && bp){
7723 p += '&' + Roo.urlEncode(bp);
7726 p = Roo.urlEncode(bp);
7731 createCallback : function(){
7733 success: this.success,
7734 failure: this.failure,
7736 timeout: (this.form.timeout*1000),
7737 upload: this.form.fileUpload ? this.success : undefined
7742 Roo.form.Action.Submit = function(form, options){
7743 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7746 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7749 haveProgress : false,
7750 uploadComplete : false,
7752 // uploadProgress indicator.
7753 uploadProgress : function()
7755 if (!this.form.progressUrl) {
7759 if (!this.haveProgress) {
7760 Roo.MessageBox.progress("Uploading", "Uploading");
7762 if (this.uploadComplete) {
7763 Roo.MessageBox.hide();
7767 this.haveProgress = true;
7769 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7771 var c = new Roo.data.Connection();
7773 url : this.form.progressUrl,
7778 success : function(req){
7779 //console.log(data);
7783 rdata = Roo.decode(req.responseText)
7785 Roo.log("Invalid data from server..");
7789 if (!rdata || !rdata.success) {
7791 Roo.MessageBox.alert(Roo.encode(rdata));
7794 var data = rdata.data;
7796 if (this.uploadComplete) {
7797 Roo.MessageBox.hide();
7802 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7803 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7806 this.uploadProgress.defer(2000,this);
7809 failure: function(data) {
7810 Roo.log('progress url failed ');
7821 // run get Values on the form, so it syncs any secondary forms.
7822 this.form.getValues();
7824 var o = this.options;
7825 var method = this.getMethod();
7826 var isPost = method == 'POST';
7827 if(o.clientValidation === false || this.form.isValid()){
7829 if (this.form.progressUrl) {
7830 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7831 (new Date() * 1) + '' + Math.random());
7836 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7837 form:this.form.el.dom,
7838 url:this.getUrl(!isPost),
7840 params:isPost ? this.getParams() : null,
7841 isUpload: this.form.fileUpload
7844 this.uploadProgress();
7846 }else if (o.clientValidation !== false){ // client validation failed
7847 this.failureType = Roo.form.Action.CLIENT_INVALID;
7848 this.form.afterAction(this, false);
7852 success : function(response)
7854 this.uploadComplete= true;
7855 if (this.haveProgress) {
7856 Roo.MessageBox.hide();
7860 var result = this.processResponse(response);
7861 if(result === true || result.success){
7862 this.form.afterAction(this, true);
7866 this.form.markInvalid(result.errors);
7867 this.failureType = Roo.form.Action.SERVER_INVALID;
7869 this.form.afterAction(this, false);
7871 failure : function(response)
7873 this.uploadComplete= true;
7874 if (this.haveProgress) {
7875 Roo.MessageBox.hide();
7878 this.response = response;
7879 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7880 this.form.afterAction(this, false);
7883 handleResponse : function(response){
7884 if(this.form.errorReader){
7885 var rs = this.form.errorReader.read(response);
7888 for(var i = 0, len = rs.records.length; i < len; i++) {
7889 var r = rs.records[i];
7893 if(errors.length < 1){
7897 success : rs.success,
7903 ret = Roo.decode(response.responseText);
7907 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7917 Roo.form.Action.Load = function(form, options){
7918 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7919 this.reader = this.form.reader;
7922 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7927 Roo.Ajax.request(Roo.apply(
7928 this.createCallback(), {
7929 method:this.getMethod(),
7930 url:this.getUrl(false),
7931 params:this.getParams()
7935 success : function(response){
7937 var result = this.processResponse(response);
7938 if(result === true || !result.success || !result.data){
7939 this.failureType = Roo.form.Action.LOAD_FAILURE;
7940 this.form.afterAction(this, false);
7943 this.form.clearInvalid();
7944 this.form.setValues(result.data);
7945 this.form.afterAction(this, true);
7948 handleResponse : function(response){
7949 if(this.form.reader){
7950 var rs = this.form.reader.read(response);
7951 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7953 success : rs.success,
7957 return Roo.decode(response.responseText);
7961 Roo.form.Action.ACTION_TYPES = {
7962 'load' : Roo.form.Action.Load,
7963 'submit' : Roo.form.Action.Submit
7972 * @class Roo.bootstrap.Form
7973 * @extends Roo.bootstrap.Component
7974 * Bootstrap Form class
7975 * @cfg {String} method GET | POST (default POST)
7976 * @cfg {String} labelAlign top | left (default top)
7977 * @cfg {String} align left | right - for navbars
7978 * @cfg {Boolean} loadMask load mask when submit (default true)
7983 * @param {Object} config The config object
7987 Roo.bootstrap.Form = function(config){
7989 Roo.bootstrap.Form.superclass.constructor.call(this, config);
7991 Roo.bootstrap.Form.popover.apply();
7995 * @event clientvalidation
7996 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
7997 * @param {Form} this
7998 * @param {Boolean} valid true if the form has passed client-side validation
8000 clientvalidation: true,
8002 * @event beforeaction
8003 * Fires before any action is performed. Return false to cancel the action.
8004 * @param {Form} this
8005 * @param {Action} action The action to be performed
8009 * @event actionfailed
8010 * Fires when an action fails.
8011 * @param {Form} this
8012 * @param {Action} action The action that failed
8014 actionfailed : true,
8016 * @event actioncomplete
8017 * Fires when an action is completed.
8018 * @param {Form} this
8019 * @param {Action} action The action that completed
8021 actioncomplete : true
8025 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8028 * @cfg {String} method
8029 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8034 * The URL to use for form actions if one isn't supplied in the action options.
8037 * @cfg {Boolean} fileUpload
8038 * Set to true if this form is a file upload.
8042 * @cfg {Object} baseParams
8043 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8047 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8051 * @cfg {Sting} align (left|right) for navbar forms
8056 activeAction : null,
8059 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8060 * element by passing it or its id or mask the form itself by passing in true.
8063 waitMsgTarget : false,
8068 * @cfg {Boolean} errorMask (true|false) default false
8073 * @cfg {Number} maskOffset Default 100
8078 * @cfg {Boolean} maskBody
8082 getAutoCreate : function(){
8086 method : this.method || 'POST',
8087 id : this.id || Roo.id(),
8090 if (this.parent().xtype.match(/^Nav/)) {
8091 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8095 if (this.labelAlign == 'left' ) {
8096 cfg.cls += ' form-horizontal';
8102 initEvents : function()
8104 this.el.on('submit', this.onSubmit, this);
8105 // this was added as random key presses on the form where triggering form submit.
8106 this.el.on('keypress', function(e) {
8107 if (e.getCharCode() != 13) {
8110 // we might need to allow it for textareas.. and some other items.
8111 // check e.getTarget().
8113 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8117 Roo.log("keypress blocked");
8125 onSubmit : function(e){
8130 * Returns true if client-side validation on the form is successful.
8133 isValid : function(){
8134 var items = this.getItems();
8138 items.each(function(f){
8144 Roo.log('invalid field: ' + f.name);
8148 if(!target && f.el.isVisible(true)){
8154 if(this.errorMask && !valid){
8155 Roo.bootstrap.Form.popover.mask(this, target);
8162 * Returns true if any fields in this form have changed since their original load.
8165 isDirty : function(){
8167 var items = this.getItems();
8168 items.each(function(f){
8178 * Performs a predefined action (submit or load) or custom actions you define on this form.
8179 * @param {String} actionName The name of the action type
8180 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8181 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8182 * accept other config options):
8184 Property Type Description
8185 ---------------- --------------- ----------------------------------------------------------------------------------
8186 url String The url for the action (defaults to the form's url)
8187 method String The form method to use (defaults to the form's method, or POST if not defined)
8188 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8189 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8190 validate the form on the client (defaults to false)
8192 * @return {BasicForm} this
8194 doAction : function(action, options){
8195 if(typeof action == 'string'){
8196 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8198 if(this.fireEvent('beforeaction', this, action) !== false){
8199 this.beforeAction(action);
8200 action.run.defer(100, action);
8206 beforeAction : function(action){
8207 var o = action.options;
8212 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8214 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8217 // not really supported yet.. ??
8219 //if(this.waitMsgTarget === true){
8220 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8221 //}else if(this.waitMsgTarget){
8222 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8223 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8225 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8231 afterAction : function(action, success){
8232 this.activeAction = null;
8233 var o = action.options;
8238 Roo.get(document.body).unmask();
8244 //if(this.waitMsgTarget === true){
8245 // this.el.unmask();
8246 //}else if(this.waitMsgTarget){
8247 // this.waitMsgTarget.unmask();
8249 // Roo.MessageBox.updateProgress(1);
8250 // Roo.MessageBox.hide();
8257 Roo.callback(o.success, o.scope, [this, action]);
8258 this.fireEvent('actioncomplete', this, action);
8262 // failure condition..
8263 // we have a scenario where updates need confirming.
8264 // eg. if a locking scenario exists..
8265 // we look for { errors : { needs_confirm : true }} in the response.
8267 (typeof(action.result) != 'undefined') &&
8268 (typeof(action.result.errors) != 'undefined') &&
8269 (typeof(action.result.errors.needs_confirm) != 'undefined')
8272 Roo.log("not supported yet");
8275 Roo.MessageBox.confirm(
8276 "Change requires confirmation",
8277 action.result.errorMsg,
8282 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8292 Roo.callback(o.failure, o.scope, [this, action]);
8293 // show an error message if no failed handler is set..
8294 if (!this.hasListener('actionfailed')) {
8295 Roo.log("need to add dialog support");
8297 Roo.MessageBox.alert("Error",
8298 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8299 action.result.errorMsg :
8300 "Saving Failed, please check your entries or try again"
8305 this.fireEvent('actionfailed', this, action);
8310 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8311 * @param {String} id The value to search for
8314 findField : function(id){
8315 var items = this.getItems();
8316 var field = items.get(id);
8318 items.each(function(f){
8319 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8326 return field || null;
8329 * Mark fields in this form invalid in bulk.
8330 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8331 * @return {BasicForm} this
8333 markInvalid : function(errors){
8334 if(errors instanceof Array){
8335 for(var i = 0, len = errors.length; i < len; i++){
8336 var fieldError = errors[i];
8337 var f = this.findField(fieldError.id);
8339 f.markInvalid(fieldError.msg);
8345 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8346 field.markInvalid(errors[id]);
8350 //Roo.each(this.childForms || [], function (f) {
8351 // f.markInvalid(errors);
8358 * Set values for fields in this form in bulk.
8359 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8360 * @return {BasicForm} this
8362 setValues : function(values){
8363 if(values instanceof Array){ // array of objects
8364 for(var i = 0, len = values.length; i < len; i++){
8366 var f = this.findField(v.id);
8368 f.setValue(v.value);
8369 if(this.trackResetOnLoad){
8370 f.originalValue = f.getValue();
8374 }else{ // object hash
8377 if(typeof values[id] != 'function' && (field = this.findField(id))){
8379 if (field.setFromData &&
8381 field.displayField &&
8382 // combos' with local stores can
8383 // be queried via setValue()
8384 // to set their value..
8385 (field.store && !field.store.isLocal)
8389 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8390 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8391 field.setFromData(sd);
8393 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8395 field.setFromData(values);
8398 field.setValue(values[id]);
8402 if(this.trackResetOnLoad){
8403 field.originalValue = field.getValue();
8409 //Roo.each(this.childForms || [], function (f) {
8410 // f.setValues(values);
8417 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8418 * they are returned as an array.
8419 * @param {Boolean} asString
8422 getValues : function(asString){
8423 //if (this.childForms) {
8424 // copy values from the child forms
8425 // Roo.each(this.childForms, function (f) {
8426 // this.setValues(f.getValues());
8432 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8433 if(asString === true){
8436 return Roo.urlDecode(fs);
8440 * Returns the fields in this form as an object with key/value pairs.
8441 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8444 getFieldValues : function(with_hidden)
8446 var items = this.getItems();
8448 items.each(function(f){
8454 var v = f.getValue();
8456 if (f.inputType =='radio') {
8457 if (typeof(ret[f.getName()]) == 'undefined') {
8458 ret[f.getName()] = ''; // empty..
8461 if (!f.el.dom.checked) {
8469 if(f.xtype == 'MoneyField'){
8470 ret[f.currencyName] = f.getCurrency();
8473 // not sure if this supported any more..
8474 if ((typeof(v) == 'object') && f.getRawValue) {
8475 v = f.getRawValue() ; // dates..
8477 // combo boxes where name != hiddenName...
8478 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8479 ret[f.name] = f.getRawValue();
8481 ret[f.getName()] = v;
8488 * Clears all invalid messages in this form.
8489 * @return {BasicForm} this
8491 clearInvalid : function(){
8492 var items = this.getItems();
8494 items.each(function(f){
8503 * @return {BasicForm} this
8506 var items = this.getItems();
8507 items.each(function(f){
8511 Roo.each(this.childForms || [], function (f) {
8519 getItems : function()
8521 var r=new Roo.util.MixedCollection(false, function(o){
8522 return o.id || (o.id = Roo.id());
8524 var iter = function(el) {
8531 Roo.each(el.items,function(e) {
8540 hideFields : function(items)
8542 Roo.each(items, function(i){
8544 var f = this.findField(i);
8555 showFields : function(items)
8557 Roo.each(items, function(i){
8559 var f = this.findField(i);
8572 Roo.apply(Roo.bootstrap.Form, {
8599 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8600 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8601 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8602 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8605 this.maskEl.top.enableDisplayMode("block");
8606 this.maskEl.left.enableDisplayMode("block");
8607 this.maskEl.bottom.enableDisplayMode("block");
8608 this.maskEl.right.enableDisplayMode("block");
8610 this.toolTip = new Roo.bootstrap.Tooltip({
8611 cls : 'roo-form-error-popover',
8613 'left' : ['r-l', [-2,0], 'right'],
8614 'right' : ['l-r', [2,0], 'left'],
8615 'bottom' : ['tl-bl', [0,2], 'top'],
8616 'top' : [ 'bl-tl', [0,-2], 'bottom']
8620 this.toolTip.render(Roo.get(document.body));
8622 this.toolTip.el.enableDisplayMode("block");
8624 Roo.get(document.body).on('click', function(){
8628 Roo.get(document.body).on('touchstart', function(){
8632 this.isApplied = true
8635 mask : function(form, target)
8639 this.target = target;
8641 if(!this.form.errorMask || !target.el){
8645 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8647 Roo.log(scrollable);
8649 var ot = this.target.el.calcOffsetsTo(scrollable);
8651 var scrollTo = ot[1] - this.form.maskOffset;
8653 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8655 scrollable.scrollTo('top', scrollTo);
8657 var box = this.target.el.getBox();
8659 var zIndex = Roo.bootstrap.Modal.zIndex++;
8662 this.maskEl.top.setStyle('position', 'absolute');
8663 this.maskEl.top.setStyle('z-index', zIndex);
8664 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8665 this.maskEl.top.setLeft(0);
8666 this.maskEl.top.setTop(0);
8667 this.maskEl.top.show();
8669 this.maskEl.left.setStyle('position', 'absolute');
8670 this.maskEl.left.setStyle('z-index', zIndex);
8671 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8672 this.maskEl.left.setLeft(0);
8673 this.maskEl.left.setTop(box.y - this.padding);
8674 this.maskEl.left.show();
8676 this.maskEl.bottom.setStyle('position', 'absolute');
8677 this.maskEl.bottom.setStyle('z-index', zIndex);
8678 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8679 this.maskEl.bottom.setLeft(0);
8680 this.maskEl.bottom.setTop(box.bottom + this.padding);
8681 this.maskEl.bottom.show();
8683 this.maskEl.right.setStyle('position', 'absolute');
8684 this.maskEl.right.setStyle('z-index', zIndex);
8685 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8686 this.maskEl.right.setLeft(box.right + this.padding);
8687 this.maskEl.right.setTop(box.y - this.padding);
8688 this.maskEl.right.show();
8690 this.toolTip.bindEl = this.target.el;
8692 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8694 var tip = this.target.blankText;
8696 if(this.target.getValue() !== '' ) {
8698 if (this.target.invalidText.length) {
8699 tip = this.target.invalidText;
8700 } else if (this.target.regexText.length){
8701 tip = this.target.regexText;
8705 this.toolTip.show(tip);
8707 this.intervalID = window.setInterval(function() {
8708 Roo.bootstrap.Form.popover.unmask();
8711 window.onwheel = function(){ return false;};
8713 (function(){ this.isMasked = true; }).defer(500, this);
8719 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8723 this.maskEl.top.setStyle('position', 'absolute');
8724 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8725 this.maskEl.top.hide();
8727 this.maskEl.left.setStyle('position', 'absolute');
8728 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8729 this.maskEl.left.hide();
8731 this.maskEl.bottom.setStyle('position', 'absolute');
8732 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8733 this.maskEl.bottom.hide();
8735 this.maskEl.right.setStyle('position', 'absolute');
8736 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8737 this.maskEl.right.hide();
8739 this.toolTip.hide();
8741 this.toolTip.el.hide();
8743 window.onwheel = function(){ return true;};
8745 if(this.intervalID){
8746 window.clearInterval(this.intervalID);
8747 this.intervalID = false;
8750 this.isMasked = false;
8760 * Ext JS Library 1.1.1
8761 * Copyright(c) 2006-2007, Ext JS, LLC.
8763 * Originally Released Under LGPL - original licence link has changed is not relivant.
8766 * <script type="text/javascript">
8769 * @class Roo.form.VTypes
8770 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8773 Roo.form.VTypes = function(){
8774 // closure these in so they are only created once.
8775 var alpha = /^[a-zA-Z_]+$/;
8776 var alphanum = /^[a-zA-Z0-9_]+$/;
8777 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8778 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8780 // All these messages and functions are configurable
8783 * The function used to validate email addresses
8784 * @param {String} value The email address
8786 'email' : function(v){
8787 return email.test(v);
8790 * The error text to display when the email validation function returns false
8793 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8795 * The keystroke filter mask to be applied on email input
8798 'emailMask' : /[a-z0-9_\.\-@]/i,
8801 * The function used to validate URLs
8802 * @param {String} value The URL
8804 'url' : function(v){
8808 * The error text to display when the url validation function returns false
8811 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8814 * The function used to validate alpha values
8815 * @param {String} value The value
8817 'alpha' : function(v){
8818 return alpha.test(v);
8821 * The error text to display when the alpha validation function returns false
8824 'alphaText' : 'This field should only contain letters and _',
8826 * The keystroke filter mask to be applied on alpha input
8829 'alphaMask' : /[a-z_]/i,
8832 * The function used to validate alphanumeric values
8833 * @param {String} value The value
8835 'alphanum' : function(v){
8836 return alphanum.test(v);
8839 * The error text to display when the alphanumeric validation function returns false
8842 'alphanumText' : 'This field should only contain letters, numbers and _',
8844 * The keystroke filter mask to be applied on alphanumeric input
8847 'alphanumMask' : /[a-z0-9_]/i
8857 * @class Roo.bootstrap.Input
8858 * @extends Roo.bootstrap.Component
8859 * Bootstrap Input class
8860 * @cfg {Boolean} disabled is it disabled
8861 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8862 * @cfg {String} name name of the input
8863 * @cfg {string} fieldLabel - the label associated
8864 * @cfg {string} placeholder - placeholder to put in text.
8865 * @cfg {string} before - input group add on before
8866 * @cfg {string} after - input group add on after
8867 * @cfg {string} size - (lg|sm) or leave empty..
8868 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8869 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8870 * @cfg {Number} md colspan out of 12 for computer-sized screens
8871 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8872 * @cfg {string} value default value of the input
8873 * @cfg {Number} labelWidth set the width of label
8874 * @cfg {Number} labellg set the width of label (1-12)
8875 * @cfg {Number} labelmd set the width of label (1-12)
8876 * @cfg {Number} labelsm set the width of label (1-12)
8877 * @cfg {Number} labelxs set the width of label (1-12)
8878 * @cfg {String} labelAlign (top|left)
8879 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8880 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8881 * @cfg {String} indicatorpos (left|right) default left
8882 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8883 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8885 * @cfg {String} align (left|center|right) Default left
8886 * @cfg {Boolean} forceFeedback (true|false) Default false
8889 * Create a new Input
8890 * @param {Object} config The config object
8893 Roo.bootstrap.Input = function(config){
8895 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8900 * Fires when this field receives input focus.
8901 * @param {Roo.form.Field} this
8906 * Fires when this field loses input focus.
8907 * @param {Roo.form.Field} this
8912 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8913 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8914 * @param {Roo.form.Field} this
8915 * @param {Roo.EventObject} e The event object
8920 * Fires just before the field blurs if the field value has changed.
8921 * @param {Roo.form.Field} this
8922 * @param {Mixed} newValue The new value
8923 * @param {Mixed} oldValue The original value
8928 * Fires after the field has been marked as invalid.
8929 * @param {Roo.form.Field} this
8930 * @param {String} msg The validation message
8935 * Fires after the field has been validated with no errors.
8936 * @param {Roo.form.Field} this
8941 * Fires after the key up
8942 * @param {Roo.form.Field} this
8943 * @param {Roo.EventObject} e The event Object
8949 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8951 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8952 automatic validation (defaults to "keyup").
8954 validationEvent : "keyup",
8956 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8958 validateOnBlur : true,
8960 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8962 validationDelay : 250,
8964 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8966 focusClass : "x-form-focus", // not needed???
8970 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8972 invalidClass : "has-warning",
8975 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
8977 validClass : "has-success",
8980 * @cfg {Boolean} hasFeedback (true|false) default true
8985 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8987 invalidFeedbackClass : "glyphicon-warning-sign",
8990 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
8992 validFeedbackClass : "glyphicon-ok",
8995 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
8997 selectOnFocus : false,
9000 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9004 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9009 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9011 disableKeyFilter : false,
9014 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9018 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9022 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9024 blankText : "Please complete this mandatory field",
9027 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9031 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9033 maxLength : Number.MAX_VALUE,
9035 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9037 minLengthText : "The minimum length for this field is {0}",
9039 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9041 maxLengthText : "The maximum length for this field is {0}",
9045 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9046 * If available, this function will be called only after the basic validators all return true, and will be passed the
9047 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9051 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9052 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9053 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9057 * @cfg {String} regexText -- Depricated - use Invalid Text
9062 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9068 autocomplete: false,
9087 formatedValue : false,
9088 forceFeedback : false,
9090 indicatorpos : 'left',
9100 parentLabelAlign : function()
9103 while (parent.parent()) {
9104 parent = parent.parent();
9105 if (typeof(parent.labelAlign) !='undefined') {
9106 return parent.labelAlign;
9113 getAutoCreate : function()
9115 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9121 if(this.inputType != 'hidden'){
9122 cfg.cls = 'form-group' //input-group
9128 type : this.inputType,
9130 cls : 'form-control',
9131 placeholder : this.placeholder || '',
9132 autocomplete : this.autocomplete || 'new-password'
9135 if(this.capture.length){
9136 input.capture = this.capture;
9139 if(this.accept.length){
9140 input.accept = this.accept + "/*";
9144 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9147 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9148 input.maxLength = this.maxLength;
9151 if (this.disabled) {
9152 input.disabled=true;
9155 if (this.readOnly) {
9156 input.readonly=true;
9160 input.name = this.name;
9164 input.cls += ' input-' + this.size;
9168 ['xs','sm','md','lg'].map(function(size){
9169 if (settings[size]) {
9170 cfg.cls += ' col-' + size + '-' + settings[size];
9174 var inputblock = input;
9178 cls: 'glyphicon form-control-feedback'
9181 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9184 cls : 'has-feedback',
9192 if (this.before || this.after) {
9195 cls : 'input-group',
9199 if (this.before && typeof(this.before) == 'string') {
9201 inputblock.cn.push({
9203 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9207 if (this.before && typeof(this.before) == 'object') {
9208 this.before = Roo.factory(this.before);
9210 inputblock.cn.push({
9212 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9213 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9217 inputblock.cn.push(input);
9219 if (this.after && typeof(this.after) == 'string') {
9220 inputblock.cn.push({
9222 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9226 if (this.after && typeof(this.after) == 'object') {
9227 this.after = Roo.factory(this.after);
9229 inputblock.cn.push({
9231 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9232 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9236 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9237 inputblock.cls += ' has-feedback';
9238 inputblock.cn.push(feedback);
9243 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9244 tooltip : 'This field is required'
9246 if (Roo.bootstrap.version == 4) {
9249 style : 'display-none'
9252 if (align ==='left' && this.fieldLabel.length) {
9254 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9261 cls : 'control-label col-form-label',
9262 html : this.fieldLabel
9273 var labelCfg = cfg.cn[1];
9274 var contentCfg = cfg.cn[2];
9276 if(this.indicatorpos == 'right'){
9281 cls : 'control-label col-form-label',
9285 html : this.fieldLabel
9299 labelCfg = cfg.cn[0];
9300 contentCfg = cfg.cn[1];
9304 if(this.labelWidth > 12){
9305 labelCfg.style = "width: " + this.labelWidth + 'px';
9308 if(this.labelWidth < 13 && this.labelmd == 0){
9309 this.labelmd = this.labelWidth;
9312 if(this.labellg > 0){
9313 labelCfg.cls += ' col-lg-' + this.labellg;
9314 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9317 if(this.labelmd > 0){
9318 labelCfg.cls += ' col-md-' + this.labelmd;
9319 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9322 if(this.labelsm > 0){
9323 labelCfg.cls += ' col-sm-' + this.labelsm;
9324 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9327 if(this.labelxs > 0){
9328 labelCfg.cls += ' col-xs-' + this.labelxs;
9329 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9333 } else if ( this.fieldLabel.length) {
9338 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9339 tooltip : 'This field is required'
9343 //cls : 'input-group-addon',
9344 html : this.fieldLabel
9352 if(this.indicatorpos == 'right'){
9357 //cls : 'input-group-addon',
9358 html : this.fieldLabel
9363 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9364 tooltip : 'This field is required'
9384 if (this.parentType === 'Navbar' && this.parent().bar) {
9385 cfg.cls += ' navbar-form';
9388 if (this.parentType === 'NavGroup') {
9389 cfg.cls += ' navbar-form';
9397 * return the real input element.
9399 inputEl: function ()
9401 return this.el.select('input.form-control',true).first();
9404 tooltipEl : function()
9406 return this.inputEl();
9409 indicatorEl : function()
9411 if (Roo.bootstrap.version == 4) {
9412 return false; // not enabled in v4 yet.
9415 var indicator = this.el.select('i.roo-required-indicator',true).first();
9425 setDisabled : function(v)
9427 var i = this.inputEl().dom;
9429 i.removeAttribute('disabled');
9433 i.setAttribute('disabled','true');
9435 initEvents : function()
9438 this.inputEl().on("keydown" , this.fireKey, this);
9439 this.inputEl().on("focus", this.onFocus, this);
9440 this.inputEl().on("blur", this.onBlur, this);
9442 this.inputEl().relayEvent('keyup', this);
9444 this.indicator = this.indicatorEl();
9447 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9450 // reference to original value for reset
9451 this.originalValue = this.getValue();
9452 //Roo.form.TextField.superclass.initEvents.call(this);
9453 if(this.validationEvent == 'keyup'){
9454 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9455 this.inputEl().on('keyup', this.filterValidation, this);
9457 else if(this.validationEvent !== false){
9458 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9461 if(this.selectOnFocus){
9462 this.on("focus", this.preFocus, this);
9465 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9466 this.inputEl().on("keypress", this.filterKeys, this);
9468 this.inputEl().relayEvent('keypress', this);
9471 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9472 this.el.on("click", this.autoSize, this);
9475 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9476 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9479 if (typeof(this.before) == 'object') {
9480 this.before.render(this.el.select('.roo-input-before',true).first());
9482 if (typeof(this.after) == 'object') {
9483 this.after.render(this.el.select('.roo-input-after',true).first());
9486 this.inputEl().on('change', this.onChange, this);
9489 filterValidation : function(e){
9490 if(!e.isNavKeyPress()){
9491 this.validationTask.delay(this.validationDelay);
9495 * Validates the field value
9496 * @return {Boolean} True if the value is valid, else false
9498 validate : function(){
9499 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9500 if(this.disabled || this.validateValue(this.getRawValue())){
9511 * Validates a value according to the field's validation rules and marks the field as invalid
9512 * if the validation fails
9513 * @param {Mixed} value The value to validate
9514 * @return {Boolean} True if the value is valid, else false
9516 validateValue : function(value)
9518 if(this.getVisibilityEl().hasClass('hidden')){
9522 if(value.length < 1) { // if it's blank
9523 if(this.allowBlank){
9529 if(value.length < this.minLength){
9532 if(value.length > this.maxLength){
9536 var vt = Roo.form.VTypes;
9537 if(!vt[this.vtype](value, this)){
9541 if(typeof this.validator == "function"){
9542 var msg = this.validator(value);
9546 if (typeof(msg) == 'string') {
9547 this.invalidText = msg;
9551 if(this.regex && !this.regex.test(value)){
9559 fireKey : function(e){
9560 //Roo.log('field ' + e.getKey());
9561 if(e.isNavKeyPress()){
9562 this.fireEvent("specialkey", this, e);
9565 focus : function (selectText){
9567 this.inputEl().focus();
9568 if(selectText === true){
9569 this.inputEl().dom.select();
9575 onFocus : function(){
9576 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9577 // this.el.addClass(this.focusClass);
9580 this.hasFocus = true;
9581 this.startValue = this.getValue();
9582 this.fireEvent("focus", this);
9586 beforeBlur : Roo.emptyFn,
9590 onBlur : function(){
9592 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9593 //this.el.removeClass(this.focusClass);
9595 this.hasFocus = false;
9596 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9599 var v = this.getValue();
9600 if(String(v) !== String(this.startValue)){
9601 this.fireEvent('change', this, v, this.startValue);
9603 this.fireEvent("blur", this);
9606 onChange : function(e)
9608 var v = this.getValue();
9609 if(String(v) !== String(this.startValue)){
9610 this.fireEvent('change', this, v, this.startValue);
9616 * Resets the current field value to the originally loaded value and clears any validation messages
9619 this.setValue(this.originalValue);
9623 * Returns the name of the field
9624 * @return {Mixed} name The name field
9626 getName: function(){
9630 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9631 * @return {Mixed} value The field value
9633 getValue : function(){
9635 var v = this.inputEl().getValue();
9640 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9641 * @return {Mixed} value The field value
9643 getRawValue : function(){
9644 var v = this.inputEl().getValue();
9650 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9651 * @param {Mixed} value The value to set
9653 setRawValue : function(v){
9654 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9657 selectText : function(start, end){
9658 var v = this.getRawValue();
9660 start = start === undefined ? 0 : start;
9661 end = end === undefined ? v.length : end;
9662 var d = this.inputEl().dom;
9663 if(d.setSelectionRange){
9664 d.setSelectionRange(start, end);
9665 }else if(d.createTextRange){
9666 var range = d.createTextRange();
9667 range.moveStart("character", start);
9668 range.moveEnd("character", v.length-end);
9675 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9676 * @param {Mixed} value The value to set
9678 setValue : function(v){
9681 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9687 processValue : function(value){
9688 if(this.stripCharsRe){
9689 var newValue = value.replace(this.stripCharsRe, '');
9690 if(newValue !== value){
9691 this.setRawValue(newValue);
9698 preFocus : function(){
9700 if(this.selectOnFocus){
9701 this.inputEl().dom.select();
9704 filterKeys : function(e){
9706 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9709 var c = e.getCharCode(), cc = String.fromCharCode(c);
9710 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9713 if(!this.maskRe.test(cc)){
9718 * Clear any invalid styles/messages for this field
9720 clearInvalid : function(){
9722 if(!this.el || this.preventMark){ // not rendered
9727 this.el.removeClass(this.invalidClass);
9729 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9731 var feedback = this.el.select('.form-control-feedback', true).first();
9734 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9740 this.indicator.removeClass('visible');
9741 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9744 this.fireEvent('valid', this);
9748 * Mark this field as valid
9750 markValid : function()
9752 if(!this.el || this.preventMark){ // not rendered...
9756 this.el.removeClass([this.invalidClass, this.validClass]);
9758 var feedback = this.el.select('.form-control-feedback', true).first();
9761 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9765 this.indicator.removeClass('visible');
9766 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9773 if(this.allowBlank && !this.getRawValue().length){
9777 this.el.addClass(this.validClass);
9779 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9781 var feedback = this.el.select('.form-control-feedback', true).first();
9784 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9785 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9790 this.fireEvent('valid', this);
9794 * Mark this field as invalid
9795 * @param {String} msg The validation message
9797 markInvalid : function(msg)
9799 if(!this.el || this.preventMark){ // not rendered
9803 this.el.removeClass([this.invalidClass, this.validClass]);
9805 var feedback = this.el.select('.form-control-feedback', true).first();
9808 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9815 if(this.allowBlank && !this.getRawValue().length){
9820 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9821 this.indicator.addClass('visible');
9824 this.el.addClass(this.invalidClass);
9826 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9828 var feedback = this.el.select('.form-control-feedback', true).first();
9831 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9833 if(this.getValue().length || this.forceFeedback){
9834 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9841 this.fireEvent('invalid', this, msg);
9844 SafariOnKeyDown : function(event)
9846 // this is a workaround for a password hang bug on chrome/ webkit.
9847 if (this.inputEl().dom.type != 'password') {
9851 var isSelectAll = false;
9853 if(this.inputEl().dom.selectionEnd > 0){
9854 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9856 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9857 event.preventDefault();
9862 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9864 event.preventDefault();
9865 // this is very hacky as keydown always get's upper case.
9867 var cc = String.fromCharCode(event.getCharCode());
9868 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9872 adjustWidth : function(tag, w){
9873 tag = tag.toLowerCase();
9874 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9875 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9879 if(tag == 'textarea'){
9882 }else if(Roo.isOpera){
9886 if(tag == 'textarea'){
9894 setFieldLabel : function(v)
9900 if(this.indicatorEl()){
9901 var ar = this.el.select('label > span',true);
9903 if (ar.elements.length) {
9904 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9905 this.fieldLabel = v;
9909 var br = this.el.select('label',true);
9911 if(br.elements.length) {
9912 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9913 this.fieldLabel = v;
9917 Roo.log('Cannot Found any of label > span || label in input');
9921 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9922 this.fieldLabel = v;
9937 * @class Roo.bootstrap.TextArea
9938 * @extends Roo.bootstrap.Input
9939 * Bootstrap TextArea class
9940 * @cfg {Number} cols Specifies the visible width of a text area
9941 * @cfg {Number} rows Specifies the visible number of lines in a text area
9942 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9943 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9944 * @cfg {string} html text
9947 * Create a new TextArea
9948 * @param {Object} config The config object
9951 Roo.bootstrap.TextArea = function(config){
9952 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9956 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9966 getAutoCreate : function(){
9968 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9974 if(this.inputType != 'hidden'){
9975 cfg.cls = 'form-group' //input-group
9983 value : this.value || '',
9984 html: this.html || '',
9985 cls : 'form-control',
9986 placeholder : this.placeholder || ''
9990 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9991 input.maxLength = this.maxLength;
9995 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
9999 input.cols = this.cols;
10002 if (this.readOnly) {
10003 input.readonly = true;
10007 input.name = this.name;
10011 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10015 ['xs','sm','md','lg'].map(function(size){
10016 if (settings[size]) {
10017 cfg.cls += ' col-' + size + '-' + settings[size];
10021 var inputblock = input;
10023 if(this.hasFeedback && !this.allowBlank){
10027 cls: 'glyphicon form-control-feedback'
10031 cls : 'has-feedback',
10040 if (this.before || this.after) {
10043 cls : 'input-group',
10047 inputblock.cn.push({
10049 cls : 'input-group-addon',
10054 inputblock.cn.push(input);
10056 if(this.hasFeedback && !this.allowBlank){
10057 inputblock.cls += ' has-feedback';
10058 inputblock.cn.push(feedback);
10062 inputblock.cn.push({
10064 cls : 'input-group-addon',
10071 if (align ==='left' && this.fieldLabel.length) {
10076 cls : 'control-label',
10077 html : this.fieldLabel
10088 if(this.labelWidth > 12){
10089 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10092 if(this.labelWidth < 13 && this.labelmd == 0){
10093 this.labelmd = this.labelWidth;
10096 if(this.labellg > 0){
10097 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10098 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10101 if(this.labelmd > 0){
10102 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10103 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10106 if(this.labelsm > 0){
10107 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10108 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10111 if(this.labelxs > 0){
10112 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10113 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10116 } else if ( this.fieldLabel.length) {
10121 //cls : 'input-group-addon',
10122 html : this.fieldLabel
10140 if (this.disabled) {
10141 input.disabled=true;
10148 * return the real textarea element.
10150 inputEl: function ()
10152 return this.el.select('textarea.form-control',true).first();
10156 * Clear any invalid styles/messages for this field
10158 clearInvalid : function()
10161 if(!this.el || this.preventMark){ // not rendered
10165 var label = this.el.select('label', true).first();
10166 var icon = this.el.select('i.fa-star', true).first();
10172 this.el.removeClass(this.invalidClass);
10174 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10176 var feedback = this.el.select('.form-control-feedback', true).first();
10179 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10184 this.fireEvent('valid', this);
10188 * Mark this field as valid
10190 markValid : function()
10192 if(!this.el || this.preventMark){ // not rendered
10196 this.el.removeClass([this.invalidClass, this.validClass]);
10198 var feedback = this.el.select('.form-control-feedback', true).first();
10201 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10204 if(this.disabled || this.allowBlank){
10208 var label = this.el.select('label', true).first();
10209 var icon = this.el.select('i.fa-star', true).first();
10215 this.el.addClass(this.validClass);
10217 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10219 var feedback = this.el.select('.form-control-feedback', true).first();
10222 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10223 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10228 this.fireEvent('valid', this);
10232 * Mark this field as invalid
10233 * @param {String} msg The validation message
10235 markInvalid : function(msg)
10237 if(!this.el || this.preventMark){ // not rendered
10241 this.el.removeClass([this.invalidClass, this.validClass]);
10243 var feedback = this.el.select('.form-control-feedback', true).first();
10246 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10249 if(this.disabled || this.allowBlank){
10253 var label = this.el.select('label', true).first();
10254 var icon = this.el.select('i.fa-star', true).first();
10256 if(!this.getValue().length && label && !icon){
10257 this.el.createChild({
10259 cls : 'text-danger fa fa-lg fa-star',
10260 tooltip : 'This field is required',
10261 style : 'margin-right:5px;'
10265 this.el.addClass(this.invalidClass);
10267 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10269 var feedback = this.el.select('.form-control-feedback', true).first();
10272 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10274 if(this.getValue().length || this.forceFeedback){
10275 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10282 this.fireEvent('invalid', this, msg);
10290 * trigger field - base class for combo..
10295 * @class Roo.bootstrap.TriggerField
10296 * @extends Roo.bootstrap.Input
10297 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10298 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10299 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10300 * for which you can provide a custom implementation. For example:
10302 var trigger = new Roo.bootstrap.TriggerField();
10303 trigger.onTriggerClick = myTriggerFn;
10304 trigger.applyTo('my-field');
10307 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10308 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10309 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10310 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10311 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10314 * Create a new TriggerField.
10315 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10316 * to the base TextField)
10318 Roo.bootstrap.TriggerField = function(config){
10319 this.mimicing = false;
10320 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10323 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10325 * @cfg {String} triggerClass A CSS class to apply to the trigger
10328 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10333 * @cfg {Boolean} removable (true|false) special filter default false
10337 /** @cfg {Boolean} grow @hide */
10338 /** @cfg {Number} growMin @hide */
10339 /** @cfg {Number} growMax @hide */
10345 autoSize: Roo.emptyFn,
10349 deferHeight : true,
10352 actionMode : 'wrap',
10357 getAutoCreate : function(){
10359 var align = this.labelAlign || this.parentLabelAlign();
10364 cls: 'form-group' //input-group
10371 type : this.inputType,
10372 cls : 'form-control',
10373 autocomplete: 'new-password',
10374 placeholder : this.placeholder || ''
10378 input.name = this.name;
10381 input.cls += ' input-' + this.size;
10384 if (this.disabled) {
10385 input.disabled=true;
10388 var inputblock = input;
10390 if(this.hasFeedback && !this.allowBlank){
10394 cls: 'glyphicon form-control-feedback'
10397 if(this.removable && !this.editable && !this.tickable){
10399 cls : 'has-feedback',
10405 cls : 'roo-combo-removable-btn close'
10412 cls : 'has-feedback',
10421 if(this.removable && !this.editable && !this.tickable){
10423 cls : 'roo-removable',
10429 cls : 'roo-combo-removable-btn close'
10436 if (this.before || this.after) {
10439 cls : 'input-group',
10443 inputblock.cn.push({
10445 cls : 'input-group-addon input-group-prepend input-group-text',
10450 inputblock.cn.push(input);
10452 if(this.hasFeedback && !this.allowBlank){
10453 inputblock.cls += ' has-feedback';
10454 inputblock.cn.push(feedback);
10458 inputblock.cn.push({
10460 cls : 'input-group-addon input-group-append input-group-text',
10469 var ibwrap = inputblock;
10474 cls: 'roo-select2-choices',
10478 cls: 'roo-select2-search-field',
10490 cls: 'roo-select2-container input-group',
10495 cls: 'form-hidden-field'
10501 if(!this.multiple && this.showToggleBtn){
10507 if (this.caret != false) {
10510 cls: 'fa fa-' + this.caret
10517 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10522 cls: 'combobox-clear',
10536 combobox.cls += ' roo-select2-container-multi';
10540 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10541 tooltip : 'This field is required'
10543 if (Roo.bootstrap.version == 4) {
10546 style : 'display:none'
10551 if (align ==='left' && this.fieldLabel.length) {
10553 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10560 cls : 'control-label',
10561 html : this.fieldLabel
10573 var labelCfg = cfg.cn[1];
10574 var contentCfg = cfg.cn[2];
10576 if(this.indicatorpos == 'right'){
10581 cls : 'control-label',
10585 html : this.fieldLabel
10599 labelCfg = cfg.cn[0];
10600 contentCfg = cfg.cn[1];
10603 if(this.labelWidth > 12){
10604 labelCfg.style = "width: " + this.labelWidth + 'px';
10607 if(this.labelWidth < 13 && this.labelmd == 0){
10608 this.labelmd = this.labelWidth;
10611 if(this.labellg > 0){
10612 labelCfg.cls += ' col-lg-' + this.labellg;
10613 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10616 if(this.labelmd > 0){
10617 labelCfg.cls += ' col-md-' + this.labelmd;
10618 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10621 if(this.labelsm > 0){
10622 labelCfg.cls += ' col-sm-' + this.labelsm;
10623 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10626 if(this.labelxs > 0){
10627 labelCfg.cls += ' col-xs-' + this.labelxs;
10628 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10631 } else if ( this.fieldLabel.length) {
10632 // Roo.log(" label");
10637 //cls : 'input-group-addon',
10638 html : this.fieldLabel
10646 if(this.indicatorpos == 'right'){
10654 html : this.fieldLabel
10668 // Roo.log(" no label && no align");
10675 ['xs','sm','md','lg'].map(function(size){
10676 if (settings[size]) {
10677 cfg.cls += ' col-' + size + '-' + settings[size];
10688 onResize : function(w, h){
10689 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10690 // if(typeof w == 'number'){
10691 // var x = w - this.trigger.getWidth();
10692 // this.inputEl().setWidth(this.adjustWidth('input', x));
10693 // this.trigger.setStyle('left', x+'px');
10698 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10701 getResizeEl : function(){
10702 return this.inputEl();
10706 getPositionEl : function(){
10707 return this.inputEl();
10711 alignErrorIcon : function(){
10712 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10716 initEvents : function(){
10720 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10721 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10722 if(!this.multiple && this.showToggleBtn){
10723 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10724 if(this.hideTrigger){
10725 this.trigger.setDisplayed(false);
10727 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10731 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10734 if(this.removable && !this.editable && !this.tickable){
10735 var close = this.closeTriggerEl();
10738 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10739 close.on('click', this.removeBtnClick, this, close);
10743 //this.trigger.addClassOnOver('x-form-trigger-over');
10744 //this.trigger.addClassOnClick('x-form-trigger-click');
10747 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10751 closeTriggerEl : function()
10753 var close = this.el.select('.roo-combo-removable-btn', true).first();
10754 return close ? close : false;
10757 removeBtnClick : function(e, h, el)
10759 e.preventDefault();
10761 if(this.fireEvent("remove", this) !== false){
10763 this.fireEvent("afterremove", this)
10767 createList : function()
10769 this.list = Roo.get(document.body).createChild({
10770 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10771 cls: 'typeahead typeahead-long dropdown-menu',
10772 style: 'display:none'
10775 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10780 initTrigger : function(){
10785 onDestroy : function(){
10787 this.trigger.removeAllListeners();
10788 // this.trigger.remove();
10791 // this.wrap.remove();
10793 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10797 onFocus : function(){
10798 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10800 if(!this.mimicing){
10801 this.wrap.addClass('x-trigger-wrap-focus');
10802 this.mimicing = true;
10803 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10804 if(this.monitorTab){
10805 this.el.on("keydown", this.checkTab, this);
10812 checkTab : function(e){
10813 if(e.getKey() == e.TAB){
10814 this.triggerBlur();
10819 onBlur : function(){
10824 mimicBlur : function(e, t){
10826 if(!this.wrap.contains(t) && this.validateBlur()){
10827 this.triggerBlur();
10833 triggerBlur : function(){
10834 this.mimicing = false;
10835 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10836 if(this.monitorTab){
10837 this.el.un("keydown", this.checkTab, this);
10839 //this.wrap.removeClass('x-trigger-wrap-focus');
10840 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10844 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10845 validateBlur : function(e, t){
10850 onDisable : function(){
10851 this.inputEl().dom.disabled = true;
10852 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10854 // this.wrap.addClass('x-item-disabled');
10859 onEnable : function(){
10860 this.inputEl().dom.disabled = false;
10861 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10863 // this.el.removeClass('x-item-disabled');
10868 onShow : function(){
10869 var ae = this.getActionEl();
10872 ae.dom.style.display = '';
10873 ae.dom.style.visibility = 'visible';
10879 onHide : function(){
10880 var ae = this.getActionEl();
10881 ae.dom.style.display = 'none';
10885 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10886 * by an implementing function.
10888 * @param {EventObject} e
10890 onTriggerClick : Roo.emptyFn
10894 * Ext JS Library 1.1.1
10895 * Copyright(c) 2006-2007, Ext JS, LLC.
10897 * Originally Released Under LGPL - original licence link has changed is not relivant.
10900 * <script type="text/javascript">
10905 * @class Roo.data.SortTypes
10907 * Defines the default sorting (casting?) comparison functions used when sorting data.
10909 Roo.data.SortTypes = {
10911 * Default sort that does nothing
10912 * @param {Mixed} s The value being converted
10913 * @return {Mixed} The comparison value
10915 none : function(s){
10920 * The regular expression used to strip tags
10924 stripTagsRE : /<\/?[^>]+>/gi,
10927 * Strips all HTML tags to sort on text only
10928 * @param {Mixed} s The value being converted
10929 * @return {String} The comparison value
10931 asText : function(s){
10932 return String(s).replace(this.stripTagsRE, "");
10936 * Strips all HTML tags to sort on text only - Case insensitive
10937 * @param {Mixed} s The value being converted
10938 * @return {String} The comparison value
10940 asUCText : function(s){
10941 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10945 * Case insensitive string
10946 * @param {Mixed} s The value being converted
10947 * @return {String} The comparison value
10949 asUCString : function(s) {
10950 return String(s).toUpperCase();
10955 * @param {Mixed} s The value being converted
10956 * @return {Number} The comparison value
10958 asDate : function(s) {
10962 if(s instanceof Date){
10963 return s.getTime();
10965 return Date.parse(String(s));
10970 * @param {Mixed} s The value being converted
10971 * @return {Float} The comparison value
10973 asFloat : function(s) {
10974 var val = parseFloat(String(s).replace(/,/g, ""));
10983 * @param {Mixed} s The value being converted
10984 * @return {Number} The comparison value
10986 asInt : function(s) {
10987 var val = parseInt(String(s).replace(/,/g, ""));
10995 * Ext JS Library 1.1.1
10996 * Copyright(c) 2006-2007, Ext JS, LLC.
10998 * Originally Released Under LGPL - original licence link has changed is not relivant.
11001 * <script type="text/javascript">
11005 * @class Roo.data.Record
11006 * Instances of this class encapsulate both record <em>definition</em> information, and record
11007 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11008 * to access Records cached in an {@link Roo.data.Store} object.<br>
11010 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11011 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11014 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11016 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11017 * {@link #create}. The parameters are the same.
11018 * @param {Array} data An associative Array of data values keyed by the field name.
11019 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11020 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11021 * not specified an integer id is generated.
11023 Roo.data.Record = function(data, id){
11024 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11029 * Generate a constructor for a specific record layout.
11030 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11031 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11032 * Each field definition object may contain the following properties: <ul>
11033 * <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,
11034 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11035 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11036 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11037 * is being used, then this is a string containing the javascript expression to reference the data relative to
11038 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11039 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11040 * this may be omitted.</p></li>
11041 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11042 * <ul><li>auto (Default, implies no conversion)</li>
11047 * <li>date</li></ul></p></li>
11048 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11049 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11050 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11051 * by the Reader into an object that will be stored in the Record. It is passed the
11052 * following parameters:<ul>
11053 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11055 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11057 * <br>usage:<br><pre><code>
11058 var TopicRecord = Roo.data.Record.create(
11059 {name: 'title', mapping: 'topic_title'},
11060 {name: 'author', mapping: 'username'},
11061 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11062 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11063 {name: 'lastPoster', mapping: 'user2'},
11064 {name: 'excerpt', mapping: 'post_text'}
11067 var myNewRecord = new TopicRecord({
11068 title: 'Do my job please',
11071 lastPost: new Date(),
11072 lastPoster: 'Animal',
11073 excerpt: 'No way dude!'
11075 myStore.add(myNewRecord);
11080 Roo.data.Record.create = function(o){
11081 var f = function(){
11082 f.superclass.constructor.apply(this, arguments);
11084 Roo.extend(f, Roo.data.Record);
11085 var p = f.prototype;
11086 p.fields = new Roo.util.MixedCollection(false, function(field){
11089 for(var i = 0, len = o.length; i < len; i++){
11090 p.fields.add(new Roo.data.Field(o[i]));
11092 f.getField = function(name){
11093 return p.fields.get(name);
11098 Roo.data.Record.AUTO_ID = 1000;
11099 Roo.data.Record.EDIT = 'edit';
11100 Roo.data.Record.REJECT = 'reject';
11101 Roo.data.Record.COMMIT = 'commit';
11103 Roo.data.Record.prototype = {
11105 * Readonly flag - true if this record has been modified.
11114 join : function(store){
11115 this.store = store;
11119 * Set the named field to the specified value.
11120 * @param {String} name The name of the field to set.
11121 * @param {Object} value The value to set the field to.
11123 set : function(name, value){
11124 if(this.data[name] == value){
11128 if(!this.modified){
11129 this.modified = {};
11131 if(typeof this.modified[name] == 'undefined'){
11132 this.modified[name] = this.data[name];
11134 this.data[name] = value;
11135 if(!this.editing && this.store){
11136 this.store.afterEdit(this);
11141 * Get the value of the named field.
11142 * @param {String} name The name of the field to get the value of.
11143 * @return {Object} The value of the field.
11145 get : function(name){
11146 return this.data[name];
11150 beginEdit : function(){
11151 this.editing = true;
11152 this.modified = {};
11156 cancelEdit : function(){
11157 this.editing = false;
11158 delete this.modified;
11162 endEdit : function(){
11163 this.editing = false;
11164 if(this.dirty && this.store){
11165 this.store.afterEdit(this);
11170 * Usually called by the {@link Roo.data.Store} which owns the Record.
11171 * Rejects all changes made to the Record since either creation, or the last commit operation.
11172 * Modified fields are reverted to their original values.
11174 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11175 * of reject operations.
11177 reject : function(){
11178 var m = this.modified;
11180 if(typeof m[n] != "function"){
11181 this.data[n] = m[n];
11184 this.dirty = false;
11185 delete this.modified;
11186 this.editing = false;
11188 this.store.afterReject(this);
11193 * Usually called by the {@link Roo.data.Store} which owns the Record.
11194 * Commits all changes made to the Record since either creation, or the last commit operation.
11196 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11197 * of commit operations.
11199 commit : function(){
11200 this.dirty = false;
11201 delete this.modified;
11202 this.editing = false;
11204 this.store.afterCommit(this);
11209 hasError : function(){
11210 return this.error != null;
11214 clearError : function(){
11219 * Creates a copy of this record.
11220 * @param {String} id (optional) A new record id if you don't want to use this record's id
11223 copy : function(newId) {
11224 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11228 * Ext JS Library 1.1.1
11229 * Copyright(c) 2006-2007, Ext JS, LLC.
11231 * Originally Released Under LGPL - original licence link has changed is not relivant.
11234 * <script type="text/javascript">
11240 * @class Roo.data.Store
11241 * @extends Roo.util.Observable
11242 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11243 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11245 * 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
11246 * has no knowledge of the format of the data returned by the Proxy.<br>
11248 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11249 * instances from the data object. These records are cached and made available through accessor functions.
11251 * Creates a new Store.
11252 * @param {Object} config A config object containing the objects needed for the Store to access data,
11253 * and read the data into Records.
11255 Roo.data.Store = function(config){
11256 this.data = new Roo.util.MixedCollection(false);
11257 this.data.getKey = function(o){
11260 this.baseParams = {};
11262 this.paramNames = {
11267 "multisort" : "_multisort"
11270 if(config && config.data){
11271 this.inlineData = config.data;
11272 delete config.data;
11275 Roo.apply(this, config);
11277 if(this.reader){ // reader passed
11278 this.reader = Roo.factory(this.reader, Roo.data);
11279 this.reader.xmodule = this.xmodule || false;
11280 if(!this.recordType){
11281 this.recordType = this.reader.recordType;
11283 if(this.reader.onMetaChange){
11284 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11288 if(this.recordType){
11289 this.fields = this.recordType.prototype.fields;
11291 this.modified = [];
11295 * @event datachanged
11296 * Fires when the data cache has changed, and a widget which is using this Store
11297 * as a Record cache should refresh its view.
11298 * @param {Store} this
11300 datachanged : true,
11302 * @event metachange
11303 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11304 * @param {Store} this
11305 * @param {Object} meta The JSON metadata
11310 * Fires when Records have been added to the Store
11311 * @param {Store} this
11312 * @param {Roo.data.Record[]} records The array of Records added
11313 * @param {Number} index The index at which the record(s) were added
11318 * Fires when a Record has been removed from the Store
11319 * @param {Store} this
11320 * @param {Roo.data.Record} record The Record that was removed
11321 * @param {Number} index The index at which the record was removed
11326 * Fires when a Record has been updated
11327 * @param {Store} this
11328 * @param {Roo.data.Record} record The Record that was updated
11329 * @param {String} operation The update operation being performed. Value may be one of:
11331 Roo.data.Record.EDIT
11332 Roo.data.Record.REJECT
11333 Roo.data.Record.COMMIT
11339 * Fires when the data cache has been cleared.
11340 * @param {Store} this
11344 * @event beforeload
11345 * Fires before a request is made for a new data object. If the beforeload handler returns false
11346 * the load action will be canceled.
11347 * @param {Store} this
11348 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11352 * @event beforeloadadd
11353 * Fires after a new set of Records has been loaded.
11354 * @param {Store} this
11355 * @param {Roo.data.Record[]} records The Records that were loaded
11356 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11358 beforeloadadd : true,
11361 * Fires after a new set of Records has been loaded, before they are added to the store.
11362 * @param {Store} this
11363 * @param {Roo.data.Record[]} records The Records that were loaded
11364 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11365 * @params {Object} return from reader
11369 * @event loadexception
11370 * Fires if an exception occurs in the Proxy during loading.
11371 * Called with the signature of the Proxy's "loadexception" event.
11372 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11375 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11376 * @param {Object} load options
11377 * @param {Object} jsonData from your request (normally this contains the Exception)
11379 loadexception : true
11383 this.proxy = Roo.factory(this.proxy, Roo.data);
11384 this.proxy.xmodule = this.xmodule || false;
11385 this.relayEvents(this.proxy, ["loadexception"]);
11387 this.sortToggle = {};
11388 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11390 Roo.data.Store.superclass.constructor.call(this);
11392 if(this.inlineData){
11393 this.loadData(this.inlineData);
11394 delete this.inlineData;
11398 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11400 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11401 * without a remote query - used by combo/forms at present.
11405 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11408 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11411 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11412 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11415 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11416 * on any HTTP request
11419 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11422 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11426 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11427 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11429 remoteSort : false,
11432 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11433 * loaded or when a record is removed. (defaults to false).
11435 pruneModifiedRecords : false,
11438 lastOptions : null,
11441 * Add Records to the Store and fires the add event.
11442 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11444 add : function(records){
11445 records = [].concat(records);
11446 for(var i = 0, len = records.length; i < len; i++){
11447 records[i].join(this);
11449 var index = this.data.length;
11450 this.data.addAll(records);
11451 this.fireEvent("add", this, records, index);
11455 * Remove a Record from the Store and fires the remove event.
11456 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11458 remove : function(record){
11459 var index = this.data.indexOf(record);
11460 this.data.removeAt(index);
11462 if(this.pruneModifiedRecords){
11463 this.modified.remove(record);
11465 this.fireEvent("remove", this, record, index);
11469 * Remove all Records from the Store and fires the clear event.
11471 removeAll : function(){
11473 if(this.pruneModifiedRecords){
11474 this.modified = [];
11476 this.fireEvent("clear", this);
11480 * Inserts Records to the Store at the given index and fires the add event.
11481 * @param {Number} index The start index at which to insert the passed Records.
11482 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11484 insert : function(index, records){
11485 records = [].concat(records);
11486 for(var i = 0, len = records.length; i < len; i++){
11487 this.data.insert(index, records[i]);
11488 records[i].join(this);
11490 this.fireEvent("add", this, records, index);
11494 * Get the index within the cache of the passed Record.
11495 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11496 * @return {Number} The index of the passed Record. Returns -1 if not found.
11498 indexOf : function(record){
11499 return this.data.indexOf(record);
11503 * Get the index within the cache of the Record with the passed id.
11504 * @param {String} id The id of the Record to find.
11505 * @return {Number} The index of the Record. Returns -1 if not found.
11507 indexOfId : function(id){
11508 return this.data.indexOfKey(id);
11512 * Get the Record with the specified id.
11513 * @param {String} id The id of the Record to find.
11514 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11516 getById : function(id){
11517 return this.data.key(id);
11521 * Get the Record at the specified index.
11522 * @param {Number} index The index of the Record to find.
11523 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11525 getAt : function(index){
11526 return this.data.itemAt(index);
11530 * Returns a range of Records between specified indices.
11531 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11532 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11533 * @return {Roo.data.Record[]} An array of Records
11535 getRange : function(start, end){
11536 return this.data.getRange(start, end);
11540 storeOptions : function(o){
11541 o = Roo.apply({}, o);
11544 this.lastOptions = o;
11548 * Loads the Record cache from the configured Proxy using the configured Reader.
11550 * If using remote paging, then the first load call must specify the <em>start</em>
11551 * and <em>limit</em> properties in the options.params property to establish the initial
11552 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11554 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11555 * and this call will return before the new data has been loaded. Perform any post-processing
11556 * in a callback function, or in a "load" event handler.</strong>
11558 * @param {Object} options An object containing properties which control loading options:<ul>
11559 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11560 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11561 * passed the following arguments:<ul>
11562 * <li>r : Roo.data.Record[]</li>
11563 * <li>options: Options object from the load call</li>
11564 * <li>success: Boolean success indicator</li></ul></li>
11565 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11566 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11569 load : function(options){
11570 options = options || {};
11571 if(this.fireEvent("beforeload", this, options) !== false){
11572 this.storeOptions(options);
11573 var p = Roo.apply(options.params || {}, this.baseParams);
11574 // if meta was not loaded from remote source.. try requesting it.
11575 if (!this.reader.metaFromRemote) {
11576 p._requestMeta = 1;
11578 if(this.sortInfo && this.remoteSort){
11579 var pn = this.paramNames;
11580 p[pn["sort"]] = this.sortInfo.field;
11581 p[pn["dir"]] = this.sortInfo.direction;
11583 if (this.multiSort) {
11584 var pn = this.paramNames;
11585 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11588 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11593 * Reloads the Record cache from the configured Proxy using the configured Reader and
11594 * the options from the last load operation performed.
11595 * @param {Object} options (optional) An object containing properties which may override the options
11596 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11597 * the most recently used options are reused).
11599 reload : function(options){
11600 this.load(Roo.applyIf(options||{}, this.lastOptions));
11604 // Called as a callback by the Reader during a load operation.
11605 loadRecords : function(o, options, success){
11606 if(!o || success === false){
11607 if(success !== false){
11608 this.fireEvent("load", this, [], options, o);
11610 if(options.callback){
11611 options.callback.call(options.scope || this, [], options, false);
11615 // if data returned failure - throw an exception.
11616 if (o.success === false) {
11617 // show a message if no listener is registered.
11618 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11619 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11621 // loadmask wil be hooked into this..
11622 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11625 var r = o.records, t = o.totalRecords || r.length;
11627 this.fireEvent("beforeloadadd", this, r, options, o);
11629 if(!options || options.add !== true){
11630 if(this.pruneModifiedRecords){
11631 this.modified = [];
11633 for(var i = 0, len = r.length; i < len; i++){
11637 this.data = this.snapshot;
11638 delete this.snapshot;
11641 this.data.addAll(r);
11642 this.totalLength = t;
11644 this.fireEvent("datachanged", this);
11646 this.totalLength = Math.max(t, this.data.length+r.length);
11650 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11652 var e = new Roo.data.Record({});
11654 e.set(this.parent.displayField, this.parent.emptyTitle);
11655 e.set(this.parent.valueField, '');
11660 this.fireEvent("load", this, r, options, o);
11661 if(options.callback){
11662 options.callback.call(options.scope || this, r, options, true);
11668 * Loads data from a passed data block. A Reader which understands the format of the data
11669 * must have been configured in the constructor.
11670 * @param {Object} data The data block from which to read the Records. The format of the data expected
11671 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11672 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11674 loadData : function(o, append){
11675 var r = this.reader.readRecords(o);
11676 this.loadRecords(r, {add: append}, true);
11680 * Gets the number of cached records.
11682 * <em>If using paging, this may not be the total size of the dataset. If the data object
11683 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11684 * the data set size</em>
11686 getCount : function(){
11687 return this.data.length || 0;
11691 * Gets the total number of records in the dataset as returned by the server.
11693 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11694 * the dataset size</em>
11696 getTotalCount : function(){
11697 return this.totalLength || 0;
11701 * Returns the sort state of the Store as an object with two properties:
11703 field {String} The name of the field by which the Records are sorted
11704 direction {String} The sort order, "ASC" or "DESC"
11707 getSortState : function(){
11708 return this.sortInfo;
11712 applySort : function(){
11713 if(this.sortInfo && !this.remoteSort){
11714 var s = this.sortInfo, f = s.field;
11715 var st = this.fields.get(f).sortType;
11716 var fn = function(r1, r2){
11717 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11718 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11720 this.data.sort(s.direction, fn);
11721 if(this.snapshot && this.snapshot != this.data){
11722 this.snapshot.sort(s.direction, fn);
11728 * Sets the default sort column and order to be used by the next load operation.
11729 * @param {String} fieldName The name of the field to sort by.
11730 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11732 setDefaultSort : function(field, dir){
11733 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11737 * Sort the Records.
11738 * If remote sorting is used, the sort is performed on the server, and the cache is
11739 * reloaded. If local sorting is used, the cache is sorted internally.
11740 * @param {String} fieldName The name of the field to sort by.
11741 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11743 sort : function(fieldName, dir){
11744 var f = this.fields.get(fieldName);
11746 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11748 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11749 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11754 this.sortToggle[f.name] = dir;
11755 this.sortInfo = {field: f.name, direction: dir};
11756 if(!this.remoteSort){
11758 this.fireEvent("datachanged", this);
11760 this.load(this.lastOptions);
11765 * Calls the specified function for each of the Records in the cache.
11766 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11767 * Returning <em>false</em> aborts and exits the iteration.
11768 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11770 each : function(fn, scope){
11771 this.data.each(fn, scope);
11775 * Gets all records modified since the last commit. Modified records are persisted across load operations
11776 * (e.g., during paging).
11777 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11779 getModifiedRecords : function(){
11780 return this.modified;
11784 createFilterFn : function(property, value, anyMatch){
11785 if(!value.exec){ // not a regex
11786 value = String(value);
11787 if(value.length == 0){
11790 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11792 return function(r){
11793 return value.test(r.data[property]);
11798 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11799 * @param {String} property A field on your records
11800 * @param {Number} start The record index to start at (defaults to 0)
11801 * @param {Number} end The last record index to include (defaults to length - 1)
11802 * @return {Number} The sum
11804 sum : function(property, start, end){
11805 var rs = this.data.items, v = 0;
11806 start = start || 0;
11807 end = (end || end === 0) ? end : rs.length-1;
11809 for(var i = start; i <= end; i++){
11810 v += (rs[i].data[property] || 0);
11816 * Filter the records by a specified property.
11817 * @param {String} field A field on your records
11818 * @param {String/RegExp} value Either a string that the field
11819 * should start with or a RegExp to test against the field
11820 * @param {Boolean} anyMatch True to match any part not just the beginning
11822 filter : function(property, value, anyMatch){
11823 var fn = this.createFilterFn(property, value, anyMatch);
11824 return fn ? this.filterBy(fn) : this.clearFilter();
11828 * Filter by a function. The specified function will be called with each
11829 * record in this data source. If the function returns true the record is included,
11830 * otherwise it is filtered.
11831 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11832 * @param {Object} scope (optional) The scope of the function (defaults to this)
11834 filterBy : function(fn, scope){
11835 this.snapshot = this.snapshot || this.data;
11836 this.data = this.queryBy(fn, scope||this);
11837 this.fireEvent("datachanged", this);
11841 * Query the records by a specified property.
11842 * @param {String} field A field on your records
11843 * @param {String/RegExp} value Either a string that the field
11844 * should start with or a RegExp to test against the field
11845 * @param {Boolean} anyMatch True to match any part not just the beginning
11846 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11848 query : function(property, value, anyMatch){
11849 var fn = this.createFilterFn(property, value, anyMatch);
11850 return fn ? this.queryBy(fn) : this.data.clone();
11854 * Query by a function. The specified function will be called with each
11855 * record in this data source. If the function returns true the record is included
11857 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11858 * @param {Object} scope (optional) The scope of the function (defaults to this)
11859 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11861 queryBy : function(fn, scope){
11862 var data = this.snapshot || this.data;
11863 return data.filterBy(fn, scope||this);
11867 * Collects unique values for a particular dataIndex from this store.
11868 * @param {String} dataIndex The property to collect
11869 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11870 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11871 * @return {Array} An array of the unique values
11873 collect : function(dataIndex, allowNull, bypassFilter){
11874 var d = (bypassFilter === true && this.snapshot) ?
11875 this.snapshot.items : this.data.items;
11876 var v, sv, r = [], l = {};
11877 for(var i = 0, len = d.length; i < len; i++){
11878 v = d[i].data[dataIndex];
11880 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11889 * Revert to a view of the Record cache with no filtering applied.
11890 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11892 clearFilter : function(suppressEvent){
11893 if(this.snapshot && this.snapshot != this.data){
11894 this.data = this.snapshot;
11895 delete this.snapshot;
11896 if(suppressEvent !== true){
11897 this.fireEvent("datachanged", this);
11903 afterEdit : function(record){
11904 if(this.modified.indexOf(record) == -1){
11905 this.modified.push(record);
11907 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11911 afterReject : function(record){
11912 this.modified.remove(record);
11913 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11917 afterCommit : function(record){
11918 this.modified.remove(record);
11919 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11923 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11924 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11926 commitChanges : function(){
11927 var m = this.modified.slice(0);
11928 this.modified = [];
11929 for(var i = 0, len = m.length; i < len; i++){
11935 * Cancel outstanding changes on all changed records.
11937 rejectChanges : function(){
11938 var m = this.modified.slice(0);
11939 this.modified = [];
11940 for(var i = 0, len = m.length; i < len; i++){
11945 onMetaChange : function(meta, rtype, o){
11946 this.recordType = rtype;
11947 this.fields = rtype.prototype.fields;
11948 delete this.snapshot;
11949 this.sortInfo = meta.sortInfo || this.sortInfo;
11950 this.modified = [];
11951 this.fireEvent('metachange', this, this.reader.meta);
11954 moveIndex : function(data, type)
11956 var index = this.indexOf(data);
11958 var newIndex = index + type;
11962 this.insert(newIndex, data);
11967 * Ext JS Library 1.1.1
11968 * Copyright(c) 2006-2007, Ext JS, LLC.
11970 * Originally Released Under LGPL - original licence link has changed is not relivant.
11973 * <script type="text/javascript">
11977 * @class Roo.data.SimpleStore
11978 * @extends Roo.data.Store
11979 * Small helper class to make creating Stores from Array data easier.
11980 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
11981 * @cfg {Array} fields An array of field definition objects, or field name strings.
11982 * @cfg {Array} data The multi-dimensional array of data
11984 * @param {Object} config
11986 Roo.data.SimpleStore = function(config){
11987 Roo.data.SimpleStore.superclass.constructor.call(this, {
11989 reader: new Roo.data.ArrayReader({
11992 Roo.data.Record.create(config.fields)
11994 proxy : new Roo.data.MemoryProxy(config.data)
11998 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12000 * Ext JS Library 1.1.1
12001 * Copyright(c) 2006-2007, Ext JS, LLC.
12003 * Originally Released Under LGPL - original licence link has changed is not relivant.
12006 * <script type="text/javascript">
12011 * @extends Roo.data.Store
12012 * @class Roo.data.JsonStore
12013 * Small helper class to make creating Stores for JSON data easier. <br/>
12015 var store = new Roo.data.JsonStore({
12016 url: 'get-images.php',
12018 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12021 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12022 * JsonReader and HttpProxy (unless inline data is provided).</b>
12023 * @cfg {Array} fields An array of field definition objects, or field name strings.
12025 * @param {Object} config
12027 Roo.data.JsonStore = function(c){
12028 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12029 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12030 reader: new Roo.data.JsonReader(c, c.fields)
12033 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12035 * Ext JS Library 1.1.1
12036 * Copyright(c) 2006-2007, Ext JS, LLC.
12038 * Originally Released Under LGPL - original licence link has changed is not relivant.
12041 * <script type="text/javascript">
12045 Roo.data.Field = function(config){
12046 if(typeof config == "string"){
12047 config = {name: config};
12049 Roo.apply(this, config);
12052 this.type = "auto";
12055 var st = Roo.data.SortTypes;
12056 // named sortTypes are supported, here we look them up
12057 if(typeof this.sortType == "string"){
12058 this.sortType = st[this.sortType];
12061 // set default sortType for strings and dates
12062 if(!this.sortType){
12065 this.sortType = st.asUCString;
12068 this.sortType = st.asDate;
12071 this.sortType = st.none;
12076 var stripRe = /[\$,%]/g;
12078 // prebuilt conversion function for this field, instead of
12079 // switching every time we're reading a value
12081 var cv, dateFormat = this.dateFormat;
12086 cv = function(v){ return v; };
12089 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12093 return v !== undefined && v !== null && v !== '' ?
12094 parseInt(String(v).replace(stripRe, ""), 10) : '';
12099 return v !== undefined && v !== null && v !== '' ?
12100 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12105 cv = function(v){ return v === true || v === "true" || v == 1; };
12112 if(v instanceof Date){
12116 if(dateFormat == "timestamp"){
12117 return new Date(v*1000);
12119 return Date.parseDate(v, dateFormat);
12121 var parsed = Date.parse(v);
12122 return parsed ? new Date(parsed) : null;
12131 Roo.data.Field.prototype = {
12139 * Ext JS Library 1.1.1
12140 * Copyright(c) 2006-2007, Ext JS, LLC.
12142 * Originally Released Under LGPL - original licence link has changed is not relivant.
12145 * <script type="text/javascript">
12148 // Base class for reading structured data from a data source. This class is intended to be
12149 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12152 * @class Roo.data.DataReader
12153 * Base class for reading structured data from a data source. This class is intended to be
12154 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12157 Roo.data.DataReader = function(meta, recordType){
12161 this.recordType = recordType instanceof Array ?
12162 Roo.data.Record.create(recordType) : recordType;
12165 Roo.data.DataReader.prototype = {
12167 * Create an empty record
12168 * @param {Object} data (optional) - overlay some values
12169 * @return {Roo.data.Record} record created.
12171 newRow : function(d) {
12173 this.recordType.prototype.fields.each(function(c) {
12175 case 'int' : da[c.name] = 0; break;
12176 case 'date' : da[c.name] = new Date(); break;
12177 case 'float' : da[c.name] = 0.0; break;
12178 case 'boolean' : da[c.name] = false; break;
12179 default : da[c.name] = ""; break;
12183 return new this.recordType(Roo.apply(da, d));
12188 * Ext JS Library 1.1.1
12189 * Copyright(c) 2006-2007, Ext JS, LLC.
12191 * Originally Released Under LGPL - original licence link has changed is not relivant.
12194 * <script type="text/javascript">
12198 * @class Roo.data.DataProxy
12199 * @extends Roo.data.Observable
12200 * This class is an abstract base class for implementations which provide retrieval of
12201 * unformatted data objects.<br>
12203 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12204 * (of the appropriate type which knows how to parse the data object) to provide a block of
12205 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12207 * Custom implementations must implement the load method as described in
12208 * {@link Roo.data.HttpProxy#load}.
12210 Roo.data.DataProxy = function(){
12213 * @event beforeload
12214 * Fires before a network request is made to retrieve a data object.
12215 * @param {Object} This DataProxy object.
12216 * @param {Object} params The params parameter to the load function.
12221 * Fires before the load method's callback is called.
12222 * @param {Object} This DataProxy object.
12223 * @param {Object} o The data object.
12224 * @param {Object} arg The callback argument object passed to the load function.
12228 * @event loadexception
12229 * Fires if an Exception occurs during data retrieval.
12230 * @param {Object} This DataProxy object.
12231 * @param {Object} o The data object.
12232 * @param {Object} arg The callback argument object passed to the load function.
12233 * @param {Object} e The Exception.
12235 loadexception : true
12237 Roo.data.DataProxy.superclass.constructor.call(this);
12240 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12243 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12247 * Ext JS Library 1.1.1
12248 * Copyright(c) 2006-2007, Ext JS, LLC.
12250 * Originally Released Under LGPL - original licence link has changed is not relivant.
12253 * <script type="text/javascript">
12256 * @class Roo.data.MemoryProxy
12257 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12258 * to the Reader when its load method is called.
12260 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12262 Roo.data.MemoryProxy = function(data){
12266 Roo.data.MemoryProxy.superclass.constructor.call(this);
12270 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12273 * Load data from the requested source (in this case an in-memory
12274 * data object passed to the constructor), read the data object into
12275 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12276 * process that block using the passed callback.
12277 * @param {Object} params This parameter is not used by the MemoryProxy class.
12278 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12279 * object into a block of Roo.data.Records.
12280 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12281 * The function must be passed <ul>
12282 * <li>The Record block object</li>
12283 * <li>The "arg" argument from the load function</li>
12284 * <li>A boolean success indicator</li>
12286 * @param {Object} scope The scope in which to call the callback
12287 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12289 load : function(params, reader, callback, scope, arg){
12290 params = params || {};
12293 result = reader.readRecords(this.data);
12295 this.fireEvent("loadexception", this, arg, null, e);
12296 callback.call(scope, null, arg, false);
12299 callback.call(scope, result, arg, true);
12303 update : function(params, records){
12308 * Ext JS Library 1.1.1
12309 * Copyright(c) 2006-2007, Ext JS, LLC.
12311 * Originally Released Under LGPL - original licence link has changed is not relivant.
12314 * <script type="text/javascript">
12317 * @class Roo.data.HttpProxy
12318 * @extends Roo.data.DataProxy
12319 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12320 * configured to reference a certain URL.<br><br>
12322 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12323 * from which the running page was served.<br><br>
12325 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12327 * Be aware that to enable the browser to parse an XML document, the server must set
12328 * the Content-Type header in the HTTP response to "text/xml".
12330 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12331 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12332 * will be used to make the request.
12334 Roo.data.HttpProxy = function(conn){
12335 Roo.data.HttpProxy.superclass.constructor.call(this);
12336 // is conn a conn config or a real conn?
12338 this.useAjax = !conn || !conn.events;
12342 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12343 // thse are take from connection...
12346 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12349 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12350 * extra parameters to each request made by this object. (defaults to undefined)
12353 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12354 * to each request made by this object. (defaults to undefined)
12357 * @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)
12360 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12363 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12369 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12373 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12374 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12375 * a finer-grained basis than the DataProxy events.
12377 getConnection : function(){
12378 return this.useAjax ? Roo.Ajax : this.conn;
12382 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12383 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12384 * process that block using the passed callback.
12385 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12386 * for the request to the remote server.
12387 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12388 * object into a block of Roo.data.Records.
12389 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12390 * The function must be passed <ul>
12391 * <li>The Record block object</li>
12392 * <li>The "arg" argument from the load function</li>
12393 * <li>A boolean success indicator</li>
12395 * @param {Object} scope The scope in which to call the callback
12396 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12398 load : function(params, reader, callback, scope, arg){
12399 if(this.fireEvent("beforeload", this, params) !== false){
12401 params : params || {},
12403 callback : callback,
12408 callback : this.loadResponse,
12412 Roo.applyIf(o, this.conn);
12413 if(this.activeRequest){
12414 Roo.Ajax.abort(this.activeRequest);
12416 this.activeRequest = Roo.Ajax.request(o);
12418 this.conn.request(o);
12421 callback.call(scope||this, null, arg, false);
12426 loadResponse : function(o, success, response){
12427 delete this.activeRequest;
12429 this.fireEvent("loadexception", this, o, response);
12430 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12435 result = o.reader.read(response);
12437 this.fireEvent("loadexception", this, o, response, e);
12438 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12442 this.fireEvent("load", this, o, o.request.arg);
12443 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12447 update : function(dataSet){
12452 updateResponse : function(dataSet){
12457 * Ext JS Library 1.1.1
12458 * Copyright(c) 2006-2007, Ext JS, LLC.
12460 * Originally Released Under LGPL - original licence link has changed is not relivant.
12463 * <script type="text/javascript">
12467 * @class Roo.data.ScriptTagProxy
12468 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12469 * other than the originating domain of the running page.<br><br>
12471 * <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
12472 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12474 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12475 * source code that is used as the source inside a <script> tag.<br><br>
12477 * In order for the browser to process the returned data, the server must wrap the data object
12478 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12479 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12480 * depending on whether the callback name was passed:
12483 boolean scriptTag = false;
12484 String cb = request.getParameter("callback");
12487 response.setContentType("text/javascript");
12489 response.setContentType("application/x-json");
12491 Writer out = response.getWriter();
12493 out.write(cb + "(");
12495 out.print(dataBlock.toJsonString());
12502 * @param {Object} config A configuration object.
12504 Roo.data.ScriptTagProxy = function(config){
12505 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12506 Roo.apply(this, config);
12507 this.head = document.getElementsByTagName("head")[0];
12510 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12512 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12514 * @cfg {String} url The URL from which to request the data object.
12517 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12521 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12522 * the server the name of the callback function set up by the load call to process the returned data object.
12523 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12524 * javascript output which calls this named function passing the data object as its only parameter.
12526 callbackParam : "callback",
12528 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12529 * name to the request.
12534 * Load data from the configured URL, read the data object into
12535 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12536 * process that block using the passed callback.
12537 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12538 * for the request to the remote server.
12539 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12540 * object into a block of Roo.data.Records.
12541 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12542 * The function must be passed <ul>
12543 * <li>The Record block object</li>
12544 * <li>The "arg" argument from the load function</li>
12545 * <li>A boolean success indicator</li>
12547 * @param {Object} scope The scope in which to call the callback
12548 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12550 load : function(params, reader, callback, scope, arg){
12551 if(this.fireEvent("beforeload", this, params) !== false){
12553 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12555 var url = this.url;
12556 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12558 url += "&_dc=" + (new Date().getTime());
12560 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12563 cb : "stcCallback"+transId,
12564 scriptId : "stcScript"+transId,
12568 callback : callback,
12574 window[trans.cb] = function(o){
12575 conn.handleResponse(o, trans);
12578 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12580 if(this.autoAbort !== false){
12584 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12586 var script = document.createElement("script");
12587 script.setAttribute("src", url);
12588 script.setAttribute("type", "text/javascript");
12589 script.setAttribute("id", trans.scriptId);
12590 this.head.appendChild(script);
12592 this.trans = trans;
12594 callback.call(scope||this, null, arg, false);
12599 isLoading : function(){
12600 return this.trans ? true : false;
12604 * Abort the current server request.
12606 abort : function(){
12607 if(this.isLoading()){
12608 this.destroyTrans(this.trans);
12613 destroyTrans : function(trans, isLoaded){
12614 this.head.removeChild(document.getElementById(trans.scriptId));
12615 clearTimeout(trans.timeoutId);
12617 window[trans.cb] = undefined;
12619 delete window[trans.cb];
12622 // if hasn't been loaded, wait for load to remove it to prevent script error
12623 window[trans.cb] = function(){
12624 window[trans.cb] = undefined;
12626 delete window[trans.cb];
12633 handleResponse : function(o, trans){
12634 this.trans = false;
12635 this.destroyTrans(trans, true);
12638 result = trans.reader.readRecords(o);
12640 this.fireEvent("loadexception", this, o, trans.arg, e);
12641 trans.callback.call(trans.scope||window, null, trans.arg, false);
12644 this.fireEvent("load", this, o, trans.arg);
12645 trans.callback.call(trans.scope||window, result, trans.arg, true);
12649 handleFailure : function(trans){
12650 this.trans = false;
12651 this.destroyTrans(trans, false);
12652 this.fireEvent("loadexception", this, null, trans.arg);
12653 trans.callback.call(trans.scope||window, null, trans.arg, false);
12657 * Ext JS Library 1.1.1
12658 * Copyright(c) 2006-2007, Ext JS, LLC.
12660 * Originally Released Under LGPL - original licence link has changed is not relivant.
12663 * <script type="text/javascript">
12667 * @class Roo.data.JsonReader
12668 * @extends Roo.data.DataReader
12669 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12670 * based on mappings in a provided Roo.data.Record constructor.
12672 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12673 * in the reply previously.
12678 var RecordDef = Roo.data.Record.create([
12679 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12680 {name: 'occupation'} // This field will use "occupation" as the mapping.
12682 var myReader = new Roo.data.JsonReader({
12683 totalProperty: "results", // The property which contains the total dataset size (optional)
12684 root: "rows", // The property which contains an Array of row objects
12685 id: "id" // The property within each row object that provides an ID for the record (optional)
12689 * This would consume a JSON file like this:
12691 { 'results': 2, 'rows': [
12692 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12693 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12696 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12697 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12698 * paged from the remote server.
12699 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12700 * @cfg {String} root name of the property which contains the Array of row objects.
12701 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12702 * @cfg {Array} fields Array of field definition objects
12704 * Create a new JsonReader
12705 * @param {Object} meta Metadata configuration options
12706 * @param {Object} recordType Either an Array of field definition objects,
12707 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12709 Roo.data.JsonReader = function(meta, recordType){
12712 // set some defaults:
12713 Roo.applyIf(meta, {
12714 totalProperty: 'total',
12715 successProperty : 'success',
12720 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12722 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12725 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12726 * Used by Store query builder to append _requestMeta to params.
12729 metaFromRemote : false,
12731 * This method is only used by a DataProxy which has retrieved data from a remote server.
12732 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12733 * @return {Object} data A data block which is used by an Roo.data.Store object as
12734 * a cache of Roo.data.Records.
12736 read : function(response){
12737 var json = response.responseText;
12739 var o = /* eval:var:o */ eval("("+json+")");
12741 throw {message: "JsonReader.read: Json object not found"};
12747 this.metaFromRemote = true;
12748 this.meta = o.metaData;
12749 this.recordType = Roo.data.Record.create(o.metaData.fields);
12750 this.onMetaChange(this.meta, this.recordType, o);
12752 return this.readRecords(o);
12755 // private function a store will implement
12756 onMetaChange : function(meta, recordType, o){
12763 simpleAccess: function(obj, subsc) {
12770 getJsonAccessor: function(){
12772 return function(expr) {
12774 return(re.test(expr))
12775 ? new Function("obj", "return obj." + expr)
12780 return Roo.emptyFn;
12785 * Create a data block containing Roo.data.Records from an XML document.
12786 * @param {Object} o An object which contains an Array of row objects in the property specified
12787 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12788 * which contains the total size of the dataset.
12789 * @return {Object} data A data block which is used by an Roo.data.Store object as
12790 * a cache of Roo.data.Records.
12792 readRecords : function(o){
12794 * After any data loads, the raw JSON data is available for further custom processing.
12798 var s = this.meta, Record = this.recordType,
12799 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12801 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12803 if(s.totalProperty) {
12804 this.getTotal = this.getJsonAccessor(s.totalProperty);
12806 if(s.successProperty) {
12807 this.getSuccess = this.getJsonAccessor(s.successProperty);
12809 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12811 var g = this.getJsonAccessor(s.id);
12812 this.getId = function(rec) {
12814 return (r === undefined || r === "") ? null : r;
12817 this.getId = function(){return null;};
12820 for(var jj = 0; jj < fl; jj++){
12822 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12823 this.ef[jj] = this.getJsonAccessor(map);
12827 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12828 if(s.totalProperty){
12829 var vt = parseInt(this.getTotal(o), 10);
12834 if(s.successProperty){
12835 var vs = this.getSuccess(o);
12836 if(vs === false || vs === 'false'){
12841 for(var i = 0; i < c; i++){
12844 var id = this.getId(n);
12845 for(var j = 0; j < fl; j++){
12847 var v = this.ef[j](n);
12849 Roo.log('missing convert for ' + f.name);
12853 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12855 var record = new Record(values, id);
12857 records[i] = record;
12863 totalRecords : totalRecords
12868 * Ext JS Library 1.1.1
12869 * Copyright(c) 2006-2007, Ext JS, LLC.
12871 * Originally Released Under LGPL - original licence link has changed is not relivant.
12874 * <script type="text/javascript">
12878 * @class Roo.data.ArrayReader
12879 * @extends Roo.data.DataReader
12880 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12881 * Each element of that Array represents a row of data fields. The
12882 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12883 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12887 var RecordDef = Roo.data.Record.create([
12888 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12889 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12891 var myReader = new Roo.data.ArrayReader({
12892 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12896 * This would consume an Array like this:
12898 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12900 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12902 * Create a new JsonReader
12903 * @param {Object} meta Metadata configuration options.
12904 * @param {Object} recordType Either an Array of field definition objects
12905 * as specified to {@link Roo.data.Record#create},
12906 * or an {@link Roo.data.Record} object
12907 * created using {@link Roo.data.Record#create}.
12909 Roo.data.ArrayReader = function(meta, recordType){
12910 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12913 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12915 * Create a data block containing Roo.data.Records from an XML document.
12916 * @param {Object} o An Array of row objects which represents the dataset.
12917 * @return {Object} data A data block which is used by an Roo.data.Store object as
12918 * a cache of Roo.data.Records.
12920 readRecords : function(o){
12921 var sid = this.meta ? this.meta.id : null;
12922 var recordType = this.recordType, fields = recordType.prototype.fields;
12925 for(var i = 0; i < root.length; i++){
12928 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12929 for(var j = 0, jlen = fields.length; j < jlen; j++){
12930 var f = fields.items[j];
12931 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12932 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12934 values[f.name] = v;
12936 var record = new recordType(values, id);
12938 records[records.length] = record;
12942 totalRecords : records.length
12951 * @class Roo.bootstrap.ComboBox
12952 * @extends Roo.bootstrap.TriggerField
12953 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12954 * @cfg {Boolean} append (true|false) default false
12955 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12956 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12957 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12958 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12959 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12960 * @cfg {Boolean} animate default true
12961 * @cfg {Boolean} emptyResultText only for touch device
12962 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12963 * @cfg {String} emptyTitle default ''
12965 * Create a new ComboBox.
12966 * @param {Object} config Configuration options
12968 Roo.bootstrap.ComboBox = function(config){
12969 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12973 * Fires when the dropdown list is expanded
12974 * @param {Roo.bootstrap.ComboBox} combo This combo box
12979 * Fires when the dropdown list is collapsed
12980 * @param {Roo.bootstrap.ComboBox} combo This combo box
12984 * @event beforeselect
12985 * Fires before a list item is selected. Return false to cancel the selection.
12986 * @param {Roo.bootstrap.ComboBox} combo This combo box
12987 * @param {Roo.data.Record} record The data record returned from the underlying store
12988 * @param {Number} index The index of the selected item in the dropdown list
12990 'beforeselect' : true,
12993 * Fires when a list item is selected
12994 * @param {Roo.bootstrap.ComboBox} combo This combo box
12995 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
12996 * @param {Number} index The index of the selected item in the dropdown list
13000 * @event beforequery
13001 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13002 * The event object passed has these properties:
13003 * @param {Roo.bootstrap.ComboBox} combo This combo box
13004 * @param {String} query The query
13005 * @param {Boolean} forceAll true to force "all" query
13006 * @param {Boolean} cancel true to cancel the query
13007 * @param {Object} e The query event object
13009 'beforequery': true,
13012 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13013 * @param {Roo.bootstrap.ComboBox} combo This combo box
13018 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13019 * @param {Roo.bootstrap.ComboBox} combo This combo box
13020 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13025 * Fires when the remove value from the combobox array
13026 * @param {Roo.bootstrap.ComboBox} combo This combo box
13030 * @event afterremove
13031 * Fires when the remove value from the combobox array
13032 * @param {Roo.bootstrap.ComboBox} combo This combo box
13034 'afterremove' : true,
13036 * @event specialfilter
13037 * Fires when specialfilter
13038 * @param {Roo.bootstrap.ComboBox} combo This combo box
13040 'specialfilter' : true,
13043 * Fires when tick the element
13044 * @param {Roo.bootstrap.ComboBox} combo This combo box
13048 * @event touchviewdisplay
13049 * Fires when touch view require special display (default is using displayField)
13050 * @param {Roo.bootstrap.ComboBox} combo This combo box
13051 * @param {Object} cfg set html .
13053 'touchviewdisplay' : true
13058 this.tickItems = [];
13060 this.selectedIndex = -1;
13061 if(this.mode == 'local'){
13062 if(config.queryDelay === undefined){
13063 this.queryDelay = 10;
13065 if(config.minChars === undefined){
13071 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13074 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13075 * rendering into an Roo.Editor, defaults to false)
13078 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13079 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13082 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13085 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13086 * the dropdown list (defaults to undefined, with no header element)
13090 * @cfg {String/Roo.Template} tpl The template to use to render the output
13094 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13096 listWidth: undefined,
13098 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13099 * mode = 'remote' or 'text' if mode = 'local')
13101 displayField: undefined,
13104 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13105 * mode = 'remote' or 'value' if mode = 'local').
13106 * Note: use of a valueField requires the user make a selection
13107 * in order for a value to be mapped.
13109 valueField: undefined,
13111 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13116 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13117 * field's data value (defaults to the underlying DOM element's name)
13119 hiddenName: undefined,
13121 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13125 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13127 selectedClass: 'active',
13130 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13134 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13135 * anchor positions (defaults to 'tl-bl')
13137 listAlign: 'tl-bl?',
13139 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13143 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13144 * query specified by the allQuery config option (defaults to 'query')
13146 triggerAction: 'query',
13148 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13149 * (defaults to 4, does not apply if editable = false)
13153 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13154 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13158 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13159 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13163 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13164 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13168 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13169 * when editable = true (defaults to false)
13171 selectOnFocus:false,
13173 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13175 queryParam: 'query',
13177 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13178 * when mode = 'remote' (defaults to 'Loading...')
13180 loadingText: 'Loading...',
13182 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13186 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13190 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13191 * traditional select (defaults to true)
13195 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13199 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13203 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13204 * listWidth has a higher value)
13208 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13209 * allow the user to set arbitrary text into the field (defaults to false)
13211 forceSelection:false,
13213 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13214 * if typeAhead = true (defaults to 250)
13216 typeAheadDelay : 250,
13218 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13219 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13221 valueNotFoundText : undefined,
13223 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13225 blockFocus : false,
13228 * @cfg {Boolean} disableClear Disable showing of clear button.
13230 disableClear : false,
13232 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13234 alwaysQuery : false,
13237 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13242 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13244 invalidClass : "has-warning",
13247 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13249 validClass : "has-success",
13252 * @cfg {Boolean} specialFilter (true|false) special filter default false
13254 specialFilter : false,
13257 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13259 mobileTouchView : true,
13262 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13264 useNativeIOS : false,
13267 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13269 mobile_restrict_height : false,
13271 ios_options : false,
13283 btnPosition : 'right',
13284 triggerList : true,
13285 showToggleBtn : true,
13287 emptyResultText: 'Empty',
13288 triggerText : 'Select',
13291 // element that contains real text value.. (when hidden is used..)
13293 getAutoCreate : function()
13298 * Render classic select for iso
13301 if(Roo.isIOS && this.useNativeIOS){
13302 cfg = this.getAutoCreateNativeIOS();
13310 if(Roo.isTouch && this.mobileTouchView){
13311 cfg = this.getAutoCreateTouchView();
13318 if(!this.tickable){
13319 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13324 * ComboBox with tickable selections
13327 var align = this.labelAlign || this.parentLabelAlign();
13330 cls : 'form-group roo-combobox-tickable' //input-group
13333 var btn_text_select = '';
13334 var btn_text_done = '';
13335 var btn_text_cancel = '';
13337 if (this.btn_text_show) {
13338 btn_text_select = 'Select';
13339 btn_text_done = 'Done';
13340 btn_text_cancel = 'Cancel';
13345 cls : 'tickable-buttons',
13350 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13351 //html : this.triggerText
13352 html: btn_text_select
13358 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13360 html: btn_text_done
13366 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13368 html: btn_text_cancel
13374 buttons.cn.unshift({
13376 cls: 'roo-select2-search-field-input'
13382 Roo.each(buttons.cn, function(c){
13384 c.cls += ' btn-' + _this.size;
13387 if (_this.disabled) {
13394 style : 'display: contents',
13399 cls: 'form-hidden-field'
13403 cls: 'roo-select2-choices',
13407 cls: 'roo-select2-search-field',
13418 cls: 'roo-select2-container input-group roo-select2-container-multi',
13424 // cls: 'typeahead typeahead-long dropdown-menu',
13425 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13430 if(this.hasFeedback && !this.allowBlank){
13434 cls: 'glyphicon form-control-feedback'
13437 combobox.cn.push(feedback);
13442 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13443 tooltip : 'This field is required'
13445 if (Roo.bootstrap.version == 4) {
13448 style : 'display:none'
13451 if (align ==='left' && this.fieldLabel.length) {
13453 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13460 cls : 'control-label col-form-label',
13461 html : this.fieldLabel
13473 var labelCfg = cfg.cn[1];
13474 var contentCfg = cfg.cn[2];
13477 if(this.indicatorpos == 'right'){
13483 cls : 'control-label col-form-label',
13487 html : this.fieldLabel
13503 labelCfg = cfg.cn[0];
13504 contentCfg = cfg.cn[1];
13508 if(this.labelWidth > 12){
13509 labelCfg.style = "width: " + this.labelWidth + 'px';
13512 if(this.labelWidth < 13 && this.labelmd == 0){
13513 this.labelmd = this.labelWidth;
13516 if(this.labellg > 0){
13517 labelCfg.cls += ' col-lg-' + this.labellg;
13518 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13521 if(this.labelmd > 0){
13522 labelCfg.cls += ' col-md-' + this.labelmd;
13523 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13526 if(this.labelsm > 0){
13527 labelCfg.cls += ' col-sm-' + this.labelsm;
13528 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13531 if(this.labelxs > 0){
13532 labelCfg.cls += ' col-xs-' + this.labelxs;
13533 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13537 } else if ( this.fieldLabel.length) {
13538 // Roo.log(" label");
13543 //cls : 'input-group-addon',
13544 html : this.fieldLabel
13549 if(this.indicatorpos == 'right'){
13553 //cls : 'input-group-addon',
13554 html : this.fieldLabel
13564 // Roo.log(" no label && no align");
13571 ['xs','sm','md','lg'].map(function(size){
13572 if (settings[size]) {
13573 cfg.cls += ' col-' + size + '-' + settings[size];
13581 _initEventsCalled : false,
13584 initEvents: function()
13586 if (this._initEventsCalled) { // as we call render... prevent looping...
13589 this._initEventsCalled = true;
13592 throw "can not find store for combo";
13595 this.indicator = this.indicatorEl();
13597 this.store = Roo.factory(this.store, Roo.data);
13598 this.store.parent = this;
13600 // if we are building from html. then this element is so complex, that we can not really
13601 // use the rendered HTML.
13602 // so we have to trash and replace the previous code.
13603 if (Roo.XComponent.build_from_html) {
13604 // remove this element....
13605 var e = this.el.dom, k=0;
13606 while (e ) { e = e.previousSibling; ++k;}
13611 this.rendered = false;
13613 this.render(this.parent().getChildContainer(true), k);
13616 if(Roo.isIOS && this.useNativeIOS){
13617 this.initIOSView();
13625 if(Roo.isTouch && this.mobileTouchView){
13626 this.initTouchView();
13631 this.initTickableEvents();
13635 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13637 if(this.hiddenName){
13639 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13641 this.hiddenField.dom.value =
13642 this.hiddenValue !== undefined ? this.hiddenValue :
13643 this.value !== undefined ? this.value : '';
13645 // prevent input submission
13646 this.el.dom.removeAttribute('name');
13647 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13652 // this.el.dom.setAttribute('autocomplete', 'off');
13655 var cls = 'x-combo-list';
13657 //this.list = new Roo.Layer({
13658 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13664 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13665 _this.list.setWidth(lw);
13668 this.list.on('mouseover', this.onViewOver, this);
13669 this.list.on('mousemove', this.onViewMove, this);
13670 this.list.on('scroll', this.onViewScroll, this);
13673 this.list.swallowEvent('mousewheel');
13674 this.assetHeight = 0;
13677 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13678 this.assetHeight += this.header.getHeight();
13681 this.innerList = this.list.createChild({cls:cls+'-inner'});
13682 this.innerList.on('mouseover', this.onViewOver, this);
13683 this.innerList.on('mousemove', this.onViewMove, this);
13684 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13686 if(this.allowBlank && !this.pageSize && !this.disableClear){
13687 this.footer = this.list.createChild({cls:cls+'-ft'});
13688 this.pageTb = new Roo.Toolbar(this.footer);
13692 this.footer = this.list.createChild({cls:cls+'-ft'});
13693 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13694 {pageSize: this.pageSize});
13698 if (this.pageTb && this.allowBlank && !this.disableClear) {
13700 this.pageTb.add(new Roo.Toolbar.Fill(), {
13701 cls: 'x-btn-icon x-btn-clear',
13703 handler: function()
13706 _this.clearValue();
13707 _this.onSelect(false, -1);
13712 this.assetHeight += this.footer.getHeight();
13717 this.tpl = Roo.bootstrap.version == 4 ?
13718 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13719 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13722 this.view = new Roo.View(this.list, this.tpl, {
13723 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13725 //this.view.wrapEl.setDisplayed(false);
13726 this.view.on('click', this.onViewClick, this);
13729 this.store.on('beforeload', this.onBeforeLoad, this);
13730 this.store.on('load', this.onLoad, this);
13731 this.store.on('loadexception', this.onLoadException, this);
13733 if(this.resizable){
13734 this.resizer = new Roo.Resizable(this.list, {
13735 pinned:true, handles:'se'
13737 this.resizer.on('resize', function(r, w, h){
13738 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13739 this.listWidth = w;
13740 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13741 this.restrictHeight();
13743 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13746 if(!this.editable){
13747 this.editable = true;
13748 this.setEditable(false);
13753 if (typeof(this.events.add.listeners) != 'undefined') {
13755 this.addicon = this.wrap.createChild(
13756 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13758 this.addicon.on('click', function(e) {
13759 this.fireEvent('add', this);
13762 if (typeof(this.events.edit.listeners) != 'undefined') {
13764 this.editicon = this.wrap.createChild(
13765 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13766 if (this.addicon) {
13767 this.editicon.setStyle('margin-left', '40px');
13769 this.editicon.on('click', function(e) {
13771 // we fire even if inothing is selected..
13772 this.fireEvent('edit', this, this.lastData );
13778 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13779 "up" : function(e){
13780 this.inKeyMode = true;
13784 "down" : function(e){
13785 if(!this.isExpanded()){
13786 this.onTriggerClick();
13788 this.inKeyMode = true;
13793 "enter" : function(e){
13794 // this.onViewClick();
13798 if(this.fireEvent("specialkey", this, e)){
13799 this.onViewClick(false);
13805 "esc" : function(e){
13809 "tab" : function(e){
13812 if(this.fireEvent("specialkey", this, e)){
13813 this.onViewClick(false);
13821 doRelay : function(foo, bar, hname){
13822 if(hname == 'down' || this.scope.isExpanded()){
13823 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13832 this.queryDelay = Math.max(this.queryDelay || 10,
13833 this.mode == 'local' ? 10 : 250);
13836 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13838 if(this.typeAhead){
13839 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13841 if(this.editable !== false){
13842 this.inputEl().on("keyup", this.onKeyUp, this);
13844 if(this.forceSelection){
13845 this.inputEl().on('blur', this.doForce, this);
13849 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13850 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13854 initTickableEvents: function()
13858 if(this.hiddenName){
13860 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13862 this.hiddenField.dom.value =
13863 this.hiddenValue !== undefined ? this.hiddenValue :
13864 this.value !== undefined ? this.value : '';
13866 // prevent input submission
13867 this.el.dom.removeAttribute('name');
13868 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13873 // this.list = this.el.select('ul.dropdown-menu',true).first();
13875 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13876 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13877 if(this.triggerList){
13878 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13881 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13882 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13884 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13885 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13887 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13888 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13890 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13891 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13892 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13895 this.cancelBtn.hide();
13900 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13901 _this.list.setWidth(lw);
13904 this.list.on('mouseover', this.onViewOver, this);
13905 this.list.on('mousemove', this.onViewMove, this);
13907 this.list.on('scroll', this.onViewScroll, this);
13910 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13911 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13914 this.view = new Roo.View(this.list, this.tpl, {
13919 selectedClass: this.selectedClass
13922 //this.view.wrapEl.setDisplayed(false);
13923 this.view.on('click', this.onViewClick, this);
13927 this.store.on('beforeload', this.onBeforeLoad, this);
13928 this.store.on('load', this.onLoad, this);
13929 this.store.on('loadexception', this.onLoadException, this);
13932 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13933 "up" : function(e){
13934 this.inKeyMode = true;
13938 "down" : function(e){
13939 this.inKeyMode = true;
13943 "enter" : function(e){
13944 if(this.fireEvent("specialkey", this, e)){
13945 this.onViewClick(false);
13951 "esc" : function(e){
13952 this.onTickableFooterButtonClick(e, false, false);
13955 "tab" : function(e){
13956 this.fireEvent("specialkey", this, e);
13958 this.onTickableFooterButtonClick(e, false, false);
13965 doRelay : function(e, fn, key){
13966 if(this.scope.isExpanded()){
13967 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13976 this.queryDelay = Math.max(this.queryDelay || 10,
13977 this.mode == 'local' ? 10 : 250);
13980 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13982 if(this.typeAhead){
13983 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13986 if(this.editable !== false){
13987 this.tickableInputEl().on("keyup", this.onKeyUp, this);
13990 this.indicator = this.indicatorEl();
13992 if(this.indicator){
13993 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
13994 this.indicator.hide();
13999 onDestroy : function(){
14001 this.view.setStore(null);
14002 this.view.el.removeAllListeners();
14003 this.view.el.remove();
14004 this.view.purgeListeners();
14007 this.list.dom.innerHTML = '';
14011 this.store.un('beforeload', this.onBeforeLoad, this);
14012 this.store.un('load', this.onLoad, this);
14013 this.store.un('loadexception', this.onLoadException, this);
14015 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14019 fireKey : function(e){
14020 if(e.isNavKeyPress() && !this.list.isVisible()){
14021 this.fireEvent("specialkey", this, e);
14026 onResize: function(w, h){
14027 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14029 // if(typeof w != 'number'){
14030 // // we do not handle it!?!?
14033 // var tw = this.trigger.getWidth();
14034 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14035 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14037 // this.inputEl().setWidth( this.adjustWidth('input', x));
14039 // //this.trigger.setStyle('left', x+'px');
14041 // if(this.list && this.listWidth === undefined){
14042 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14043 // this.list.setWidth(lw);
14044 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14052 * Allow or prevent the user from directly editing the field text. If false is passed,
14053 * the user will only be able to select from the items defined in the dropdown list. This method
14054 * is the runtime equivalent of setting the 'editable' config option at config time.
14055 * @param {Boolean} value True to allow the user to directly edit the field text
14057 setEditable : function(value){
14058 if(value == this.editable){
14061 this.editable = value;
14063 this.inputEl().dom.setAttribute('readOnly', true);
14064 this.inputEl().on('mousedown', this.onTriggerClick, this);
14065 this.inputEl().addClass('x-combo-noedit');
14067 this.inputEl().dom.setAttribute('readOnly', false);
14068 this.inputEl().un('mousedown', this.onTriggerClick, this);
14069 this.inputEl().removeClass('x-combo-noedit');
14075 onBeforeLoad : function(combo,opts){
14076 if(!this.hasFocus){
14080 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14082 this.restrictHeight();
14083 this.selectedIndex = -1;
14087 onLoad : function(){
14089 this.hasQuery = false;
14091 if(!this.hasFocus){
14095 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14096 this.loading.hide();
14099 if(this.store.getCount() > 0){
14102 this.restrictHeight();
14103 if(this.lastQuery == this.allQuery){
14104 if(this.editable && !this.tickable){
14105 this.inputEl().dom.select();
14109 !this.selectByValue(this.value, true) &&
14112 !this.store.lastOptions ||
14113 typeof(this.store.lastOptions.add) == 'undefined' ||
14114 this.store.lastOptions.add != true
14117 this.select(0, true);
14120 if(this.autoFocus){
14123 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14124 this.taTask.delay(this.typeAheadDelay);
14128 this.onEmptyResults();
14134 onLoadException : function()
14136 this.hasQuery = false;
14138 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14139 this.loading.hide();
14142 if(this.tickable && this.editable){
14147 // only causes errors at present
14148 //Roo.log(this.store.reader.jsonData);
14149 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14151 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14157 onTypeAhead : function(){
14158 if(this.store.getCount() > 0){
14159 var r = this.store.getAt(0);
14160 var newValue = r.data[this.displayField];
14161 var len = newValue.length;
14162 var selStart = this.getRawValue().length;
14164 if(selStart != len){
14165 this.setRawValue(newValue);
14166 this.selectText(selStart, newValue.length);
14172 onSelect : function(record, index){
14174 if(this.fireEvent('beforeselect', this, record, index) !== false){
14176 this.setFromData(index > -1 ? record.data : false);
14179 this.fireEvent('select', this, record, index);
14184 * Returns the currently selected field value or empty string if no value is set.
14185 * @return {String} value The selected value
14187 getValue : function()
14189 if(Roo.isIOS && this.useNativeIOS){
14190 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14194 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14197 if(this.valueField){
14198 return typeof this.value != 'undefined' ? this.value : '';
14200 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14204 getRawValue : function()
14206 if(Roo.isIOS && this.useNativeIOS){
14207 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14210 var v = this.inputEl().getValue();
14216 * Clears any text/value currently set in the field
14218 clearValue : function(){
14220 if(this.hiddenField){
14221 this.hiddenField.dom.value = '';
14224 this.setRawValue('');
14225 this.lastSelectionText = '';
14226 this.lastData = false;
14228 var close = this.closeTriggerEl();
14239 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14240 * will be displayed in the field. If the value does not match the data value of an existing item,
14241 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14242 * Otherwise the field will be blank (although the value will still be set).
14243 * @param {String} value The value to match
14245 setValue : function(v)
14247 if(Roo.isIOS && this.useNativeIOS){
14248 this.setIOSValue(v);
14258 if(this.valueField){
14259 var r = this.findRecord(this.valueField, v);
14261 text = r.data[this.displayField];
14262 }else if(this.valueNotFoundText !== undefined){
14263 text = this.valueNotFoundText;
14266 this.lastSelectionText = text;
14267 if(this.hiddenField){
14268 this.hiddenField.dom.value = v;
14270 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14273 var close = this.closeTriggerEl();
14276 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14282 * @property {Object} the last set data for the element
14287 * Sets the value of the field based on a object which is related to the record format for the store.
14288 * @param {Object} value the value to set as. or false on reset?
14290 setFromData : function(o){
14297 var dv = ''; // display value
14298 var vv = ''; // value value..
14300 if (this.displayField) {
14301 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14303 // this is an error condition!!!
14304 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14307 if(this.valueField){
14308 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14311 var close = this.closeTriggerEl();
14314 if(dv.length || vv * 1 > 0){
14316 this.blockFocus=true;
14322 if(this.hiddenField){
14323 this.hiddenField.dom.value = vv;
14325 this.lastSelectionText = dv;
14326 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14330 // no hidden field.. - we store the value in 'value', but still display
14331 // display field!!!!
14332 this.lastSelectionText = dv;
14333 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14340 reset : function(){
14341 // overridden so that last data is reset..
14348 this.setValue(this.originalValue);
14349 //this.clearInvalid();
14350 this.lastData = false;
14352 this.view.clearSelections();
14358 findRecord : function(prop, value){
14360 if(this.store.getCount() > 0){
14361 this.store.each(function(r){
14362 if(r.data[prop] == value){
14372 getName: function()
14374 // returns hidden if it's set..
14375 if (!this.rendered) {return ''};
14376 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14380 onViewMove : function(e, t){
14381 this.inKeyMode = false;
14385 onViewOver : function(e, t){
14386 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14389 var item = this.view.findItemFromChild(t);
14392 var index = this.view.indexOf(item);
14393 this.select(index, false);
14398 onViewClick : function(view, doFocus, el, e)
14400 var index = this.view.getSelectedIndexes()[0];
14402 var r = this.store.getAt(index);
14406 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14413 Roo.each(this.tickItems, function(v,k){
14415 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14417 _this.tickItems.splice(k, 1);
14419 if(typeof(e) == 'undefined' && view == false){
14420 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14432 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14433 this.tickItems.push(r.data);
14436 if(typeof(e) == 'undefined' && view == false){
14437 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14444 this.onSelect(r, index);
14446 if(doFocus !== false && !this.blockFocus){
14447 this.inputEl().focus();
14452 restrictHeight : function(){
14453 //this.innerList.dom.style.height = '';
14454 //var inner = this.innerList.dom;
14455 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14456 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14457 //this.list.beginUpdate();
14458 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14459 this.list.alignTo(this.inputEl(), this.listAlign);
14460 this.list.alignTo(this.inputEl(), this.listAlign);
14461 //this.list.endUpdate();
14465 onEmptyResults : function(){
14467 if(this.tickable && this.editable){
14468 this.hasFocus = false;
14469 this.restrictHeight();
14477 * Returns true if the dropdown list is expanded, else false.
14479 isExpanded : function(){
14480 return this.list.isVisible();
14484 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14485 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14486 * @param {String} value The data value of the item to select
14487 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14488 * selected item if it is not currently in view (defaults to true)
14489 * @return {Boolean} True if the value matched an item in the list, else false
14491 selectByValue : function(v, scrollIntoView){
14492 if(v !== undefined && v !== null){
14493 var r = this.findRecord(this.valueField || this.displayField, v);
14495 this.select(this.store.indexOf(r), scrollIntoView);
14503 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14504 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14505 * @param {Number} index The zero-based index of the list item to select
14506 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14507 * selected item if it is not currently in view (defaults to true)
14509 select : function(index, scrollIntoView){
14510 this.selectedIndex = index;
14511 this.view.select(index);
14512 if(scrollIntoView !== false){
14513 var el = this.view.getNode(index);
14515 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14518 this.list.scrollChildIntoView(el, false);
14524 selectNext : function(){
14525 var ct = this.store.getCount();
14527 if(this.selectedIndex == -1){
14529 }else if(this.selectedIndex < ct-1){
14530 this.select(this.selectedIndex+1);
14536 selectPrev : function(){
14537 var ct = this.store.getCount();
14539 if(this.selectedIndex == -1){
14541 }else if(this.selectedIndex != 0){
14542 this.select(this.selectedIndex-1);
14548 onKeyUp : function(e){
14549 if(this.editable !== false && !e.isSpecialKey()){
14550 this.lastKey = e.getKey();
14551 this.dqTask.delay(this.queryDelay);
14556 validateBlur : function(){
14557 return !this.list || !this.list.isVisible();
14561 initQuery : function(){
14563 var v = this.getRawValue();
14565 if(this.tickable && this.editable){
14566 v = this.tickableInputEl().getValue();
14573 doForce : function(){
14574 if(this.inputEl().dom.value.length > 0){
14575 this.inputEl().dom.value =
14576 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14582 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14583 * query allowing the query action to be canceled if needed.
14584 * @param {String} query The SQL query to execute
14585 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14586 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14587 * saved in the current store (defaults to false)
14589 doQuery : function(q, forceAll){
14591 if(q === undefined || q === null){
14596 forceAll: forceAll,
14600 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14605 forceAll = qe.forceAll;
14606 if(forceAll === true || (q.length >= this.minChars)){
14608 this.hasQuery = true;
14610 if(this.lastQuery != q || this.alwaysQuery){
14611 this.lastQuery = q;
14612 if(this.mode == 'local'){
14613 this.selectedIndex = -1;
14615 this.store.clearFilter();
14618 if(this.specialFilter){
14619 this.fireEvent('specialfilter', this);
14624 this.store.filter(this.displayField, q);
14627 this.store.fireEvent("datachanged", this.store);
14634 this.store.baseParams[this.queryParam] = q;
14636 var options = {params : this.getParams(q)};
14639 options.add = true;
14640 options.params.start = this.page * this.pageSize;
14643 this.store.load(options);
14646 * this code will make the page width larger, at the beginning, the list not align correctly,
14647 * we should expand the list on onLoad
14648 * so command out it
14653 this.selectedIndex = -1;
14658 this.loadNext = false;
14662 getParams : function(q){
14664 //p[this.queryParam] = q;
14668 p.limit = this.pageSize;
14674 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14676 collapse : function(){
14677 if(!this.isExpanded()){
14683 this.hasFocus = false;
14687 this.cancelBtn.hide();
14688 this.trigger.show();
14691 this.tickableInputEl().dom.value = '';
14692 this.tickableInputEl().blur();
14697 Roo.get(document).un('mousedown', this.collapseIf, this);
14698 Roo.get(document).un('mousewheel', this.collapseIf, this);
14699 if (!this.editable) {
14700 Roo.get(document).un('keydown', this.listKeyPress, this);
14702 this.fireEvent('collapse', this);
14708 collapseIf : function(e){
14709 var in_combo = e.within(this.el);
14710 var in_list = e.within(this.list);
14711 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14713 if (in_combo || in_list || is_list) {
14714 //e.stopPropagation();
14719 this.onTickableFooterButtonClick(e, false, false);
14727 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14729 expand : function(){
14731 if(this.isExpanded() || !this.hasFocus){
14735 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14736 this.list.setWidth(lw);
14742 this.restrictHeight();
14746 this.tickItems = Roo.apply([], this.item);
14749 this.cancelBtn.show();
14750 this.trigger.hide();
14753 this.tickableInputEl().focus();
14758 Roo.get(document).on('mousedown', this.collapseIf, this);
14759 Roo.get(document).on('mousewheel', this.collapseIf, this);
14760 if (!this.editable) {
14761 Roo.get(document).on('keydown', this.listKeyPress, this);
14764 this.fireEvent('expand', this);
14768 // Implements the default empty TriggerField.onTriggerClick function
14769 onTriggerClick : function(e)
14771 Roo.log('trigger click');
14773 if(this.disabled || !this.triggerList){
14778 this.loadNext = false;
14780 if(this.isExpanded()){
14782 if (!this.blockFocus) {
14783 this.inputEl().focus();
14787 this.hasFocus = true;
14788 if(this.triggerAction == 'all') {
14789 this.doQuery(this.allQuery, true);
14791 this.doQuery(this.getRawValue());
14793 if (!this.blockFocus) {
14794 this.inputEl().focus();
14799 onTickableTriggerClick : function(e)
14806 this.loadNext = false;
14807 this.hasFocus = true;
14809 if(this.triggerAction == 'all') {
14810 this.doQuery(this.allQuery, true);
14812 this.doQuery(this.getRawValue());
14816 onSearchFieldClick : function(e)
14818 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14819 this.onTickableFooterButtonClick(e, false, false);
14823 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14828 this.loadNext = false;
14829 this.hasFocus = true;
14831 if(this.triggerAction == 'all') {
14832 this.doQuery(this.allQuery, true);
14834 this.doQuery(this.getRawValue());
14838 listKeyPress : function(e)
14840 //Roo.log('listkeypress');
14841 // scroll to first matching element based on key pres..
14842 if (e.isSpecialKey()) {
14845 var k = String.fromCharCode(e.getKey()).toUpperCase();
14848 var csel = this.view.getSelectedNodes();
14849 var cselitem = false;
14851 var ix = this.view.indexOf(csel[0]);
14852 cselitem = this.store.getAt(ix);
14853 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14859 this.store.each(function(v) {
14861 // start at existing selection.
14862 if (cselitem.id == v.id) {
14868 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14869 match = this.store.indexOf(v);
14875 if (match === false) {
14876 return true; // no more action?
14879 this.view.select(match);
14880 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14881 sn.scrollIntoView(sn.dom.parentNode, false);
14884 onViewScroll : function(e, t){
14886 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){
14890 this.hasQuery = true;
14892 this.loading = this.list.select('.loading', true).first();
14894 if(this.loading === null){
14895 this.list.createChild({
14897 cls: 'loading roo-select2-more-results roo-select2-active',
14898 html: 'Loading more results...'
14901 this.loading = this.list.select('.loading', true).first();
14903 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14905 this.loading.hide();
14908 this.loading.show();
14913 this.loadNext = true;
14915 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14920 addItem : function(o)
14922 var dv = ''; // display value
14924 if (this.displayField) {
14925 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14927 // this is an error condition!!!
14928 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14935 var choice = this.choices.createChild({
14937 cls: 'roo-select2-search-choice',
14946 cls: 'roo-select2-search-choice-close fa fa-times',
14951 }, this.searchField);
14953 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14955 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14963 this.inputEl().dom.value = '';
14968 onRemoveItem : function(e, _self, o)
14970 e.preventDefault();
14972 this.lastItem = Roo.apply([], this.item);
14974 var index = this.item.indexOf(o.data) * 1;
14977 Roo.log('not this item?!');
14981 this.item.splice(index, 1);
14986 this.fireEvent('remove', this, e);
14992 syncValue : function()
14994 if(!this.item.length){
15001 Roo.each(this.item, function(i){
15002 if(_this.valueField){
15003 value.push(i[_this.valueField]);
15010 this.value = value.join(',');
15012 if(this.hiddenField){
15013 this.hiddenField.dom.value = this.value;
15016 this.store.fireEvent("datachanged", this.store);
15021 clearItem : function()
15023 if(!this.multiple){
15029 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15037 if(this.tickable && !Roo.isTouch){
15038 this.view.refresh();
15042 inputEl: function ()
15044 if(Roo.isIOS && this.useNativeIOS){
15045 return this.el.select('select.roo-ios-select', true).first();
15048 if(Roo.isTouch && this.mobileTouchView){
15049 return this.el.select('input.form-control',true).first();
15053 return this.searchField;
15056 return this.el.select('input.form-control',true).first();
15059 onTickableFooterButtonClick : function(e, btn, el)
15061 e.preventDefault();
15063 this.lastItem = Roo.apply([], this.item);
15065 if(btn && btn.name == 'cancel'){
15066 this.tickItems = Roo.apply([], this.item);
15075 Roo.each(this.tickItems, function(o){
15083 validate : function()
15085 if(this.getVisibilityEl().hasClass('hidden')){
15089 var v = this.getRawValue();
15092 v = this.getValue();
15095 if(this.disabled || this.allowBlank || v.length){
15100 this.markInvalid();
15104 tickableInputEl : function()
15106 if(!this.tickable || !this.editable){
15107 return this.inputEl();
15110 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15114 getAutoCreateTouchView : function()
15119 cls: 'form-group' //input-group
15125 type : this.inputType,
15126 cls : 'form-control x-combo-noedit',
15127 autocomplete: 'new-password',
15128 placeholder : this.placeholder || '',
15133 input.name = this.name;
15137 input.cls += ' input-' + this.size;
15140 if (this.disabled) {
15141 input.disabled = true;
15152 inputblock.cls += ' input-group';
15154 inputblock.cn.unshift({
15156 cls : 'input-group-addon input-group-prepend input-group-text',
15161 if(this.removable && !this.multiple){
15162 inputblock.cls += ' roo-removable';
15164 inputblock.cn.push({
15167 cls : 'roo-combo-removable-btn close'
15171 if(this.hasFeedback && !this.allowBlank){
15173 inputblock.cls += ' has-feedback';
15175 inputblock.cn.push({
15177 cls: 'glyphicon form-control-feedback'
15184 inputblock.cls += (this.before) ? '' : ' input-group';
15186 inputblock.cn.push({
15188 cls : 'input-group-addon input-group-append input-group-text',
15194 var ibwrap = inputblock;
15199 cls: 'roo-select2-choices',
15203 cls: 'roo-select2-search-field',
15216 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15221 cls: 'form-hidden-field'
15227 if(!this.multiple && this.showToggleBtn){
15234 if (this.caret != false) {
15237 cls: 'fa fa-' + this.caret
15244 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15249 cls: 'combobox-clear',
15263 combobox.cls += ' roo-select2-container-multi';
15266 var align = this.labelAlign || this.parentLabelAlign();
15268 if (align ==='left' && this.fieldLabel.length) {
15273 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15274 tooltip : 'This field is required'
15278 cls : 'control-label col-form-label',
15279 html : this.fieldLabel
15290 var labelCfg = cfg.cn[1];
15291 var contentCfg = cfg.cn[2];
15294 if(this.indicatorpos == 'right'){
15299 cls : 'control-label col-form-label',
15303 html : this.fieldLabel
15307 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15308 tooltip : 'This field is required'
15321 labelCfg = cfg.cn[0];
15322 contentCfg = cfg.cn[1];
15327 if(this.labelWidth > 12){
15328 labelCfg.style = "width: " + this.labelWidth + 'px';
15331 if(this.labelWidth < 13 && this.labelmd == 0){
15332 this.labelmd = this.labelWidth;
15335 if(this.labellg > 0){
15336 labelCfg.cls += ' col-lg-' + this.labellg;
15337 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15340 if(this.labelmd > 0){
15341 labelCfg.cls += ' col-md-' + this.labelmd;
15342 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15345 if(this.labelsm > 0){
15346 labelCfg.cls += ' col-sm-' + this.labelsm;
15347 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15350 if(this.labelxs > 0){
15351 labelCfg.cls += ' col-xs-' + this.labelxs;
15352 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15356 } else if ( this.fieldLabel.length) {
15360 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15361 tooltip : 'This field is required'
15365 cls : 'control-label',
15366 html : this.fieldLabel
15377 if(this.indicatorpos == 'right'){
15381 cls : 'control-label',
15382 html : this.fieldLabel,
15386 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15387 tooltip : 'This field is required'
15404 var settings = this;
15406 ['xs','sm','md','lg'].map(function(size){
15407 if (settings[size]) {
15408 cfg.cls += ' col-' + size + '-' + settings[size];
15415 initTouchView : function()
15417 this.renderTouchView();
15419 this.touchViewEl.on('scroll', function(){
15420 this.el.dom.scrollTop = 0;
15423 this.originalValue = this.getValue();
15425 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15427 this.inputEl().on("click", this.showTouchView, this);
15428 if (this.triggerEl) {
15429 this.triggerEl.on("click", this.showTouchView, this);
15433 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15434 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15436 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15438 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15439 this.store.on('load', this.onTouchViewLoad, this);
15440 this.store.on('loadexception', this.onTouchViewLoadException, this);
15442 if(this.hiddenName){
15444 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15446 this.hiddenField.dom.value =
15447 this.hiddenValue !== undefined ? this.hiddenValue :
15448 this.value !== undefined ? this.value : '';
15450 this.el.dom.removeAttribute('name');
15451 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15455 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15456 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15459 if(this.removable && !this.multiple){
15460 var close = this.closeTriggerEl();
15462 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15463 close.on('click', this.removeBtnClick, this, close);
15467 * fix the bug in Safari iOS8
15469 this.inputEl().on("focus", function(e){
15470 document.activeElement.blur();
15473 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15480 renderTouchView : function()
15482 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15483 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15485 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15486 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15488 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15489 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15490 this.touchViewBodyEl.setStyle('overflow', 'auto');
15492 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15493 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15495 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15496 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15500 showTouchView : function()
15506 this.touchViewHeaderEl.hide();
15508 if(this.modalTitle.length){
15509 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15510 this.touchViewHeaderEl.show();
15513 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15514 this.touchViewEl.show();
15516 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15518 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15519 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15521 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15523 if(this.modalTitle.length){
15524 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15527 this.touchViewBodyEl.setHeight(bodyHeight);
15531 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15533 this.touchViewEl.addClass('in');
15536 if(this._touchViewMask){
15537 Roo.get(document.body).addClass("x-body-masked");
15538 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15539 this._touchViewMask.setStyle('z-index', 10000);
15540 this._touchViewMask.addClass('show');
15543 this.doTouchViewQuery();
15547 hideTouchView : function()
15549 this.touchViewEl.removeClass('in');
15553 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15555 this.touchViewEl.setStyle('display', 'none');
15558 if(this._touchViewMask){
15559 this._touchViewMask.removeClass('show');
15560 Roo.get(document.body).removeClass("x-body-masked");
15564 setTouchViewValue : function()
15571 Roo.each(this.tickItems, function(o){
15576 this.hideTouchView();
15579 doTouchViewQuery : function()
15588 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15592 if(!this.alwaysQuery || this.mode == 'local'){
15593 this.onTouchViewLoad();
15600 onTouchViewBeforeLoad : function(combo,opts)
15606 onTouchViewLoad : function()
15608 if(this.store.getCount() < 1){
15609 this.onTouchViewEmptyResults();
15613 this.clearTouchView();
15615 var rawValue = this.getRawValue();
15617 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15619 this.tickItems = [];
15621 this.store.data.each(function(d, rowIndex){
15622 var row = this.touchViewListGroup.createChild(template);
15624 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15625 row.addClass(d.data.cls);
15628 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15631 html : d.data[this.displayField]
15634 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15635 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15638 row.removeClass('selected');
15639 if(!this.multiple && this.valueField &&
15640 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15643 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15644 row.addClass('selected');
15647 if(this.multiple && this.valueField &&
15648 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15652 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15653 this.tickItems.push(d.data);
15656 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15660 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15662 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15664 if(this.modalTitle.length){
15665 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15668 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15670 if(this.mobile_restrict_height && listHeight < bodyHeight){
15671 this.touchViewBodyEl.setHeight(listHeight);
15676 if(firstChecked && listHeight > bodyHeight){
15677 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15682 onTouchViewLoadException : function()
15684 this.hideTouchView();
15687 onTouchViewEmptyResults : function()
15689 this.clearTouchView();
15691 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15693 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15697 clearTouchView : function()
15699 this.touchViewListGroup.dom.innerHTML = '';
15702 onTouchViewClick : function(e, el, o)
15704 e.preventDefault();
15707 var rowIndex = o.rowIndex;
15709 var r = this.store.getAt(rowIndex);
15711 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15713 if(!this.multiple){
15714 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15715 c.dom.removeAttribute('checked');
15718 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15720 this.setFromData(r.data);
15722 var close = this.closeTriggerEl();
15728 this.hideTouchView();
15730 this.fireEvent('select', this, r, rowIndex);
15735 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15736 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15737 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15741 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15742 this.addItem(r.data);
15743 this.tickItems.push(r.data);
15747 getAutoCreateNativeIOS : function()
15750 cls: 'form-group' //input-group,
15755 cls : 'roo-ios-select'
15759 combobox.name = this.name;
15762 if (this.disabled) {
15763 combobox.disabled = true;
15766 var settings = this;
15768 ['xs','sm','md','lg'].map(function(size){
15769 if (settings[size]) {
15770 cfg.cls += ' col-' + size + '-' + settings[size];
15780 initIOSView : function()
15782 this.store.on('load', this.onIOSViewLoad, this);
15787 onIOSViewLoad : function()
15789 if(this.store.getCount() < 1){
15793 this.clearIOSView();
15795 if(this.allowBlank) {
15797 var default_text = '-- SELECT --';
15799 if(this.placeholder.length){
15800 default_text = this.placeholder;
15803 if(this.emptyTitle.length){
15804 default_text += ' - ' + this.emptyTitle + ' -';
15807 var opt = this.inputEl().createChild({
15810 html : default_text
15814 o[this.valueField] = 0;
15815 o[this.displayField] = default_text;
15817 this.ios_options.push({
15824 this.store.data.each(function(d, rowIndex){
15828 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15829 html = d.data[this.displayField];
15834 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15835 value = d.data[this.valueField];
15844 if(this.value == d.data[this.valueField]){
15845 option['selected'] = true;
15848 var opt = this.inputEl().createChild(option);
15850 this.ios_options.push({
15857 this.inputEl().on('change', function(){
15858 this.fireEvent('select', this);
15863 clearIOSView: function()
15865 this.inputEl().dom.innerHTML = '';
15867 this.ios_options = [];
15870 setIOSValue: function(v)
15874 if(!this.ios_options){
15878 Roo.each(this.ios_options, function(opts){
15880 opts.el.dom.removeAttribute('selected');
15882 if(opts.data[this.valueField] != v){
15886 opts.el.dom.setAttribute('selected', true);
15892 * @cfg {Boolean} grow
15896 * @cfg {Number} growMin
15900 * @cfg {Number} growMax
15909 Roo.apply(Roo.bootstrap.ComboBox, {
15913 cls: 'modal-header',
15935 cls: 'list-group-item',
15939 cls: 'roo-combobox-list-group-item-value'
15943 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15957 listItemCheckbox : {
15959 cls: 'list-group-item',
15963 cls: 'roo-combobox-list-group-item-value'
15967 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
15983 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
15988 cls: 'modal-footer',
15996 cls: 'col-xs-6 text-left',
15999 cls: 'btn btn-danger roo-touch-view-cancel',
16005 cls: 'col-xs-6 text-right',
16008 cls: 'btn btn-success roo-touch-view-ok',
16019 Roo.apply(Roo.bootstrap.ComboBox, {
16021 touchViewTemplate : {
16023 cls: 'modal fade roo-combobox-touch-view',
16027 cls: 'modal-dialog',
16028 style : 'position:fixed', // we have to fix position....
16032 cls: 'modal-content',
16034 Roo.bootstrap.ComboBox.header,
16035 Roo.bootstrap.ComboBox.body,
16036 Roo.bootstrap.ComboBox.footer
16045 * Ext JS Library 1.1.1
16046 * Copyright(c) 2006-2007, Ext JS, LLC.
16048 * Originally Released Under LGPL - original licence link has changed is not relivant.
16051 * <script type="text/javascript">
16056 * @extends Roo.util.Observable
16057 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16058 * This class also supports single and multi selection modes. <br>
16059 * Create a data model bound view:
16061 var store = new Roo.data.Store(...);
16063 var view = new Roo.View({
16065 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16067 singleSelect: true,
16068 selectedClass: "ydataview-selected",
16072 // listen for node click?
16073 view.on("click", function(vw, index, node, e){
16074 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16078 dataModel.load("foobar.xml");
16080 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16082 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16083 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16085 * Note: old style constructor is still suported (container, template, config)
16088 * Create a new View
16089 * @param {Object} config The config object
16092 Roo.View = function(config, depreciated_tpl, depreciated_config){
16094 this.parent = false;
16096 if (typeof(depreciated_tpl) == 'undefined') {
16097 // new way.. - universal constructor.
16098 Roo.apply(this, config);
16099 this.el = Roo.get(this.el);
16102 this.el = Roo.get(config);
16103 this.tpl = depreciated_tpl;
16104 Roo.apply(this, depreciated_config);
16106 this.wrapEl = this.el.wrap().wrap();
16107 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16110 if(typeof(this.tpl) == "string"){
16111 this.tpl = new Roo.Template(this.tpl);
16113 // support xtype ctors..
16114 this.tpl = new Roo.factory(this.tpl, Roo);
16118 this.tpl.compile();
16123 * @event beforeclick
16124 * Fires before a click is processed. Returns false to cancel the default action.
16125 * @param {Roo.View} this
16126 * @param {Number} index The index of the target node
16127 * @param {HTMLElement} node The target node
16128 * @param {Roo.EventObject} e The raw event object
16130 "beforeclick" : true,
16133 * Fires when a template node is clicked.
16134 * @param {Roo.View} this
16135 * @param {Number} index The index of the target node
16136 * @param {HTMLElement} node The target node
16137 * @param {Roo.EventObject} e The raw event object
16142 * Fires when a template node is double clicked.
16143 * @param {Roo.View} this
16144 * @param {Number} index The index of the target node
16145 * @param {HTMLElement} node The target node
16146 * @param {Roo.EventObject} e The raw event object
16150 * @event contextmenu
16151 * Fires when a template node is right clicked.
16152 * @param {Roo.View} this
16153 * @param {Number} index The index of the target node
16154 * @param {HTMLElement} node The target node
16155 * @param {Roo.EventObject} e The raw event object
16157 "contextmenu" : true,
16159 * @event selectionchange
16160 * Fires when the selected nodes change.
16161 * @param {Roo.View} this
16162 * @param {Array} selections Array of the selected nodes
16164 "selectionchange" : true,
16167 * @event beforeselect
16168 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16169 * @param {Roo.View} this
16170 * @param {HTMLElement} node The node to be selected
16171 * @param {Array} selections Array of currently selected nodes
16173 "beforeselect" : true,
16175 * @event preparedata
16176 * Fires on every row to render, to allow you to change the data.
16177 * @param {Roo.View} this
16178 * @param {Object} data to be rendered (change this)
16180 "preparedata" : true
16188 "click": this.onClick,
16189 "dblclick": this.onDblClick,
16190 "contextmenu": this.onContextMenu,
16194 this.selections = [];
16196 this.cmp = new Roo.CompositeElementLite([]);
16198 this.store = Roo.factory(this.store, Roo.data);
16199 this.setStore(this.store, true);
16202 if ( this.footer && this.footer.xtype) {
16204 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16206 this.footer.dataSource = this.store;
16207 this.footer.container = fctr;
16208 this.footer = Roo.factory(this.footer, Roo);
16209 fctr.insertFirst(this.el);
16211 // this is a bit insane - as the paging toolbar seems to detach the el..
16212 // dom.parentNode.parentNode.parentNode
16213 // they get detached?
16217 Roo.View.superclass.constructor.call(this);
16222 Roo.extend(Roo.View, Roo.util.Observable, {
16225 * @cfg {Roo.data.Store} store Data store to load data from.
16230 * @cfg {String|Roo.Element} el The container element.
16235 * @cfg {String|Roo.Template} tpl The template used by this View
16239 * @cfg {String} dataName the named area of the template to use as the data area
16240 * Works with domtemplates roo-name="name"
16244 * @cfg {String} selectedClass The css class to add to selected nodes
16246 selectedClass : "x-view-selected",
16248 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16253 * @cfg {String} text to display on mask (default Loading)
16257 * @cfg {Boolean} multiSelect Allow multiple selection
16259 multiSelect : false,
16261 * @cfg {Boolean} singleSelect Allow single selection
16263 singleSelect: false,
16266 * @cfg {Boolean} toggleSelect - selecting
16268 toggleSelect : false,
16271 * @cfg {Boolean} tickable - selecting
16276 * Returns the element this view is bound to.
16277 * @return {Roo.Element}
16279 getEl : function(){
16280 return this.wrapEl;
16286 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16288 refresh : function(){
16289 //Roo.log('refresh');
16292 // if we are using something like 'domtemplate', then
16293 // the what gets used is:
16294 // t.applySubtemplate(NAME, data, wrapping data..)
16295 // the outer template then get' applied with
16296 // the store 'extra data'
16297 // and the body get's added to the
16298 // roo-name="data" node?
16299 // <span class='roo-tpl-{name}'></span> ?????
16303 this.clearSelections();
16304 this.el.update("");
16306 var records = this.store.getRange();
16307 if(records.length < 1) {
16309 // is this valid?? = should it render a template??
16311 this.el.update(this.emptyText);
16315 if (this.dataName) {
16316 this.el.update(t.apply(this.store.meta)); //????
16317 el = this.el.child('.roo-tpl-' + this.dataName);
16320 for(var i = 0, len = records.length; i < len; i++){
16321 var data = this.prepareData(records[i].data, i, records[i]);
16322 this.fireEvent("preparedata", this, data, i, records[i]);
16324 var d = Roo.apply({}, data);
16327 Roo.apply(d, {'roo-id' : Roo.id()});
16331 Roo.each(this.parent.item, function(item){
16332 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16335 Roo.apply(d, {'roo-data-checked' : 'checked'});
16339 html[html.length] = Roo.util.Format.trim(
16341 t.applySubtemplate(this.dataName, d, this.store.meta) :
16348 el.update(html.join(""));
16349 this.nodes = el.dom.childNodes;
16350 this.updateIndexes(0);
16355 * Function to override to reformat the data that is sent to
16356 * the template for each node.
16357 * DEPRICATED - use the preparedata event handler.
16358 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16359 * a JSON object for an UpdateManager bound view).
16361 prepareData : function(data, index, record)
16363 this.fireEvent("preparedata", this, data, index, record);
16367 onUpdate : function(ds, record){
16368 // Roo.log('on update');
16369 this.clearSelections();
16370 var index = this.store.indexOf(record);
16371 var n = this.nodes[index];
16372 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16373 n.parentNode.removeChild(n);
16374 this.updateIndexes(index, index);
16380 onAdd : function(ds, records, index)
16382 //Roo.log(['on Add', ds, records, index] );
16383 this.clearSelections();
16384 if(this.nodes.length == 0){
16388 var n = this.nodes[index];
16389 for(var i = 0, len = records.length; i < len; i++){
16390 var d = this.prepareData(records[i].data, i, records[i]);
16392 this.tpl.insertBefore(n, d);
16395 this.tpl.append(this.el, d);
16398 this.updateIndexes(index);
16401 onRemove : function(ds, record, index){
16402 // Roo.log('onRemove');
16403 this.clearSelections();
16404 var el = this.dataName ?
16405 this.el.child('.roo-tpl-' + this.dataName) :
16408 el.dom.removeChild(this.nodes[index]);
16409 this.updateIndexes(index);
16413 * Refresh an individual node.
16414 * @param {Number} index
16416 refreshNode : function(index){
16417 this.onUpdate(this.store, this.store.getAt(index));
16420 updateIndexes : function(startIndex, endIndex){
16421 var ns = this.nodes;
16422 startIndex = startIndex || 0;
16423 endIndex = endIndex || ns.length - 1;
16424 for(var i = startIndex; i <= endIndex; i++){
16425 ns[i].nodeIndex = i;
16430 * Changes the data store this view uses and refresh the view.
16431 * @param {Store} store
16433 setStore : function(store, initial){
16434 if(!initial && this.store){
16435 this.store.un("datachanged", this.refresh);
16436 this.store.un("add", this.onAdd);
16437 this.store.un("remove", this.onRemove);
16438 this.store.un("update", this.onUpdate);
16439 this.store.un("clear", this.refresh);
16440 this.store.un("beforeload", this.onBeforeLoad);
16441 this.store.un("load", this.onLoad);
16442 this.store.un("loadexception", this.onLoad);
16446 store.on("datachanged", this.refresh, this);
16447 store.on("add", this.onAdd, this);
16448 store.on("remove", this.onRemove, this);
16449 store.on("update", this.onUpdate, this);
16450 store.on("clear", this.refresh, this);
16451 store.on("beforeload", this.onBeforeLoad, this);
16452 store.on("load", this.onLoad, this);
16453 store.on("loadexception", this.onLoad, this);
16461 * onbeforeLoad - masks the loading area.
16464 onBeforeLoad : function(store,opts)
16466 //Roo.log('onBeforeLoad');
16468 this.el.update("");
16470 this.el.mask(this.mask ? this.mask : "Loading" );
16472 onLoad : function ()
16479 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16480 * @param {HTMLElement} node
16481 * @return {HTMLElement} The template node
16483 findItemFromChild : function(node){
16484 var el = this.dataName ?
16485 this.el.child('.roo-tpl-' + this.dataName,true) :
16488 if(!node || node.parentNode == el){
16491 var p = node.parentNode;
16492 while(p && p != el){
16493 if(p.parentNode == el){
16502 onClick : function(e){
16503 var item = this.findItemFromChild(e.getTarget());
16505 var index = this.indexOf(item);
16506 if(this.onItemClick(item, index, e) !== false){
16507 this.fireEvent("click", this, index, item, e);
16510 this.clearSelections();
16515 onContextMenu : function(e){
16516 var item = this.findItemFromChild(e.getTarget());
16518 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16523 onDblClick : function(e){
16524 var item = this.findItemFromChild(e.getTarget());
16526 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16530 onItemClick : function(item, index, e)
16532 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16535 if (this.toggleSelect) {
16536 var m = this.isSelected(item) ? 'unselect' : 'select';
16539 _t[m](item, true, false);
16542 if(this.multiSelect || this.singleSelect){
16543 if(this.multiSelect && e.shiftKey && this.lastSelection){
16544 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16546 this.select(item, this.multiSelect && e.ctrlKey);
16547 this.lastSelection = item;
16550 if(!this.tickable){
16551 e.preventDefault();
16559 * Get the number of selected nodes.
16562 getSelectionCount : function(){
16563 return this.selections.length;
16567 * Get the currently selected nodes.
16568 * @return {Array} An array of HTMLElements
16570 getSelectedNodes : function(){
16571 return this.selections;
16575 * Get the indexes of the selected nodes.
16578 getSelectedIndexes : function(){
16579 var indexes = [], s = this.selections;
16580 for(var i = 0, len = s.length; i < len; i++){
16581 indexes.push(s[i].nodeIndex);
16587 * Clear all selections
16588 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16590 clearSelections : function(suppressEvent){
16591 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16592 this.cmp.elements = this.selections;
16593 this.cmp.removeClass(this.selectedClass);
16594 this.selections = [];
16595 if(!suppressEvent){
16596 this.fireEvent("selectionchange", this, this.selections);
16602 * Returns true if the passed node is selected
16603 * @param {HTMLElement/Number} node The node or node index
16604 * @return {Boolean}
16606 isSelected : function(node){
16607 var s = this.selections;
16611 node = this.getNode(node);
16612 return s.indexOf(node) !== -1;
16617 * @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
16618 * @param {Boolean} keepExisting (optional) true to keep existing selections
16619 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16621 select : function(nodeInfo, keepExisting, suppressEvent){
16622 if(nodeInfo instanceof Array){
16624 this.clearSelections(true);
16626 for(var i = 0, len = nodeInfo.length; i < len; i++){
16627 this.select(nodeInfo[i], true, true);
16631 var node = this.getNode(nodeInfo);
16632 if(!node || this.isSelected(node)){
16633 return; // already selected.
16636 this.clearSelections(true);
16639 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16640 Roo.fly(node).addClass(this.selectedClass);
16641 this.selections.push(node);
16642 if(!suppressEvent){
16643 this.fireEvent("selectionchange", this, this.selections);
16651 * @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
16652 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16653 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16655 unselect : function(nodeInfo, keepExisting, suppressEvent)
16657 if(nodeInfo instanceof Array){
16658 Roo.each(this.selections, function(s) {
16659 this.unselect(s, nodeInfo);
16663 var node = this.getNode(nodeInfo);
16664 if(!node || !this.isSelected(node)){
16665 //Roo.log("not selected");
16666 return; // not selected.
16670 Roo.each(this.selections, function(s) {
16672 Roo.fly(node).removeClass(this.selectedClass);
16679 this.selections= ns;
16680 this.fireEvent("selectionchange", this, this.selections);
16684 * Gets a template node.
16685 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16686 * @return {HTMLElement} The node or null if it wasn't found
16688 getNode : function(nodeInfo){
16689 if(typeof nodeInfo == "string"){
16690 return document.getElementById(nodeInfo);
16691 }else if(typeof nodeInfo == "number"){
16692 return this.nodes[nodeInfo];
16698 * Gets a range template nodes.
16699 * @param {Number} startIndex
16700 * @param {Number} endIndex
16701 * @return {Array} An array of nodes
16703 getNodes : function(start, end){
16704 var ns = this.nodes;
16705 start = start || 0;
16706 end = typeof end == "undefined" ? ns.length - 1 : end;
16709 for(var i = start; i <= end; i++){
16713 for(var i = start; i >= end; i--){
16721 * Finds the index of the passed node
16722 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16723 * @return {Number} The index of the node or -1
16725 indexOf : function(node){
16726 node = this.getNode(node);
16727 if(typeof node.nodeIndex == "number"){
16728 return node.nodeIndex;
16730 var ns = this.nodes;
16731 for(var i = 0, len = ns.length; i < len; i++){
16742 * based on jquery fullcalendar
16746 Roo.bootstrap = Roo.bootstrap || {};
16748 * @class Roo.bootstrap.Calendar
16749 * @extends Roo.bootstrap.Component
16750 * Bootstrap Calendar class
16751 * @cfg {Boolean} loadMask (true|false) default false
16752 * @cfg {Object} header generate the user specific header of the calendar, default false
16755 * Create a new Container
16756 * @param {Object} config The config object
16761 Roo.bootstrap.Calendar = function(config){
16762 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16766 * Fires when a date is selected
16767 * @param {DatePicker} this
16768 * @param {Date} date The selected date
16772 * @event monthchange
16773 * Fires when the displayed month changes
16774 * @param {DatePicker} this
16775 * @param {Date} date The selected month
16777 'monthchange': true,
16779 * @event evententer
16780 * Fires when mouse over an event
16781 * @param {Calendar} this
16782 * @param {event} Event
16784 'evententer': true,
16786 * @event eventleave
16787 * Fires when the mouse leaves an
16788 * @param {Calendar} this
16791 'eventleave': true,
16793 * @event eventclick
16794 * Fires when the mouse click an
16795 * @param {Calendar} this
16804 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16807 * @cfg {Number} startDay
16808 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16816 getAutoCreate : function(){
16819 var fc_button = function(name, corner, style, content ) {
16820 return Roo.apply({},{
16822 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16824 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16827 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16838 style : 'width:100%',
16845 cls : 'fc-header-left',
16847 fc_button('prev', 'left', 'arrow', '‹' ),
16848 fc_button('next', 'right', 'arrow', '›' ),
16849 { tag: 'span', cls: 'fc-header-space' },
16850 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16858 cls : 'fc-header-center',
16862 cls: 'fc-header-title',
16865 html : 'month / year'
16873 cls : 'fc-header-right',
16875 /* fc_button('month', 'left', '', 'month' ),
16876 fc_button('week', '', '', 'week' ),
16877 fc_button('day', 'right', '', 'day' )
16889 header = this.header;
16892 var cal_heads = function() {
16894 // fixme - handle this.
16896 for (var i =0; i < Date.dayNames.length; i++) {
16897 var d = Date.dayNames[i];
16900 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16901 html : d.substring(0,3)
16905 ret[0].cls += ' fc-first';
16906 ret[6].cls += ' fc-last';
16909 var cal_cell = function(n) {
16912 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16917 cls: 'fc-day-number',
16921 cls: 'fc-day-content',
16925 style: 'position: relative;' // height: 17px;
16937 var cal_rows = function() {
16940 for (var r = 0; r < 6; r++) {
16947 for (var i =0; i < Date.dayNames.length; i++) {
16948 var d = Date.dayNames[i];
16949 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16952 row.cn[0].cls+=' fc-first';
16953 row.cn[0].cn[0].style = 'min-height:90px';
16954 row.cn[6].cls+=' fc-last';
16958 ret[0].cls += ' fc-first';
16959 ret[4].cls += ' fc-prev-last';
16960 ret[5].cls += ' fc-last';
16967 cls: 'fc-border-separate',
16968 style : 'width:100%',
16976 cls : 'fc-first fc-last',
16994 cls : 'fc-content',
16995 style : "position: relative;",
16998 cls : 'fc-view fc-view-month fc-grid',
16999 style : 'position: relative',
17000 unselectable : 'on',
17003 cls : 'fc-event-container',
17004 style : 'position:absolute;z-index:8;top:0;left:0;'
17022 initEvents : function()
17025 throw "can not find store for calendar";
17031 style: "text-align:center",
17035 style: "background-color:white;width:50%;margin:250 auto",
17039 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17050 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17052 var size = this.el.select('.fc-content', true).first().getSize();
17053 this.maskEl.setSize(size.width, size.height);
17054 this.maskEl.enableDisplayMode("block");
17055 if(!this.loadMask){
17056 this.maskEl.hide();
17059 this.store = Roo.factory(this.store, Roo.data);
17060 this.store.on('load', this.onLoad, this);
17061 this.store.on('beforeload', this.onBeforeLoad, this);
17065 this.cells = this.el.select('.fc-day',true);
17066 //Roo.log(this.cells);
17067 this.textNodes = this.el.query('.fc-day-number');
17068 this.cells.addClassOnOver('fc-state-hover');
17070 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17071 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17072 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17073 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17075 this.on('monthchange', this.onMonthChange, this);
17077 this.update(new Date().clearTime());
17080 resize : function() {
17081 var sz = this.el.getSize();
17083 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17084 this.el.select('.fc-day-content div',true).setHeight(34);
17089 showPrevMonth : function(e){
17090 this.update(this.activeDate.add("mo", -1));
17092 showToday : function(e){
17093 this.update(new Date().clearTime());
17096 showNextMonth : function(e){
17097 this.update(this.activeDate.add("mo", 1));
17101 showPrevYear : function(){
17102 this.update(this.activeDate.add("y", -1));
17106 showNextYear : function(){
17107 this.update(this.activeDate.add("y", 1));
17112 update : function(date)
17114 var vd = this.activeDate;
17115 this.activeDate = date;
17116 // if(vd && this.el){
17117 // var t = date.getTime();
17118 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17119 // Roo.log('using add remove');
17121 // this.fireEvent('monthchange', this, date);
17123 // this.cells.removeClass("fc-state-highlight");
17124 // this.cells.each(function(c){
17125 // if(c.dateValue == t){
17126 // c.addClass("fc-state-highlight");
17127 // setTimeout(function(){
17128 // try{c.dom.firstChild.focus();}catch(e){}
17138 var days = date.getDaysInMonth();
17140 var firstOfMonth = date.getFirstDateOfMonth();
17141 var startingPos = firstOfMonth.getDay()-this.startDay;
17143 if(startingPos < this.startDay){
17147 var pm = date.add(Date.MONTH, -1);
17148 var prevStart = pm.getDaysInMonth()-startingPos;
17150 this.cells = this.el.select('.fc-day',true);
17151 this.textNodes = this.el.query('.fc-day-number');
17152 this.cells.addClassOnOver('fc-state-hover');
17154 var cells = this.cells.elements;
17155 var textEls = this.textNodes;
17157 Roo.each(cells, function(cell){
17158 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17161 days += startingPos;
17163 // convert everything to numbers so it's fast
17164 var day = 86400000;
17165 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17168 //Roo.log(prevStart);
17170 var today = new Date().clearTime().getTime();
17171 var sel = date.clearTime().getTime();
17172 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17173 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17174 var ddMatch = this.disabledDatesRE;
17175 var ddText = this.disabledDatesText;
17176 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17177 var ddaysText = this.disabledDaysText;
17178 var format = this.format;
17180 var setCellClass = function(cal, cell){
17184 //Roo.log('set Cell Class');
17186 var t = d.getTime();
17190 cell.dateValue = t;
17192 cell.className += " fc-today";
17193 cell.className += " fc-state-highlight";
17194 cell.title = cal.todayText;
17197 // disable highlight in other month..
17198 //cell.className += " fc-state-highlight";
17203 cell.className = " fc-state-disabled";
17204 cell.title = cal.minText;
17208 cell.className = " fc-state-disabled";
17209 cell.title = cal.maxText;
17213 if(ddays.indexOf(d.getDay()) != -1){
17214 cell.title = ddaysText;
17215 cell.className = " fc-state-disabled";
17218 if(ddMatch && format){
17219 var fvalue = d.dateFormat(format);
17220 if(ddMatch.test(fvalue)){
17221 cell.title = ddText.replace("%0", fvalue);
17222 cell.className = " fc-state-disabled";
17226 if (!cell.initialClassName) {
17227 cell.initialClassName = cell.dom.className;
17230 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17235 for(; i < startingPos; i++) {
17236 textEls[i].innerHTML = (++prevStart);
17237 d.setDate(d.getDate()+1);
17239 cells[i].className = "fc-past fc-other-month";
17240 setCellClass(this, cells[i]);
17245 for(; i < days; i++){
17246 intDay = i - startingPos + 1;
17247 textEls[i].innerHTML = (intDay);
17248 d.setDate(d.getDate()+1);
17250 cells[i].className = ''; // "x-date-active";
17251 setCellClass(this, cells[i]);
17255 for(; i < 42; i++) {
17256 textEls[i].innerHTML = (++extraDays);
17257 d.setDate(d.getDate()+1);
17259 cells[i].className = "fc-future fc-other-month";
17260 setCellClass(this, cells[i]);
17263 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17265 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17267 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17268 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17270 if(totalRows != 6){
17271 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17272 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17275 this.fireEvent('monthchange', this, date);
17279 if(!this.internalRender){
17280 var main = this.el.dom.firstChild;
17281 var w = main.offsetWidth;
17282 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17283 Roo.fly(main).setWidth(w);
17284 this.internalRender = true;
17285 // opera does not respect the auto grow header center column
17286 // then, after it gets a width opera refuses to recalculate
17287 // without a second pass
17288 if(Roo.isOpera && !this.secondPass){
17289 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17290 this.secondPass = true;
17291 this.update.defer(10, this, [date]);
17298 findCell : function(dt) {
17299 dt = dt.clearTime().getTime();
17301 this.cells.each(function(c){
17302 //Roo.log("check " +c.dateValue + '?=' + dt);
17303 if(c.dateValue == dt){
17313 findCells : function(ev) {
17314 var s = ev.start.clone().clearTime().getTime();
17316 var e= ev.end.clone().clearTime().getTime();
17319 this.cells.each(function(c){
17320 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17322 if(c.dateValue > e){
17325 if(c.dateValue < s){
17334 // findBestRow: function(cells)
17338 // for (var i =0 ; i < cells.length;i++) {
17339 // ret = Math.max(cells[i].rows || 0,ret);
17346 addItem : function(ev)
17348 // look for vertical location slot in
17349 var cells = this.findCells(ev);
17351 // ev.row = this.findBestRow(cells);
17353 // work out the location.
17357 for(var i =0; i < cells.length; i++) {
17359 cells[i].row = cells[0].row;
17362 cells[i].row = cells[i].row + 1;
17372 if (crow.start.getY() == cells[i].getY()) {
17374 crow.end = cells[i];
17391 cells[0].events.push(ev);
17393 this.calevents.push(ev);
17396 clearEvents: function() {
17398 if(!this.calevents){
17402 Roo.each(this.cells.elements, function(c){
17408 Roo.each(this.calevents, function(e) {
17409 Roo.each(e.els, function(el) {
17410 el.un('mouseenter' ,this.onEventEnter, this);
17411 el.un('mouseleave' ,this.onEventLeave, this);
17416 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17422 renderEvents: function()
17426 this.cells.each(function(c) {
17435 if(c.row != c.events.length){
17436 r = 4 - (4 - (c.row - c.events.length));
17439 c.events = ev.slice(0, r);
17440 c.more = ev.slice(r);
17442 if(c.more.length && c.more.length == 1){
17443 c.events.push(c.more.pop());
17446 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17450 this.cells.each(function(c) {
17452 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17455 for (var e = 0; e < c.events.length; e++){
17456 var ev = c.events[e];
17457 var rows = ev.rows;
17459 for(var i = 0; i < rows.length; i++) {
17461 // how many rows should it span..
17464 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17465 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17467 unselectable : "on",
17470 cls: 'fc-event-inner',
17474 // cls: 'fc-event-time',
17475 // html : cells.length > 1 ? '' : ev.time
17479 cls: 'fc-event-title',
17480 html : String.format('{0}', ev.title)
17487 cls: 'ui-resizable-handle ui-resizable-e',
17488 html : '  '
17495 cfg.cls += ' fc-event-start';
17497 if ((i+1) == rows.length) {
17498 cfg.cls += ' fc-event-end';
17501 var ctr = _this.el.select('.fc-event-container',true).first();
17502 var cg = ctr.createChild(cfg);
17504 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17505 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17507 var r = (c.more.length) ? 1 : 0;
17508 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17509 cg.setWidth(ebox.right - sbox.x -2);
17511 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17512 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17513 cg.on('click', _this.onEventClick, _this, ev);
17524 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17525 style : 'position: absolute',
17526 unselectable : "on",
17529 cls: 'fc-event-inner',
17533 cls: 'fc-event-title',
17541 cls: 'ui-resizable-handle ui-resizable-e',
17542 html : '  '
17548 var ctr = _this.el.select('.fc-event-container',true).first();
17549 var cg = ctr.createChild(cfg);
17551 var sbox = c.select('.fc-day-content',true).first().getBox();
17552 var ebox = c.select('.fc-day-content',true).first().getBox();
17554 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17555 cg.setWidth(ebox.right - sbox.x -2);
17557 cg.on('click', _this.onMoreEventClick, _this, c.more);
17567 onEventEnter: function (e, el,event,d) {
17568 this.fireEvent('evententer', this, el, event);
17571 onEventLeave: function (e, el,event,d) {
17572 this.fireEvent('eventleave', this, el, event);
17575 onEventClick: function (e, el,event,d) {
17576 this.fireEvent('eventclick', this, el, event);
17579 onMonthChange: function () {
17583 onMoreEventClick: function(e, el, more)
17587 this.calpopover.placement = 'right';
17588 this.calpopover.setTitle('More');
17590 this.calpopover.setContent('');
17592 var ctr = this.calpopover.el.select('.popover-content', true).first();
17594 Roo.each(more, function(m){
17596 cls : 'fc-event-hori fc-event-draggable',
17599 var cg = ctr.createChild(cfg);
17601 cg.on('click', _this.onEventClick, _this, m);
17604 this.calpopover.show(el);
17609 onLoad: function ()
17611 this.calevents = [];
17614 if(this.store.getCount() > 0){
17615 this.store.data.each(function(d){
17618 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17619 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17620 time : d.data.start_time,
17621 title : d.data.title,
17622 description : d.data.description,
17623 venue : d.data.venue
17628 this.renderEvents();
17630 if(this.calevents.length && this.loadMask){
17631 this.maskEl.hide();
17635 onBeforeLoad: function()
17637 this.clearEvents();
17639 this.maskEl.show();
17653 * @class Roo.bootstrap.Popover
17654 * @extends Roo.bootstrap.Component
17655 * Bootstrap Popover class
17656 * @cfg {String} html contents of the popover (or false to use children..)
17657 * @cfg {String} title of popover (or false to hide)
17658 * @cfg {String} placement how it is placed
17659 * @cfg {String} trigger click || hover (or false to trigger manually)
17660 * @cfg {String} over what (parent or false to trigger manually.)
17661 * @cfg {Number} delay - delay before showing
17664 * Create a new Popover
17665 * @param {Object} config The config object
17668 Roo.bootstrap.Popover = function(config){
17669 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17675 * After the popover show
17677 * @param {Roo.bootstrap.Popover} this
17682 * After the popover hide
17684 * @param {Roo.bootstrap.Popover} this
17690 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17692 title: 'Fill in a title',
17695 placement : 'right',
17696 trigger : 'hover', // hover
17702 can_build_overlaid : false,
17704 getChildContainer : function()
17706 return this.el.select('.popover-content',true).first();
17709 getAutoCreate : function(){
17712 cls : 'popover roo-dynamic',
17713 style: 'display:block',
17719 cls : 'popover-inner',
17723 cls: 'popover-title popover-header',
17727 cls : 'popover-content popover-body',
17738 setTitle: function(str)
17741 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17743 setContent: function(str)
17746 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17748 // as it get's added to the bottom of the page.
17749 onRender : function(ct, position)
17751 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17753 var cfg = Roo.apply({}, this.getAutoCreate());
17757 cfg.cls += ' ' + this.cls;
17760 cfg.style = this.style;
17762 //Roo.log("adding to ");
17763 this.el = Roo.get(document.body).createChild(cfg, position);
17764 // Roo.log(this.el);
17769 initEvents : function()
17771 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17772 this.el.enableDisplayMode('block');
17774 if (this.over === false) {
17777 if (this.triggers === false) {
17780 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17781 var triggers = this.trigger ? this.trigger.split(' ') : [];
17782 Roo.each(triggers, function(trigger) {
17784 if (trigger == 'click') {
17785 on_el.on('click', this.toggle, this);
17786 } else if (trigger != 'manual') {
17787 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17788 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17790 on_el.on(eventIn ,this.enter, this);
17791 on_el.on(eventOut, this.leave, this);
17802 toggle : function () {
17803 this.hoverState == 'in' ? this.leave() : this.enter();
17806 enter : function () {
17808 clearTimeout(this.timeout);
17810 this.hoverState = 'in';
17812 if (!this.delay || !this.delay.show) {
17817 this.timeout = setTimeout(function () {
17818 if (_t.hoverState == 'in') {
17821 }, this.delay.show)
17824 leave : function() {
17825 clearTimeout(this.timeout);
17827 this.hoverState = 'out';
17829 if (!this.delay || !this.delay.hide) {
17834 this.timeout = setTimeout(function () {
17835 if (_t.hoverState == 'out') {
17838 }, this.delay.hide)
17841 show : function (on_el)
17844 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17848 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17849 if (this.html !== false) {
17850 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17852 this.el.removeClass([
17853 'fade','top','bottom', 'left', 'right','in',
17854 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17856 if (!this.title.length) {
17857 this.el.select('.popover-title',true).hide();
17860 var placement = typeof this.placement == 'function' ?
17861 this.placement.call(this, this.el, on_el) :
17864 var autoToken = /\s?auto?\s?/i;
17865 var autoPlace = autoToken.test(placement);
17867 placement = placement.replace(autoToken, '') || 'top';
17871 //this.el.setXY([0,0]);
17873 this.el.dom.style.display='block';
17874 this.el.addClass(placement);
17876 //this.el.appendTo(on_el);
17878 var p = this.getPosition();
17879 var box = this.el.getBox();
17884 var align = Roo.bootstrap.Popover.alignment[placement];
17887 this.el.alignTo(on_el, align[0],align[1]);
17888 //var arrow = this.el.select('.arrow',true).first();
17889 //arrow.set(align[2],
17891 this.el.addClass('in');
17894 if (this.el.hasClass('fade')) {
17898 this.hoverState = 'in';
17900 this.fireEvent('show', this);
17905 this.el.setXY([0,0]);
17906 this.el.removeClass('in');
17908 this.hoverState = null;
17910 this.fireEvent('hide', this);
17915 Roo.bootstrap.Popover.alignment = {
17916 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17917 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17918 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17919 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17930 * @class Roo.bootstrap.Progress
17931 * @extends Roo.bootstrap.Component
17932 * Bootstrap Progress class
17933 * @cfg {Boolean} striped striped of the progress bar
17934 * @cfg {Boolean} active animated of the progress bar
17938 * Create a new Progress
17939 * @param {Object} config The config object
17942 Roo.bootstrap.Progress = function(config){
17943 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17946 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17951 getAutoCreate : function(){
17959 cfg.cls += ' progress-striped';
17963 cfg.cls += ' active';
17982 * @class Roo.bootstrap.ProgressBar
17983 * @extends Roo.bootstrap.Component
17984 * Bootstrap ProgressBar class
17985 * @cfg {Number} aria_valuenow aria-value now
17986 * @cfg {Number} aria_valuemin aria-value min
17987 * @cfg {Number} aria_valuemax aria-value max
17988 * @cfg {String} label label for the progress bar
17989 * @cfg {String} panel (success | info | warning | danger )
17990 * @cfg {String} role role of the progress bar
17991 * @cfg {String} sr_only text
17995 * Create a new ProgressBar
17996 * @param {Object} config The config object
17999 Roo.bootstrap.ProgressBar = function(config){
18000 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18003 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18007 aria_valuemax : 100,
18013 getAutoCreate : function()
18018 cls: 'progress-bar',
18019 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18031 cfg.role = this.role;
18034 if(this.aria_valuenow){
18035 cfg['aria-valuenow'] = this.aria_valuenow;
18038 if(this.aria_valuemin){
18039 cfg['aria-valuemin'] = this.aria_valuemin;
18042 if(this.aria_valuemax){
18043 cfg['aria-valuemax'] = this.aria_valuemax;
18046 if(this.label && !this.sr_only){
18047 cfg.html = this.label;
18051 cfg.cls += ' progress-bar-' + this.panel;
18057 update : function(aria_valuenow)
18059 this.aria_valuenow = aria_valuenow;
18061 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18076 * @class Roo.bootstrap.TabGroup
18077 * @extends Roo.bootstrap.Column
18078 * Bootstrap Column class
18079 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18080 * @cfg {Boolean} carousel true to make the group behave like a carousel
18081 * @cfg {Boolean} bullets show bullets for the panels
18082 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18083 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18084 * @cfg {Boolean} showarrow (true|false) show arrow default true
18087 * Create a new TabGroup
18088 * @param {Object} config The config object
18091 Roo.bootstrap.TabGroup = function(config){
18092 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18094 this.navId = Roo.id();
18097 Roo.bootstrap.TabGroup.register(this);
18101 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18104 transition : false,
18109 slideOnTouch : false,
18112 getAutoCreate : function()
18114 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18116 cfg.cls += ' tab-content';
18118 if (this.carousel) {
18119 cfg.cls += ' carousel slide';
18122 cls : 'carousel-inner',
18126 if(this.bullets && !Roo.isTouch){
18129 cls : 'carousel-bullets',
18133 if(this.bullets_cls){
18134 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18141 cfg.cn[0].cn.push(bullets);
18144 if(this.showarrow){
18145 cfg.cn[0].cn.push({
18147 class : 'carousel-arrow',
18151 class : 'carousel-prev',
18155 class : 'fa fa-chevron-left'
18161 class : 'carousel-next',
18165 class : 'fa fa-chevron-right'
18178 initEvents: function()
18180 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18181 // this.el.on("touchstart", this.onTouchStart, this);
18184 if(this.autoslide){
18187 this.slideFn = window.setInterval(function() {
18188 _this.showPanelNext();
18192 if(this.showarrow){
18193 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18194 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18200 // onTouchStart : function(e, el, o)
18202 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18206 // this.showPanelNext();
18210 getChildContainer : function()
18212 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18216 * register a Navigation item
18217 * @param {Roo.bootstrap.NavItem} the navitem to add
18219 register : function(item)
18221 this.tabs.push( item);
18222 item.navId = this.navId; // not really needed..
18227 getActivePanel : function()
18230 Roo.each(this.tabs, function(t) {
18240 getPanelByName : function(n)
18243 Roo.each(this.tabs, function(t) {
18244 if (t.tabId == n) {
18252 indexOfPanel : function(p)
18255 Roo.each(this.tabs, function(t,i) {
18256 if (t.tabId == p.tabId) {
18265 * show a specific panel
18266 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18267 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18269 showPanel : function (pan)
18271 if(this.transition || typeof(pan) == 'undefined'){
18272 Roo.log("waiting for the transitionend");
18276 if (typeof(pan) == 'number') {
18277 pan = this.tabs[pan];
18280 if (typeof(pan) == 'string') {
18281 pan = this.getPanelByName(pan);
18284 var cur = this.getActivePanel();
18287 Roo.log('pan or acitve pan is undefined');
18291 if (pan.tabId == this.getActivePanel().tabId) {
18295 if (false === cur.fireEvent('beforedeactivate')) {
18299 if(this.bullets > 0 && !Roo.isTouch){
18300 this.setActiveBullet(this.indexOfPanel(pan));
18303 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18305 this.transition = true;
18306 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18307 var lr = dir == 'next' ? 'left' : 'right';
18308 pan.el.addClass(dir); // or prev
18309 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18310 cur.el.addClass(lr); // or right
18311 pan.el.addClass(lr);
18314 cur.el.on('transitionend', function() {
18315 Roo.log("trans end?");
18317 pan.el.removeClass([lr,dir]);
18318 pan.setActive(true);
18320 cur.el.removeClass([lr]);
18321 cur.setActive(false);
18323 _this.transition = false;
18325 }, this, { single: true } );
18330 cur.setActive(false);
18331 pan.setActive(true);
18336 showPanelNext : function()
18338 var i = this.indexOfPanel(this.getActivePanel());
18340 if (i >= this.tabs.length - 1 && !this.autoslide) {
18344 if (i >= this.tabs.length - 1 && this.autoslide) {
18348 this.showPanel(this.tabs[i+1]);
18351 showPanelPrev : function()
18353 var i = this.indexOfPanel(this.getActivePanel());
18355 if (i < 1 && !this.autoslide) {
18359 if (i < 1 && this.autoslide) {
18360 i = this.tabs.length;
18363 this.showPanel(this.tabs[i-1]);
18367 addBullet: function()
18369 if(!this.bullets || Roo.isTouch){
18372 var ctr = this.el.select('.carousel-bullets',true).first();
18373 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18374 var bullet = ctr.createChild({
18375 cls : 'bullet bullet-' + i
18376 },ctr.dom.lastChild);
18381 bullet.on('click', (function(e, el, o, ii, t){
18383 e.preventDefault();
18385 this.showPanel(ii);
18387 if(this.autoslide && this.slideFn){
18388 clearInterval(this.slideFn);
18389 this.slideFn = window.setInterval(function() {
18390 _this.showPanelNext();
18394 }).createDelegate(this, [i, bullet], true));
18399 setActiveBullet : function(i)
18405 Roo.each(this.el.select('.bullet', true).elements, function(el){
18406 el.removeClass('selected');
18409 var bullet = this.el.select('.bullet-' + i, true).first();
18415 bullet.addClass('selected');
18426 Roo.apply(Roo.bootstrap.TabGroup, {
18430 * register a Navigation Group
18431 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18433 register : function(navgrp)
18435 this.groups[navgrp.navId] = navgrp;
18439 * fetch a Navigation Group based on the navigation ID
18440 * if one does not exist , it will get created.
18441 * @param {string} the navgroup to add
18442 * @returns {Roo.bootstrap.NavGroup} the navgroup
18444 get: function(navId) {
18445 if (typeof(this.groups[navId]) == 'undefined') {
18446 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18448 return this.groups[navId] ;
18463 * @class Roo.bootstrap.TabPanel
18464 * @extends Roo.bootstrap.Component
18465 * Bootstrap TabPanel class
18466 * @cfg {Boolean} active panel active
18467 * @cfg {String} html panel content
18468 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18469 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18470 * @cfg {String} href click to link..
18474 * Create a new TabPanel
18475 * @param {Object} config The config object
18478 Roo.bootstrap.TabPanel = function(config){
18479 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18483 * Fires when the active status changes
18484 * @param {Roo.bootstrap.TabPanel} this
18485 * @param {Boolean} state the new state
18490 * @event beforedeactivate
18491 * Fires before a tab is de-activated - can be used to do validation on a form.
18492 * @param {Roo.bootstrap.TabPanel} this
18493 * @return {Boolean} false if there is an error
18496 'beforedeactivate': true
18499 this.tabId = this.tabId || Roo.id();
18503 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18511 getAutoCreate : function(){
18514 // item is needed for carousel - not sure if it has any effect otherwise
18515 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18516 html: this.html || ''
18520 cfg.cls += ' active';
18524 cfg.tabId = this.tabId;
18531 initEvents: function()
18533 var p = this.parent();
18535 this.navId = this.navId || p.navId;
18537 if (typeof(this.navId) != 'undefined') {
18538 // not really needed.. but just in case.. parent should be a NavGroup.
18539 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18543 var i = tg.tabs.length - 1;
18545 if(this.active && tg.bullets > 0 && i < tg.bullets){
18546 tg.setActiveBullet(i);
18550 this.el.on('click', this.onClick, this);
18553 this.el.on("touchstart", this.onTouchStart, this);
18554 this.el.on("touchmove", this.onTouchMove, this);
18555 this.el.on("touchend", this.onTouchEnd, this);
18560 onRender : function(ct, position)
18562 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18565 setActive : function(state)
18567 Roo.log("panel - set active " + this.tabId + "=" + state);
18569 this.active = state;
18571 this.el.removeClass('active');
18573 } else if (!this.el.hasClass('active')) {
18574 this.el.addClass('active');
18577 this.fireEvent('changed', this, state);
18580 onClick : function(e)
18582 e.preventDefault();
18584 if(!this.href.length){
18588 window.location.href = this.href;
18597 onTouchStart : function(e)
18599 this.swiping = false;
18601 this.startX = e.browserEvent.touches[0].clientX;
18602 this.startY = e.browserEvent.touches[0].clientY;
18605 onTouchMove : function(e)
18607 this.swiping = true;
18609 this.endX = e.browserEvent.touches[0].clientX;
18610 this.endY = e.browserEvent.touches[0].clientY;
18613 onTouchEnd : function(e)
18620 var tabGroup = this.parent();
18622 if(this.endX > this.startX){ // swiping right
18623 tabGroup.showPanelPrev();
18627 if(this.startX > this.endX){ // swiping left
18628 tabGroup.showPanelNext();
18647 * @class Roo.bootstrap.DateField
18648 * @extends Roo.bootstrap.Input
18649 * Bootstrap DateField class
18650 * @cfg {Number} weekStart default 0
18651 * @cfg {String} viewMode default empty, (months|years)
18652 * @cfg {String} minViewMode default empty, (months|years)
18653 * @cfg {Number} startDate default -Infinity
18654 * @cfg {Number} endDate default Infinity
18655 * @cfg {Boolean} todayHighlight default false
18656 * @cfg {Boolean} todayBtn default false
18657 * @cfg {Boolean} calendarWeeks default false
18658 * @cfg {Object} daysOfWeekDisabled default empty
18659 * @cfg {Boolean} singleMode default false (true | false)
18661 * @cfg {Boolean} keyboardNavigation default true
18662 * @cfg {String} language default en
18665 * Create a new DateField
18666 * @param {Object} config The config object
18669 Roo.bootstrap.DateField = function(config){
18670 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18674 * Fires when this field show.
18675 * @param {Roo.bootstrap.DateField} this
18676 * @param {Mixed} date The date value
18681 * Fires when this field hide.
18682 * @param {Roo.bootstrap.DateField} this
18683 * @param {Mixed} date The date value
18688 * Fires when select a date.
18689 * @param {Roo.bootstrap.DateField} this
18690 * @param {Mixed} date The date value
18694 * @event beforeselect
18695 * Fires when before select a date.
18696 * @param {Roo.bootstrap.DateField} this
18697 * @param {Mixed} date The date value
18699 beforeselect : true
18703 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18706 * @cfg {String} format
18707 * The default date format string which can be overriden for localization support. The format must be
18708 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18712 * @cfg {String} altFormats
18713 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18714 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18716 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18724 todayHighlight : false,
18730 keyboardNavigation: true,
18732 calendarWeeks: false,
18734 startDate: -Infinity,
18738 daysOfWeekDisabled: [],
18742 singleMode : false,
18744 UTCDate: function()
18746 return new Date(Date.UTC.apply(Date, arguments));
18749 UTCToday: function()
18751 var today = new Date();
18752 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18755 getDate: function() {
18756 var d = this.getUTCDate();
18757 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18760 getUTCDate: function() {
18764 setDate: function(d) {
18765 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18768 setUTCDate: function(d) {
18770 this.setValue(this.formatDate(this.date));
18773 onRender: function(ct, position)
18776 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18778 this.language = this.language || 'en';
18779 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18780 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18782 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18783 this.format = this.format || 'm/d/y';
18784 this.isInline = false;
18785 this.isInput = true;
18786 this.component = this.el.select('.add-on', true).first() || false;
18787 this.component = (this.component && this.component.length === 0) ? false : this.component;
18788 this.hasInput = this.component && this.inputEl().length;
18790 if (typeof(this.minViewMode === 'string')) {
18791 switch (this.minViewMode) {
18793 this.minViewMode = 1;
18796 this.minViewMode = 2;
18799 this.minViewMode = 0;
18804 if (typeof(this.viewMode === 'string')) {
18805 switch (this.viewMode) {
18818 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18820 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18822 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18824 this.picker().on('mousedown', this.onMousedown, this);
18825 this.picker().on('click', this.onClick, this);
18827 this.picker().addClass('datepicker-dropdown');
18829 this.startViewMode = this.viewMode;
18831 if(this.singleMode){
18832 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18833 v.setVisibilityMode(Roo.Element.DISPLAY);
18837 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18838 v.setStyle('width', '189px');
18842 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18843 if(!this.calendarWeeks){
18848 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18849 v.attr('colspan', function(i, val){
18850 return parseInt(val) + 1;
18855 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18857 this.setStartDate(this.startDate);
18858 this.setEndDate(this.endDate);
18860 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18867 if(this.isInline) {
18872 picker : function()
18874 return this.pickerEl;
18875 // return this.el.select('.datepicker', true).first();
18878 fillDow: function()
18880 var dowCnt = this.weekStart;
18889 if(this.calendarWeeks){
18897 while (dowCnt < this.weekStart + 7) {
18901 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18905 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18908 fillMonths: function()
18911 var months = this.picker().select('>.datepicker-months td', true).first();
18913 months.dom.innerHTML = '';
18919 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18922 months.createChild(month);
18929 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;
18931 if (this.date < this.startDate) {
18932 this.viewDate = new Date(this.startDate);
18933 } else if (this.date > this.endDate) {
18934 this.viewDate = new Date(this.endDate);
18936 this.viewDate = new Date(this.date);
18944 var d = new Date(this.viewDate),
18945 year = d.getUTCFullYear(),
18946 month = d.getUTCMonth(),
18947 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18948 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18949 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18950 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18951 currentDate = this.date && this.date.valueOf(),
18952 today = this.UTCToday();
18954 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18956 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18958 // this.picker.select('>tfoot th.today').
18959 // .text(dates[this.language].today)
18960 // .toggle(this.todayBtn !== false);
18962 this.updateNavArrows();
18965 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18967 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18969 prevMonth.setUTCDate(day);
18971 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18973 var nextMonth = new Date(prevMonth);
18975 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
18977 nextMonth = nextMonth.valueOf();
18979 var fillMonths = false;
18981 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
18983 while(prevMonth.valueOf() <= nextMonth) {
18986 if (prevMonth.getUTCDay() === this.weekStart) {
18988 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
18996 if(this.calendarWeeks){
18997 // ISO 8601: First week contains first thursday.
18998 // ISO also states week starts on Monday, but we can be more abstract here.
19000 // Start of current week: based on weekstart/current date
19001 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19002 // Thursday of this week
19003 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19004 // First Thursday of year, year from thursday
19005 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19006 // Calendar week: ms between thursdays, div ms per day, div 7 days
19007 calWeek = (th - yth) / 864e5 / 7 + 1;
19009 fillMonths.cn.push({
19017 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19019 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19022 if (this.todayHighlight &&
19023 prevMonth.getUTCFullYear() == today.getFullYear() &&
19024 prevMonth.getUTCMonth() == today.getMonth() &&
19025 prevMonth.getUTCDate() == today.getDate()) {
19026 clsName += ' today';
19029 if (currentDate && prevMonth.valueOf() === currentDate) {
19030 clsName += ' active';
19033 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19034 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19035 clsName += ' disabled';
19038 fillMonths.cn.push({
19040 cls: 'day ' + clsName,
19041 html: prevMonth.getDate()
19044 prevMonth.setDate(prevMonth.getDate()+1);
19047 var currentYear = this.date && this.date.getUTCFullYear();
19048 var currentMonth = this.date && this.date.getUTCMonth();
19050 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19052 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19053 v.removeClass('active');
19055 if(currentYear === year && k === currentMonth){
19056 v.addClass('active');
19059 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19060 v.addClass('disabled');
19066 year = parseInt(year/10, 10) * 10;
19068 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19070 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19073 for (var i = -1; i < 11; i++) {
19074 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19076 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19084 showMode: function(dir)
19087 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19090 Roo.each(this.picker().select('>div',true).elements, function(v){
19091 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19094 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19099 if(this.isInline) {
19103 this.picker().removeClass(['bottom', 'top']);
19105 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19107 * place to the top of element!
19111 this.picker().addClass('top');
19112 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19117 this.picker().addClass('bottom');
19119 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19122 parseDate : function(value)
19124 if(!value || value instanceof Date){
19127 var v = Date.parseDate(value, this.format);
19128 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19129 v = Date.parseDate(value, 'Y-m-d');
19131 if(!v && this.altFormats){
19132 if(!this.altFormatsArray){
19133 this.altFormatsArray = this.altFormats.split("|");
19135 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19136 v = Date.parseDate(value, this.altFormatsArray[i]);
19142 formatDate : function(date, fmt)
19144 return (!date || !(date instanceof Date)) ?
19145 date : date.dateFormat(fmt || this.format);
19148 onFocus : function()
19150 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19154 onBlur : function()
19156 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19158 var d = this.inputEl().getValue();
19165 showPopup : function()
19167 this.picker().show();
19171 this.fireEvent('showpopup', this, this.date);
19174 hidePopup : function()
19176 if(this.isInline) {
19179 this.picker().hide();
19180 this.viewMode = this.startViewMode;
19183 this.fireEvent('hidepopup', this, this.date);
19187 onMousedown: function(e)
19189 e.stopPropagation();
19190 e.preventDefault();
19195 Roo.bootstrap.DateField.superclass.keyup.call(this);
19199 setValue: function(v)
19201 if(this.fireEvent('beforeselect', this, v) !== false){
19202 var d = new Date(this.parseDate(v) ).clearTime();
19204 if(isNaN(d.getTime())){
19205 this.date = this.viewDate = '';
19206 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19210 v = this.formatDate(d);
19212 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19214 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19218 this.fireEvent('select', this, this.date);
19222 getValue: function()
19224 return this.formatDate(this.date);
19227 fireKey: function(e)
19229 if (!this.picker().isVisible()){
19230 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19236 var dateChanged = false,
19238 newDate, newViewDate;
19243 e.preventDefault();
19247 if (!this.keyboardNavigation) {
19250 dir = e.keyCode == 37 ? -1 : 1;
19253 newDate = this.moveYear(this.date, dir);
19254 newViewDate = this.moveYear(this.viewDate, dir);
19255 } else if (e.shiftKey){
19256 newDate = this.moveMonth(this.date, dir);
19257 newViewDate = this.moveMonth(this.viewDate, dir);
19259 newDate = new Date(this.date);
19260 newDate.setUTCDate(this.date.getUTCDate() + dir);
19261 newViewDate = new Date(this.viewDate);
19262 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19264 if (this.dateWithinRange(newDate)){
19265 this.date = newDate;
19266 this.viewDate = newViewDate;
19267 this.setValue(this.formatDate(this.date));
19269 e.preventDefault();
19270 dateChanged = true;
19275 if (!this.keyboardNavigation) {
19278 dir = e.keyCode == 38 ? -1 : 1;
19280 newDate = this.moveYear(this.date, dir);
19281 newViewDate = this.moveYear(this.viewDate, dir);
19282 } else if (e.shiftKey){
19283 newDate = this.moveMonth(this.date, dir);
19284 newViewDate = this.moveMonth(this.viewDate, dir);
19286 newDate = new Date(this.date);
19287 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19288 newViewDate = new Date(this.viewDate);
19289 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19291 if (this.dateWithinRange(newDate)){
19292 this.date = newDate;
19293 this.viewDate = newViewDate;
19294 this.setValue(this.formatDate(this.date));
19296 e.preventDefault();
19297 dateChanged = true;
19301 this.setValue(this.formatDate(this.date));
19303 e.preventDefault();
19306 this.setValue(this.formatDate(this.date));
19320 onClick: function(e)
19322 e.stopPropagation();
19323 e.preventDefault();
19325 var target = e.getTarget();
19327 if(target.nodeName.toLowerCase() === 'i'){
19328 target = Roo.get(target).dom.parentNode;
19331 var nodeName = target.nodeName;
19332 var className = target.className;
19333 var html = target.innerHTML;
19334 //Roo.log(nodeName);
19336 switch(nodeName.toLowerCase()) {
19338 switch(className) {
19344 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19345 switch(this.viewMode){
19347 this.viewDate = this.moveMonth(this.viewDate, dir);
19351 this.viewDate = this.moveYear(this.viewDate, dir);
19357 var date = new Date();
19358 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19360 this.setValue(this.formatDate(this.date));
19367 if (className.indexOf('disabled') < 0) {
19368 this.viewDate.setUTCDate(1);
19369 if (className.indexOf('month') > -1) {
19370 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19372 var year = parseInt(html, 10) || 0;
19373 this.viewDate.setUTCFullYear(year);
19377 if(this.singleMode){
19378 this.setValue(this.formatDate(this.viewDate));
19389 //Roo.log(className);
19390 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19391 var day = parseInt(html, 10) || 1;
19392 var year = this.viewDate.getUTCFullYear(),
19393 month = this.viewDate.getUTCMonth();
19395 if (className.indexOf('old') > -1) {
19402 } else if (className.indexOf('new') > -1) {
19410 //Roo.log([year,month,day]);
19411 this.date = this.UTCDate(year, month, day,0,0,0,0);
19412 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19414 //Roo.log(this.formatDate(this.date));
19415 this.setValue(this.formatDate(this.date));
19422 setStartDate: function(startDate)
19424 this.startDate = startDate || -Infinity;
19425 if (this.startDate !== -Infinity) {
19426 this.startDate = this.parseDate(this.startDate);
19429 this.updateNavArrows();
19432 setEndDate: function(endDate)
19434 this.endDate = endDate || Infinity;
19435 if (this.endDate !== Infinity) {
19436 this.endDate = this.parseDate(this.endDate);
19439 this.updateNavArrows();
19442 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19444 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19445 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19446 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19448 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19449 return parseInt(d, 10);
19452 this.updateNavArrows();
19455 updateNavArrows: function()
19457 if(this.singleMode){
19461 var d = new Date(this.viewDate),
19462 year = d.getUTCFullYear(),
19463 month = d.getUTCMonth();
19465 Roo.each(this.picker().select('.prev', true).elements, function(v){
19467 switch (this.viewMode) {
19470 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19476 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19483 Roo.each(this.picker().select('.next', true).elements, function(v){
19485 switch (this.viewMode) {
19488 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19494 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19502 moveMonth: function(date, dir)
19507 var new_date = new Date(date.valueOf()),
19508 day = new_date.getUTCDate(),
19509 month = new_date.getUTCMonth(),
19510 mag = Math.abs(dir),
19512 dir = dir > 0 ? 1 : -1;
19515 // If going back one month, make sure month is not current month
19516 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19518 return new_date.getUTCMonth() == month;
19520 // If going forward one month, make sure month is as expected
19521 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19523 return new_date.getUTCMonth() != new_month;
19525 new_month = month + dir;
19526 new_date.setUTCMonth(new_month);
19527 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19528 if (new_month < 0 || new_month > 11) {
19529 new_month = (new_month + 12) % 12;
19532 // For magnitudes >1, move one month at a time...
19533 for (var i=0; i<mag; i++) {
19534 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19535 new_date = this.moveMonth(new_date, dir);
19537 // ...then reset the day, keeping it in the new month
19538 new_month = new_date.getUTCMonth();
19539 new_date.setUTCDate(day);
19541 return new_month != new_date.getUTCMonth();
19544 // Common date-resetting loop -- if date is beyond end of month, make it
19547 new_date.setUTCDate(--day);
19548 new_date.setUTCMonth(new_month);
19553 moveYear: function(date, dir)
19555 return this.moveMonth(date, dir*12);
19558 dateWithinRange: function(date)
19560 return date >= this.startDate && date <= this.endDate;
19566 this.picker().remove();
19569 validateValue : function(value)
19571 if(this.getVisibilityEl().hasClass('hidden')){
19575 if(value.length < 1) {
19576 if(this.allowBlank){
19582 if(value.length < this.minLength){
19585 if(value.length > this.maxLength){
19589 var vt = Roo.form.VTypes;
19590 if(!vt[this.vtype](value, this)){
19594 if(typeof this.validator == "function"){
19595 var msg = this.validator(value);
19601 if(this.regex && !this.regex.test(value)){
19605 if(typeof(this.parseDate(value)) == 'undefined'){
19609 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19613 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19623 this.date = this.viewDate = '';
19625 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19630 Roo.apply(Roo.bootstrap.DateField, {
19641 html: '<i class="fa fa-arrow-left"/>'
19651 html: '<i class="fa fa-arrow-right"/>'
19693 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19694 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19695 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19696 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19697 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19710 navFnc: 'FullYear',
19715 navFnc: 'FullYear',
19720 Roo.apply(Roo.bootstrap.DateField, {
19724 cls: 'datepicker dropdown-menu roo-dynamic',
19728 cls: 'datepicker-days',
19732 cls: 'table-condensed',
19734 Roo.bootstrap.DateField.head,
19738 Roo.bootstrap.DateField.footer
19745 cls: 'datepicker-months',
19749 cls: 'table-condensed',
19751 Roo.bootstrap.DateField.head,
19752 Roo.bootstrap.DateField.content,
19753 Roo.bootstrap.DateField.footer
19760 cls: 'datepicker-years',
19764 cls: 'table-condensed',
19766 Roo.bootstrap.DateField.head,
19767 Roo.bootstrap.DateField.content,
19768 Roo.bootstrap.DateField.footer
19787 * @class Roo.bootstrap.TimeField
19788 * @extends Roo.bootstrap.Input
19789 * Bootstrap DateField class
19793 * Create a new TimeField
19794 * @param {Object} config The config object
19797 Roo.bootstrap.TimeField = function(config){
19798 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19802 * Fires when this field show.
19803 * @param {Roo.bootstrap.DateField} thisthis
19804 * @param {Mixed} date The date value
19809 * Fires when this field hide.
19810 * @param {Roo.bootstrap.DateField} this
19811 * @param {Mixed} date The date value
19816 * Fires when select a date.
19817 * @param {Roo.bootstrap.DateField} this
19818 * @param {Mixed} date The date value
19824 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19827 * @cfg {String} format
19828 * The default time format string which can be overriden for localization support. The format must be
19829 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19833 onRender: function(ct, position)
19836 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19838 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19840 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19842 this.pop = this.picker().select('>.datepicker-time',true).first();
19843 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19845 this.picker().on('mousedown', this.onMousedown, this);
19846 this.picker().on('click', this.onClick, this);
19848 this.picker().addClass('datepicker-dropdown');
19853 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19854 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19855 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19856 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19857 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19858 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19862 fireKey: function(e){
19863 if (!this.picker().isVisible()){
19864 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19870 e.preventDefault();
19878 this.onTogglePeriod();
19881 this.onIncrementMinutes();
19884 this.onDecrementMinutes();
19893 onClick: function(e) {
19894 e.stopPropagation();
19895 e.preventDefault();
19898 picker : function()
19900 return this.el.select('.datepicker', true).first();
19903 fillTime: function()
19905 var time = this.pop.select('tbody', true).first();
19907 time.dom.innerHTML = '';
19922 cls: 'hours-up glyphicon glyphicon-chevron-up'
19942 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19963 cls: 'timepicker-hour',
19978 cls: 'timepicker-minute',
19993 cls: 'btn btn-primary period',
20015 cls: 'hours-down glyphicon glyphicon-chevron-down'
20035 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20053 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20060 var hours = this.time.getHours();
20061 var minutes = this.time.getMinutes();
20074 hours = hours - 12;
20078 hours = '0' + hours;
20082 minutes = '0' + minutes;
20085 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20086 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20087 this.pop.select('button', true).first().dom.innerHTML = period;
20093 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20095 var cls = ['bottom'];
20097 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20104 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20109 this.picker().addClass(cls.join('-'));
20113 Roo.each(cls, function(c){
20115 _this.picker().setTop(_this.inputEl().getHeight());
20119 _this.picker().setTop(0 - _this.picker().getHeight());
20124 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20128 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20135 onFocus : function()
20137 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20141 onBlur : function()
20143 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20149 this.picker().show();
20154 this.fireEvent('show', this, this.date);
20159 this.picker().hide();
20162 this.fireEvent('hide', this, this.date);
20165 setTime : function()
20168 this.setValue(this.time.format(this.format));
20170 this.fireEvent('select', this, this.date);
20175 onMousedown: function(e){
20176 e.stopPropagation();
20177 e.preventDefault();
20180 onIncrementHours: function()
20182 Roo.log('onIncrementHours');
20183 this.time = this.time.add(Date.HOUR, 1);
20188 onDecrementHours: function()
20190 Roo.log('onDecrementHours');
20191 this.time = this.time.add(Date.HOUR, -1);
20195 onIncrementMinutes: function()
20197 Roo.log('onIncrementMinutes');
20198 this.time = this.time.add(Date.MINUTE, 1);
20202 onDecrementMinutes: function()
20204 Roo.log('onDecrementMinutes');
20205 this.time = this.time.add(Date.MINUTE, -1);
20209 onTogglePeriod: function()
20211 Roo.log('onTogglePeriod');
20212 this.time = this.time.add(Date.HOUR, 12);
20219 Roo.apply(Roo.bootstrap.TimeField, {
20249 cls: 'btn btn-info ok',
20261 Roo.apply(Roo.bootstrap.TimeField, {
20265 cls: 'datepicker dropdown-menu',
20269 cls: 'datepicker-time',
20273 cls: 'table-condensed',
20275 Roo.bootstrap.TimeField.content,
20276 Roo.bootstrap.TimeField.footer
20295 * @class Roo.bootstrap.MonthField
20296 * @extends Roo.bootstrap.Input
20297 * Bootstrap MonthField class
20299 * @cfg {String} language default en
20302 * Create a new MonthField
20303 * @param {Object} config The config object
20306 Roo.bootstrap.MonthField = function(config){
20307 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20312 * Fires when this field show.
20313 * @param {Roo.bootstrap.MonthField} this
20314 * @param {Mixed} date The date value
20319 * Fires when this field hide.
20320 * @param {Roo.bootstrap.MonthField} this
20321 * @param {Mixed} date The date value
20326 * Fires when select a date.
20327 * @param {Roo.bootstrap.MonthField} this
20328 * @param {String} oldvalue The old value
20329 * @param {String} newvalue The new value
20335 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20337 onRender: function(ct, position)
20340 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20342 this.language = this.language || 'en';
20343 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20344 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20346 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20347 this.isInline = false;
20348 this.isInput = true;
20349 this.component = this.el.select('.add-on', true).first() || false;
20350 this.component = (this.component && this.component.length === 0) ? false : this.component;
20351 this.hasInput = this.component && this.inputEL().length;
20353 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20355 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20357 this.picker().on('mousedown', this.onMousedown, this);
20358 this.picker().on('click', this.onClick, this);
20360 this.picker().addClass('datepicker-dropdown');
20362 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20363 v.setStyle('width', '189px');
20370 if(this.isInline) {
20376 setValue: function(v, suppressEvent)
20378 var o = this.getValue();
20380 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20384 if(suppressEvent !== true){
20385 this.fireEvent('select', this, o, v);
20390 getValue: function()
20395 onClick: function(e)
20397 e.stopPropagation();
20398 e.preventDefault();
20400 var target = e.getTarget();
20402 if(target.nodeName.toLowerCase() === 'i'){
20403 target = Roo.get(target).dom.parentNode;
20406 var nodeName = target.nodeName;
20407 var className = target.className;
20408 var html = target.innerHTML;
20410 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20414 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20416 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20422 picker : function()
20424 return this.pickerEl;
20427 fillMonths: function()
20430 var months = this.picker().select('>.datepicker-months td', true).first();
20432 months.dom.innerHTML = '';
20438 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20441 months.createChild(month);
20450 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20451 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20454 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20455 e.removeClass('active');
20457 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20458 e.addClass('active');
20465 if(this.isInline) {
20469 this.picker().removeClass(['bottom', 'top']);
20471 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20473 * place to the top of element!
20477 this.picker().addClass('top');
20478 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20483 this.picker().addClass('bottom');
20485 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20488 onFocus : function()
20490 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20494 onBlur : function()
20496 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20498 var d = this.inputEl().getValue();
20507 this.picker().show();
20508 this.picker().select('>.datepicker-months', true).first().show();
20512 this.fireEvent('show', this, this.date);
20517 if(this.isInline) {
20520 this.picker().hide();
20521 this.fireEvent('hide', this, this.date);
20525 onMousedown: function(e)
20527 e.stopPropagation();
20528 e.preventDefault();
20533 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20537 fireKey: function(e)
20539 if (!this.picker().isVisible()){
20540 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20551 e.preventDefault();
20555 dir = e.keyCode == 37 ? -1 : 1;
20557 this.vIndex = this.vIndex + dir;
20559 if(this.vIndex < 0){
20563 if(this.vIndex > 11){
20567 if(isNaN(this.vIndex)){
20571 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20577 dir = e.keyCode == 38 ? -1 : 1;
20579 this.vIndex = this.vIndex + dir * 4;
20581 if(this.vIndex < 0){
20585 if(this.vIndex > 11){
20589 if(isNaN(this.vIndex)){
20593 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20598 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20599 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20603 e.preventDefault();
20606 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20607 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20623 this.picker().remove();
20628 Roo.apply(Roo.bootstrap.MonthField, {
20647 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20648 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20653 Roo.apply(Roo.bootstrap.MonthField, {
20657 cls: 'datepicker dropdown-menu roo-dynamic',
20661 cls: 'datepicker-months',
20665 cls: 'table-condensed',
20667 Roo.bootstrap.DateField.content
20687 * @class Roo.bootstrap.CheckBox
20688 * @extends Roo.bootstrap.Input
20689 * Bootstrap CheckBox class
20691 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20692 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20693 * @cfg {String} boxLabel The text that appears beside the checkbox
20694 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20695 * @cfg {Boolean} checked initnal the element
20696 * @cfg {Boolean} inline inline the element (default false)
20697 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20698 * @cfg {String} tooltip label tooltip
20701 * Create a new CheckBox
20702 * @param {Object} config The config object
20705 Roo.bootstrap.CheckBox = function(config){
20706 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20711 * Fires when the element is checked or unchecked.
20712 * @param {Roo.bootstrap.CheckBox} this This input
20713 * @param {Boolean} checked The new checked value
20718 * Fires when the element is click.
20719 * @param {Roo.bootstrap.CheckBox} this This input
20726 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20728 inputType: 'checkbox',
20737 getAutoCreate : function()
20739 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20745 cfg.cls = 'form-group ' + this.inputType; //input-group
20748 cfg.cls += ' ' + this.inputType + '-inline';
20754 type : this.inputType,
20755 value : this.inputValue,
20756 cls : 'roo-' + this.inputType, //'form-box',
20757 placeholder : this.placeholder || ''
20761 if(this.inputType != 'radio'){
20765 cls : 'roo-hidden-value',
20766 value : this.checked ? this.inputValue : this.valueOff
20771 if (this.weight) { // Validity check?
20772 cfg.cls += " " + this.inputType + "-" + this.weight;
20775 if (this.disabled) {
20776 input.disabled=true;
20780 input.checked = this.checked;
20785 input.name = this.name;
20787 if(this.inputType != 'radio'){
20788 hidden.name = this.name;
20789 input.name = '_hidden_' + this.name;
20794 input.cls += ' input-' + this.size;
20799 ['xs','sm','md','lg'].map(function(size){
20800 if (settings[size]) {
20801 cfg.cls += ' col-' + size + '-' + settings[size];
20805 var inputblock = input;
20807 if (this.before || this.after) {
20810 cls : 'input-group',
20815 inputblock.cn.push({
20817 cls : 'input-group-addon',
20822 inputblock.cn.push(input);
20824 if(this.inputType != 'radio'){
20825 inputblock.cn.push(hidden);
20829 inputblock.cn.push({
20831 cls : 'input-group-addon',
20838 if (align ==='left' && this.fieldLabel.length) {
20839 // Roo.log("left and has label");
20844 cls : 'control-label',
20845 html : this.fieldLabel
20855 if(this.labelWidth > 12){
20856 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20859 if(this.labelWidth < 13 && this.labelmd == 0){
20860 this.labelmd = this.labelWidth;
20863 if(this.labellg > 0){
20864 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20865 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20868 if(this.labelmd > 0){
20869 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20870 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20873 if(this.labelsm > 0){
20874 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20875 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20878 if(this.labelxs > 0){
20879 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20880 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20883 } else if ( this.fieldLabel.length) {
20884 // Roo.log(" label");
20888 tag: this.boxLabel ? 'span' : 'label',
20890 cls: 'control-label box-input-label',
20891 //cls : 'input-group-addon',
20892 html : this.fieldLabel
20901 // Roo.log(" no label && no align");
20902 cfg.cn = [ inputblock ] ;
20908 var boxLabelCfg = {
20910 //'for': id, // box label is handled by onclick - so no for...
20912 html: this.boxLabel
20916 boxLabelCfg.tooltip = this.tooltip;
20919 cfg.cn.push(boxLabelCfg);
20922 if(this.inputType != 'radio'){
20923 cfg.cn.push(hidden);
20931 * return the real input element.
20933 inputEl: function ()
20935 return this.el.select('input.roo-' + this.inputType,true).first();
20937 hiddenEl: function ()
20939 return this.el.select('input.roo-hidden-value',true).first();
20942 labelEl: function()
20944 return this.el.select('label.control-label',true).first();
20946 /* depricated... */
20950 return this.labelEl();
20953 boxLabelEl: function()
20955 return this.el.select('label.box-label',true).first();
20958 initEvents : function()
20960 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20962 this.inputEl().on('click', this.onClick, this);
20964 if (this.boxLabel) {
20965 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20968 this.startValue = this.getValue();
20971 Roo.bootstrap.CheckBox.register(this);
20975 onClick : function(e)
20977 if(this.fireEvent('click', this, e) !== false){
20978 this.setChecked(!this.checked);
20983 setChecked : function(state,suppressEvent)
20985 this.startValue = this.getValue();
20987 if(this.inputType == 'radio'){
20989 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
20990 e.dom.checked = false;
20993 this.inputEl().dom.checked = true;
20995 this.inputEl().dom.value = this.inputValue;
20997 if(suppressEvent !== true){
20998 this.fireEvent('check', this, true);
21006 this.checked = state;
21008 this.inputEl().dom.checked = state;
21011 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21013 if(suppressEvent !== true){
21014 this.fireEvent('check', this, state);
21020 getValue : function()
21022 if(this.inputType == 'radio'){
21023 return this.getGroupValue();
21026 return this.hiddenEl().dom.value;
21030 getGroupValue : function()
21032 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21036 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21039 setValue : function(v,suppressEvent)
21041 if(this.inputType == 'radio'){
21042 this.setGroupValue(v, suppressEvent);
21046 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21051 setGroupValue : function(v, suppressEvent)
21053 this.startValue = this.getValue();
21055 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21056 e.dom.checked = false;
21058 if(e.dom.value == v){
21059 e.dom.checked = true;
21063 if(suppressEvent !== true){
21064 this.fireEvent('check', this, true);
21072 validate : function()
21074 if(this.getVisibilityEl().hasClass('hidden')){
21080 (this.inputType == 'radio' && this.validateRadio()) ||
21081 (this.inputType == 'checkbox' && this.validateCheckbox())
21087 this.markInvalid();
21091 validateRadio : function()
21093 if(this.getVisibilityEl().hasClass('hidden')){
21097 if(this.allowBlank){
21103 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21104 if(!e.dom.checked){
21116 validateCheckbox : function()
21119 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21120 //return (this.getValue() == this.inputValue) ? true : false;
21123 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21131 for(var i in group){
21132 if(group[i].el.isVisible(true)){
21140 for(var i in group){
21145 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21152 * Mark this field as valid
21154 markValid : function()
21158 this.fireEvent('valid', this);
21160 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21163 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21170 if(this.inputType == 'radio'){
21171 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21172 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21173 e.findParent('.form-group', false, true).addClass(_this.validClass);
21180 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21181 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21185 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21191 for(var i in group){
21192 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21193 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21198 * Mark this field as invalid
21199 * @param {String} msg The validation message
21201 markInvalid : function(msg)
21203 if(this.allowBlank){
21209 this.fireEvent('invalid', this, msg);
21211 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21214 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21218 label.markInvalid();
21221 if(this.inputType == 'radio'){
21222 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21223 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21224 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21231 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21232 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21236 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21242 for(var i in group){
21243 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21244 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21249 clearInvalid : function()
21251 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21253 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21255 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21257 if (label && label.iconEl) {
21258 label.iconEl.removeClass(label.validClass);
21259 label.iconEl.removeClass(label.invalidClass);
21263 disable : function()
21265 if(this.inputType != 'radio'){
21266 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21273 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21274 _this.getActionEl().addClass(this.disabledClass);
21275 e.dom.disabled = true;
21279 this.disabled = true;
21280 this.fireEvent("disable", this);
21284 enable : function()
21286 if(this.inputType != 'radio'){
21287 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21294 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21295 _this.getActionEl().removeClass(this.disabledClass);
21296 e.dom.disabled = false;
21300 this.disabled = false;
21301 this.fireEvent("enable", this);
21305 setBoxLabel : function(v)
21310 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21316 Roo.apply(Roo.bootstrap.CheckBox, {
21321 * register a CheckBox Group
21322 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21324 register : function(checkbox)
21326 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21327 this.groups[checkbox.groupId] = {};
21330 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21334 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21338 * fetch a CheckBox Group based on the group ID
21339 * @param {string} the group ID
21340 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21342 get: function(groupId) {
21343 if (typeof(this.groups[groupId]) == 'undefined') {
21347 return this.groups[groupId] ;
21360 * @class Roo.bootstrap.Radio
21361 * @extends Roo.bootstrap.Component
21362 * Bootstrap Radio class
21363 * @cfg {String} boxLabel - the label associated
21364 * @cfg {String} value - the value of radio
21367 * Create a new Radio
21368 * @param {Object} config The config object
21370 Roo.bootstrap.Radio = function(config){
21371 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21375 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21381 getAutoCreate : function()
21385 cls : 'form-group radio',
21390 html : this.boxLabel
21398 initEvents : function()
21400 this.parent().register(this);
21402 this.el.on('click', this.onClick, this);
21406 onClick : function(e)
21408 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21409 this.setChecked(true);
21413 setChecked : function(state, suppressEvent)
21415 this.parent().setValue(this.value, suppressEvent);
21419 setBoxLabel : function(v)
21424 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21439 * @class Roo.bootstrap.SecurePass
21440 * @extends Roo.bootstrap.Input
21441 * Bootstrap SecurePass class
21445 * Create a new SecurePass
21446 * @param {Object} config The config object
21449 Roo.bootstrap.SecurePass = function (config) {
21450 // these go here, so the translation tool can replace them..
21452 PwdEmpty: "Please type a password, and then retype it to confirm.",
21453 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21454 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21455 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21456 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21457 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21458 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21459 TooWeak: "Your password is Too Weak."
21461 this.meterLabel = "Password strength:";
21462 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21463 this.meterClass = [
21464 "roo-password-meter-tooweak",
21465 "roo-password-meter-weak",
21466 "roo-password-meter-medium",
21467 "roo-password-meter-strong",
21468 "roo-password-meter-grey"
21473 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21476 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21478 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21480 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21481 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21482 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21483 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21484 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21485 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21486 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21496 * @cfg {String/Object} Label for the strength meter (defaults to
21497 * 'Password strength:')
21502 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21503 * ['Weak', 'Medium', 'Strong'])
21506 pwdStrengths: false,
21519 initEvents: function ()
21521 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21523 if (this.el.is('input[type=password]') && Roo.isSafari) {
21524 this.el.on('keydown', this.SafariOnKeyDown, this);
21527 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21530 onRender: function (ct, position)
21532 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21533 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21534 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21536 this.trigger.createChild({
21541 cls: 'roo-password-meter-grey col-xs-12',
21544 //width: this.meterWidth + 'px'
21548 cls: 'roo-password-meter-text'
21554 if (this.hideTrigger) {
21555 this.trigger.setDisplayed(false);
21557 this.setSize(this.width || '', this.height || '');
21560 onDestroy: function ()
21562 if (this.trigger) {
21563 this.trigger.removeAllListeners();
21564 this.trigger.remove();
21567 this.wrap.remove();
21569 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21572 checkStrength: function ()
21574 var pwd = this.inputEl().getValue();
21575 if (pwd == this._lastPwd) {
21580 if (this.ClientSideStrongPassword(pwd)) {
21582 } else if (this.ClientSideMediumPassword(pwd)) {
21584 } else if (this.ClientSideWeakPassword(pwd)) {
21590 Roo.log('strength1: ' + strength);
21592 //var pm = this.trigger.child('div/div/div').dom;
21593 var pm = this.trigger.child('div/div');
21594 pm.removeClass(this.meterClass);
21595 pm.addClass(this.meterClass[strength]);
21598 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21600 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21602 this._lastPwd = pwd;
21606 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21608 this._lastPwd = '';
21610 var pm = this.trigger.child('div/div');
21611 pm.removeClass(this.meterClass);
21612 pm.addClass('roo-password-meter-grey');
21615 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21618 this.inputEl().dom.type='password';
21621 validateValue: function (value)
21624 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21627 if (value.length == 0) {
21628 if (this.allowBlank) {
21629 this.clearInvalid();
21633 this.markInvalid(this.errors.PwdEmpty);
21634 this.errorMsg = this.errors.PwdEmpty;
21642 if ('[\x21-\x7e]*'.match(value)) {
21643 this.markInvalid(this.errors.PwdBadChar);
21644 this.errorMsg = this.errors.PwdBadChar;
21647 if (value.length < 6) {
21648 this.markInvalid(this.errors.PwdShort);
21649 this.errorMsg = this.errors.PwdShort;
21652 if (value.length > 16) {
21653 this.markInvalid(this.errors.PwdLong);
21654 this.errorMsg = this.errors.PwdLong;
21658 if (this.ClientSideStrongPassword(value)) {
21660 } else if (this.ClientSideMediumPassword(value)) {
21662 } else if (this.ClientSideWeakPassword(value)) {
21669 if (strength < 2) {
21670 //this.markInvalid(this.errors.TooWeak);
21671 this.errorMsg = this.errors.TooWeak;
21676 console.log('strength2: ' + strength);
21678 //var pm = this.trigger.child('div/div/div').dom;
21680 var pm = this.trigger.child('div/div');
21681 pm.removeClass(this.meterClass);
21682 pm.addClass(this.meterClass[strength]);
21684 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21686 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21688 this.errorMsg = '';
21692 CharacterSetChecks: function (type)
21695 this.fResult = false;
21698 isctype: function (character, type)
21701 case this.kCapitalLetter:
21702 if (character >= 'A' && character <= 'Z') {
21707 case this.kSmallLetter:
21708 if (character >= 'a' && character <= 'z') {
21714 if (character >= '0' && character <= '9') {
21719 case this.kPunctuation:
21720 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21731 IsLongEnough: function (pwd, size)
21733 return !(pwd == null || isNaN(size) || pwd.length < size);
21736 SpansEnoughCharacterSets: function (word, nb)
21738 if (!this.IsLongEnough(word, nb))
21743 var characterSetChecks = new Array(
21744 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21745 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21748 for (var index = 0; index < word.length; ++index) {
21749 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21750 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21751 characterSetChecks[nCharSet].fResult = true;
21758 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21759 if (characterSetChecks[nCharSet].fResult) {
21764 if (nCharSets < nb) {
21770 ClientSideStrongPassword: function (pwd)
21772 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21775 ClientSideMediumPassword: function (pwd)
21777 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21780 ClientSideWeakPassword: function (pwd)
21782 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21785 })//<script type="text/javascript">
21788 * Based Ext JS Library 1.1.1
21789 * Copyright(c) 2006-2007, Ext JS, LLC.
21795 * @class Roo.HtmlEditorCore
21796 * @extends Roo.Component
21797 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21799 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21802 Roo.HtmlEditorCore = function(config){
21805 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21810 * @event initialize
21811 * Fires when the editor is fully initialized (including the iframe)
21812 * @param {Roo.HtmlEditorCore} this
21817 * Fires when the editor is first receives the focus. Any insertion must wait
21818 * until after this event.
21819 * @param {Roo.HtmlEditorCore} this
21823 * @event beforesync
21824 * Fires before the textarea is updated with content from the editor iframe. Return false
21825 * to cancel the sync.
21826 * @param {Roo.HtmlEditorCore} this
21827 * @param {String} html
21831 * @event beforepush
21832 * Fires before the iframe editor is updated with content from the textarea. Return false
21833 * to cancel the push.
21834 * @param {Roo.HtmlEditorCore} this
21835 * @param {String} html
21840 * Fires when the textarea is updated with content from the editor iframe.
21841 * @param {Roo.HtmlEditorCore} this
21842 * @param {String} html
21847 * Fires when the iframe editor is updated with content from the textarea.
21848 * @param {Roo.HtmlEditorCore} this
21849 * @param {String} html
21854 * @event editorevent
21855 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21856 * @param {Roo.HtmlEditorCore} this
21862 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21864 // defaults : white / black...
21865 this.applyBlacklists();
21872 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21876 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21882 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21887 * @cfg {Number} height (in pixels)
21891 * @cfg {Number} width (in pixels)
21896 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21899 stylesheets: false,
21904 // private properties
21905 validationEvent : false,
21907 initialized : false,
21909 sourceEditMode : false,
21910 onFocus : Roo.emptyFn,
21912 hideMode:'offsets',
21916 // blacklist + whitelisted elements..
21923 * Protected method that will not generally be called directly. It
21924 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21925 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21927 getDocMarkup : function(){
21931 // inherit styels from page...??
21932 if (this.stylesheets === false) {
21934 Roo.get(document.head).select('style').each(function(node) {
21935 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21938 Roo.get(document.head).select('link').each(function(node) {
21939 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21942 } else if (!this.stylesheets.length) {
21944 st = '<style type="text/css">' +
21945 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21948 st = '<style type="text/css">' +
21953 st += '<style type="text/css">' +
21954 'IMG { cursor: pointer } ' +
21957 var cls = 'roo-htmleditor-body';
21959 if(this.bodyCls.length){
21960 cls += ' ' + this.bodyCls;
21963 return '<html><head>' + st +
21964 //<style type="text/css">' +
21965 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21967 ' </head><body class="' + cls + '"></body></html>';
21971 onRender : function(ct, position)
21974 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
21975 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
21978 this.el.dom.style.border = '0 none';
21979 this.el.dom.setAttribute('tabIndex', -1);
21980 this.el.addClass('x-hidden hide');
21984 if(Roo.isIE){ // fix IE 1px bogus margin
21985 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
21989 this.frameId = Roo.id();
21993 var iframe = this.owner.wrap.createChild({
21995 cls: 'form-control', // bootstrap..
21997 name: this.frameId,
21998 frameBorder : 'no',
21999 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22004 this.iframe = iframe.dom;
22006 this.assignDocWin();
22008 this.doc.designMode = 'on';
22011 this.doc.write(this.getDocMarkup());
22015 var task = { // must defer to wait for browser to be ready
22017 //console.log("run task?" + this.doc.readyState);
22018 this.assignDocWin();
22019 if(this.doc.body || this.doc.readyState == 'complete'){
22021 this.doc.designMode="on";
22025 Roo.TaskMgr.stop(task);
22026 this.initEditor.defer(10, this);
22033 Roo.TaskMgr.start(task);
22038 onResize : function(w, h)
22040 Roo.log('resize: ' +w + ',' + h );
22041 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22045 if(typeof w == 'number'){
22047 this.iframe.style.width = w + 'px';
22049 if(typeof h == 'number'){
22051 this.iframe.style.height = h + 'px';
22053 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22060 * Toggles the editor between standard and source edit mode.
22061 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22063 toggleSourceEdit : function(sourceEditMode){
22065 this.sourceEditMode = sourceEditMode === true;
22067 if(this.sourceEditMode){
22069 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22072 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22073 //this.iframe.className = '';
22076 //this.setSize(this.owner.wrap.getSize());
22077 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22084 * Protected method that will not generally be called directly. If you need/want
22085 * custom HTML cleanup, this is the method you should override.
22086 * @param {String} html The HTML to be cleaned
22087 * return {String} The cleaned HTML
22089 cleanHtml : function(html){
22090 html = String(html);
22091 if(html.length > 5){
22092 if(Roo.isSafari){ // strip safari nonsense
22093 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22096 if(html == ' '){
22103 * HTML Editor -> Textarea
22104 * Protected method that will not generally be called directly. Syncs the contents
22105 * of the editor iframe with the textarea.
22107 syncValue : function(){
22108 if(this.initialized){
22109 var bd = (this.doc.body || this.doc.documentElement);
22110 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22111 var html = bd.innerHTML;
22113 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22114 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22116 html = '<div style="'+m[0]+'">' + html + '</div>';
22119 html = this.cleanHtml(html);
22120 // fix up the special chars.. normaly like back quotes in word...
22121 // however we do not want to do this with chinese..
22122 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22123 var cc = b.charCodeAt();
22125 (cc >= 0x4E00 && cc < 0xA000 ) ||
22126 (cc >= 0x3400 && cc < 0x4E00 ) ||
22127 (cc >= 0xf900 && cc < 0xfb00 )
22133 if(this.owner.fireEvent('beforesync', this, html) !== false){
22134 this.el.dom.value = html;
22135 this.owner.fireEvent('sync', this, html);
22141 * Protected method that will not generally be called directly. Pushes the value of the textarea
22142 * into the iframe editor.
22144 pushValue : function(){
22145 if(this.initialized){
22146 var v = this.el.dom.value.trim();
22148 // if(v.length < 1){
22152 if(this.owner.fireEvent('beforepush', this, v) !== false){
22153 var d = (this.doc.body || this.doc.documentElement);
22155 this.cleanUpPaste();
22156 this.el.dom.value = d.innerHTML;
22157 this.owner.fireEvent('push', this, v);
22163 deferFocus : function(){
22164 this.focus.defer(10, this);
22168 focus : function(){
22169 if(this.win && !this.sourceEditMode){
22176 assignDocWin: function()
22178 var iframe = this.iframe;
22181 this.doc = iframe.contentWindow.document;
22182 this.win = iframe.contentWindow;
22184 // if (!Roo.get(this.frameId)) {
22187 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22188 // this.win = Roo.get(this.frameId).dom.contentWindow;
22190 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22194 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22195 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22200 initEditor : function(){
22201 //console.log("INIT EDITOR");
22202 this.assignDocWin();
22206 this.doc.designMode="on";
22208 this.doc.write(this.getDocMarkup());
22211 var dbody = (this.doc.body || this.doc.documentElement);
22212 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22213 // this copies styles from the containing element into thsi one..
22214 // not sure why we need all of this..
22215 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22217 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22218 //ss['background-attachment'] = 'fixed'; // w3c
22219 dbody.bgProperties = 'fixed'; // ie
22220 //Roo.DomHelper.applyStyles(dbody, ss);
22221 Roo.EventManager.on(this.doc, {
22222 //'mousedown': this.onEditorEvent,
22223 'mouseup': this.onEditorEvent,
22224 'dblclick': this.onEditorEvent,
22225 'click': this.onEditorEvent,
22226 'keyup': this.onEditorEvent,
22231 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22233 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22234 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22236 this.initialized = true;
22238 this.owner.fireEvent('initialize', this);
22243 onDestroy : function(){
22249 //for (var i =0; i < this.toolbars.length;i++) {
22250 // // fixme - ask toolbars for heights?
22251 // this.toolbars[i].onDestroy();
22254 //this.wrap.dom.innerHTML = '';
22255 //this.wrap.remove();
22260 onFirstFocus : function(){
22262 this.assignDocWin();
22265 this.activated = true;
22268 if(Roo.isGecko){ // prevent silly gecko errors
22270 var s = this.win.getSelection();
22271 if(!s.focusNode || s.focusNode.nodeType != 3){
22272 var r = s.getRangeAt(0);
22273 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22278 this.execCmd('useCSS', true);
22279 this.execCmd('styleWithCSS', false);
22282 this.owner.fireEvent('activate', this);
22286 adjustFont: function(btn){
22287 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22288 //if(Roo.isSafari){ // safari
22291 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22292 if(Roo.isSafari){ // safari
22293 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22294 v = (v < 10) ? 10 : v;
22295 v = (v > 48) ? 48 : v;
22296 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22301 v = Math.max(1, v+adjust);
22303 this.execCmd('FontSize', v );
22306 onEditorEvent : function(e)
22308 this.owner.fireEvent('editorevent', this, e);
22309 // this.updateToolbar();
22310 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22313 insertTag : function(tg)
22315 // could be a bit smarter... -> wrap the current selected tRoo..
22316 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22318 range = this.createRange(this.getSelection());
22319 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22320 wrappingNode.appendChild(range.extractContents());
22321 range.insertNode(wrappingNode);
22328 this.execCmd("formatblock", tg);
22332 insertText : function(txt)
22336 var range = this.createRange();
22337 range.deleteContents();
22338 //alert(Sender.getAttribute('label'));
22340 range.insertNode(this.doc.createTextNode(txt));
22346 * Executes a Midas editor command on the editor document and performs necessary focus and
22347 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22348 * @param {String} cmd The Midas command
22349 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22351 relayCmd : function(cmd, value){
22353 this.execCmd(cmd, value);
22354 this.owner.fireEvent('editorevent', this);
22355 //this.updateToolbar();
22356 this.owner.deferFocus();
22360 * Executes a Midas editor command directly on the editor document.
22361 * For visual commands, you should use {@link #relayCmd} instead.
22362 * <b>This should only be called after the editor is initialized.</b>
22363 * @param {String} cmd The Midas command
22364 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22366 execCmd : function(cmd, value){
22367 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22374 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22376 * @param {String} text | dom node..
22378 insertAtCursor : function(text)
22381 if(!this.activated){
22387 var r = this.doc.selection.createRange();
22398 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22402 // from jquery ui (MIT licenced)
22404 var win = this.win;
22406 if (win.getSelection && win.getSelection().getRangeAt) {
22407 range = win.getSelection().getRangeAt(0);
22408 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22409 range.insertNode(node);
22410 } else if (win.document.selection && win.document.selection.createRange) {
22411 // no firefox support
22412 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22413 win.document.selection.createRange().pasteHTML(txt);
22415 // no firefox support
22416 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22417 this.execCmd('InsertHTML', txt);
22426 mozKeyPress : function(e){
22428 var c = e.getCharCode(), cmd;
22431 c = String.fromCharCode(c).toLowerCase();
22445 this.cleanUpPaste.defer(100, this);
22453 e.preventDefault();
22461 fixKeys : function(){ // load time branching for fastest keydown performance
22463 return function(e){
22464 var k = e.getKey(), r;
22467 r = this.doc.selection.createRange();
22470 r.pasteHTML('    ');
22477 r = this.doc.selection.createRange();
22479 var target = r.parentElement();
22480 if(!target || target.tagName.toLowerCase() != 'li'){
22482 r.pasteHTML('<br />');
22488 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22489 this.cleanUpPaste.defer(100, this);
22495 }else if(Roo.isOpera){
22496 return function(e){
22497 var k = e.getKey();
22501 this.execCmd('InsertHTML','    ');
22504 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22505 this.cleanUpPaste.defer(100, this);
22510 }else if(Roo.isSafari){
22511 return function(e){
22512 var k = e.getKey();
22516 this.execCmd('InsertText','\t');
22520 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22521 this.cleanUpPaste.defer(100, this);
22529 getAllAncestors: function()
22531 var p = this.getSelectedNode();
22534 a.push(p); // push blank onto stack..
22535 p = this.getParentElement();
22539 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22543 a.push(this.doc.body);
22547 lastSelNode : false,
22550 getSelection : function()
22552 this.assignDocWin();
22553 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22556 getSelectedNode: function()
22558 // this may only work on Gecko!!!
22560 // should we cache this!!!!
22565 var range = this.createRange(this.getSelection()).cloneRange();
22568 var parent = range.parentElement();
22570 var testRange = range.duplicate();
22571 testRange.moveToElementText(parent);
22572 if (testRange.inRange(range)) {
22575 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22578 parent = parent.parentElement;
22583 // is ancestor a text element.
22584 var ac = range.commonAncestorContainer;
22585 if (ac.nodeType == 3) {
22586 ac = ac.parentNode;
22589 var ar = ac.childNodes;
22592 var other_nodes = [];
22593 var has_other_nodes = false;
22594 for (var i=0;i<ar.length;i++) {
22595 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22598 // fullly contained node.
22600 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22605 // probably selected..
22606 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22607 other_nodes.push(ar[i]);
22611 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22616 has_other_nodes = true;
22618 if (!nodes.length && other_nodes.length) {
22619 nodes= other_nodes;
22621 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22627 createRange: function(sel)
22629 // this has strange effects when using with
22630 // top toolbar - not sure if it's a great idea.
22631 //this.editor.contentWindow.focus();
22632 if (typeof sel != "undefined") {
22634 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22636 return this.doc.createRange();
22639 return this.doc.createRange();
22642 getParentElement: function()
22645 this.assignDocWin();
22646 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22648 var range = this.createRange(sel);
22651 var p = range.commonAncestorContainer;
22652 while (p.nodeType == 3) { // text node
22663 * Range intersection.. the hard stuff...
22667 * [ -- selected range --- ]
22671 * if end is before start or hits it. fail.
22672 * if start is after end or hits it fail.
22674 * if either hits (but other is outside. - then it's not
22680 // @see http://www.thismuchiknow.co.uk/?p=64.
22681 rangeIntersectsNode : function(range, node)
22683 var nodeRange = node.ownerDocument.createRange();
22685 nodeRange.selectNode(node);
22687 nodeRange.selectNodeContents(node);
22690 var rangeStartRange = range.cloneRange();
22691 rangeStartRange.collapse(true);
22693 var rangeEndRange = range.cloneRange();
22694 rangeEndRange.collapse(false);
22696 var nodeStartRange = nodeRange.cloneRange();
22697 nodeStartRange.collapse(true);
22699 var nodeEndRange = nodeRange.cloneRange();
22700 nodeEndRange.collapse(false);
22702 return rangeStartRange.compareBoundaryPoints(
22703 Range.START_TO_START, nodeEndRange) == -1 &&
22704 rangeEndRange.compareBoundaryPoints(
22705 Range.START_TO_START, nodeStartRange) == 1;
22709 rangeCompareNode : function(range, node)
22711 var nodeRange = node.ownerDocument.createRange();
22713 nodeRange.selectNode(node);
22715 nodeRange.selectNodeContents(node);
22719 range.collapse(true);
22721 nodeRange.collapse(true);
22723 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22724 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22726 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22728 var nodeIsBefore = ss == 1;
22729 var nodeIsAfter = ee == -1;
22731 if (nodeIsBefore && nodeIsAfter) {
22734 if (!nodeIsBefore && nodeIsAfter) {
22735 return 1; //right trailed.
22738 if (nodeIsBefore && !nodeIsAfter) {
22739 return 2; // left trailed.
22745 // private? - in a new class?
22746 cleanUpPaste : function()
22748 // cleans up the whole document..
22749 Roo.log('cleanuppaste');
22751 this.cleanUpChildren(this.doc.body);
22752 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22753 if (clean != this.doc.body.innerHTML) {
22754 this.doc.body.innerHTML = clean;
22759 cleanWordChars : function(input) {// change the chars to hex code
22760 var he = Roo.HtmlEditorCore;
22762 var output = input;
22763 Roo.each(he.swapCodes, function(sw) {
22764 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22766 output = output.replace(swapper, sw[1]);
22773 cleanUpChildren : function (n)
22775 if (!n.childNodes.length) {
22778 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22779 this.cleanUpChild(n.childNodes[i]);
22786 cleanUpChild : function (node)
22789 //console.log(node);
22790 if (node.nodeName == "#text") {
22791 // clean up silly Windows -- stuff?
22794 if (node.nodeName == "#comment") {
22795 node.parentNode.removeChild(node);
22796 // clean up silly Windows -- stuff?
22799 var lcname = node.tagName.toLowerCase();
22800 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22801 // whitelist of tags..
22803 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22805 node.parentNode.removeChild(node);
22810 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22812 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22813 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22815 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22816 // remove_keep_children = true;
22819 if (remove_keep_children) {
22820 this.cleanUpChildren(node);
22821 // inserts everything just before this node...
22822 while (node.childNodes.length) {
22823 var cn = node.childNodes[0];
22824 node.removeChild(cn);
22825 node.parentNode.insertBefore(cn, node);
22827 node.parentNode.removeChild(node);
22831 if (!node.attributes || !node.attributes.length) {
22832 this.cleanUpChildren(node);
22836 function cleanAttr(n,v)
22839 if (v.match(/^\./) || v.match(/^\//)) {
22842 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22845 if (v.match(/^#/)) {
22848 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22849 node.removeAttribute(n);
22853 var cwhite = this.cwhite;
22854 var cblack = this.cblack;
22856 function cleanStyle(n,v)
22858 if (v.match(/expression/)) { //XSS?? should we even bother..
22859 node.removeAttribute(n);
22863 var parts = v.split(/;/);
22866 Roo.each(parts, function(p) {
22867 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22871 var l = p.split(':').shift().replace(/\s+/g,'');
22872 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22874 if ( cwhite.length && cblack.indexOf(l) > -1) {
22875 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22876 //node.removeAttribute(n);
22880 // only allow 'c whitelisted system attributes'
22881 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22882 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22883 //node.removeAttribute(n);
22893 if (clean.length) {
22894 node.setAttribute(n, clean.join(';'));
22896 node.removeAttribute(n);
22902 for (var i = node.attributes.length-1; i > -1 ; i--) {
22903 var a = node.attributes[i];
22906 if (a.name.toLowerCase().substr(0,2)=='on') {
22907 node.removeAttribute(a.name);
22910 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22911 node.removeAttribute(a.name);
22914 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22915 cleanAttr(a.name,a.value); // fixme..
22918 if (a.name == 'style') {
22919 cleanStyle(a.name,a.value);
22922 /// clean up MS crap..
22923 // tecnically this should be a list of valid class'es..
22926 if (a.name == 'class') {
22927 if (a.value.match(/^Mso/)) {
22928 node.className = '';
22931 if (a.value.match(/^body$/)) {
22932 node.className = '';
22943 this.cleanUpChildren(node);
22949 * Clean up MS wordisms...
22951 cleanWord : function(node)
22956 this.cleanWord(this.doc.body);
22959 if (node.nodeName == "#text") {
22960 // clean up silly Windows -- stuff?
22963 if (node.nodeName == "#comment") {
22964 node.parentNode.removeChild(node);
22965 // clean up silly Windows -- stuff?
22969 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22970 node.parentNode.removeChild(node);
22974 // remove - but keep children..
22975 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
22976 while (node.childNodes.length) {
22977 var cn = node.childNodes[0];
22978 node.removeChild(cn);
22979 node.parentNode.insertBefore(cn, node);
22981 node.parentNode.removeChild(node);
22982 this.iterateChildren(node, this.cleanWord);
22986 if (node.className.length) {
22988 var cn = node.className.split(/\W+/);
22990 Roo.each(cn, function(cls) {
22991 if (cls.match(/Mso[a-zA-Z]+/)) {
22996 node.className = cna.length ? cna.join(' ') : '';
22998 node.removeAttribute("class");
23002 if (node.hasAttribute("lang")) {
23003 node.removeAttribute("lang");
23006 if (node.hasAttribute("style")) {
23008 var styles = node.getAttribute("style").split(";");
23010 Roo.each(styles, function(s) {
23011 if (!s.match(/:/)) {
23014 var kv = s.split(":");
23015 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23018 // what ever is left... we allow.
23021 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23022 if (!nstyle.length) {
23023 node.removeAttribute('style');
23026 this.iterateChildren(node, this.cleanWord);
23032 * iterateChildren of a Node, calling fn each time, using this as the scole..
23033 * @param {DomNode} node node to iterate children of.
23034 * @param {Function} fn method of this class to call on each item.
23036 iterateChildren : function(node, fn)
23038 if (!node.childNodes.length) {
23041 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23042 fn.call(this, node.childNodes[i])
23048 * cleanTableWidths.
23050 * Quite often pasting from word etc.. results in tables with column and widths.
23051 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23054 cleanTableWidths : function(node)
23059 this.cleanTableWidths(this.doc.body);
23064 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23067 Roo.log(node.tagName);
23068 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23069 this.iterateChildren(node, this.cleanTableWidths);
23072 if (node.hasAttribute('width')) {
23073 node.removeAttribute('width');
23077 if (node.hasAttribute("style")) {
23080 var styles = node.getAttribute("style").split(";");
23082 Roo.each(styles, function(s) {
23083 if (!s.match(/:/)) {
23086 var kv = s.split(":");
23087 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23090 // what ever is left... we allow.
23093 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23094 if (!nstyle.length) {
23095 node.removeAttribute('style');
23099 this.iterateChildren(node, this.cleanTableWidths);
23107 domToHTML : function(currentElement, depth, nopadtext) {
23109 depth = depth || 0;
23110 nopadtext = nopadtext || false;
23112 if (!currentElement) {
23113 return this.domToHTML(this.doc.body);
23116 //Roo.log(currentElement);
23118 var allText = false;
23119 var nodeName = currentElement.nodeName;
23120 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23122 if (nodeName == '#text') {
23124 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23129 if (nodeName != 'BODY') {
23132 // Prints the node tagName, such as <A>, <IMG>, etc
23135 for(i = 0; i < currentElement.attributes.length;i++) {
23137 var aname = currentElement.attributes.item(i).name;
23138 if (!currentElement.attributes.item(i).value.length) {
23141 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23144 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23153 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23156 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23161 // Traverse the tree
23163 var currentElementChild = currentElement.childNodes.item(i);
23164 var allText = true;
23165 var innerHTML = '';
23167 while (currentElementChild) {
23168 // Formatting code (indent the tree so it looks nice on the screen)
23169 var nopad = nopadtext;
23170 if (lastnode == 'SPAN') {
23174 if (currentElementChild.nodeName == '#text') {
23175 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23176 toadd = nopadtext ? toadd : toadd.trim();
23177 if (!nopad && toadd.length > 80) {
23178 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23180 innerHTML += toadd;
23183 currentElementChild = currentElement.childNodes.item(i);
23189 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23191 // Recursively traverse the tree structure of the child node
23192 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23193 lastnode = currentElementChild.nodeName;
23195 currentElementChild=currentElement.childNodes.item(i);
23201 // The remaining code is mostly for formatting the tree
23202 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23207 ret+= "</"+tagName+">";
23213 applyBlacklists : function()
23215 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23216 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23220 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23221 if (b.indexOf(tag) > -1) {
23224 this.white.push(tag);
23228 Roo.each(w, function(tag) {
23229 if (b.indexOf(tag) > -1) {
23232 if (this.white.indexOf(tag) > -1) {
23235 this.white.push(tag);
23240 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23241 if (w.indexOf(tag) > -1) {
23244 this.black.push(tag);
23248 Roo.each(b, function(tag) {
23249 if (w.indexOf(tag) > -1) {
23252 if (this.black.indexOf(tag) > -1) {
23255 this.black.push(tag);
23260 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23261 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23265 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23266 if (b.indexOf(tag) > -1) {
23269 this.cwhite.push(tag);
23273 Roo.each(w, function(tag) {
23274 if (b.indexOf(tag) > -1) {
23277 if (this.cwhite.indexOf(tag) > -1) {
23280 this.cwhite.push(tag);
23285 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23286 if (w.indexOf(tag) > -1) {
23289 this.cblack.push(tag);
23293 Roo.each(b, function(tag) {
23294 if (w.indexOf(tag) > -1) {
23297 if (this.cblack.indexOf(tag) > -1) {
23300 this.cblack.push(tag);
23305 setStylesheets : function(stylesheets)
23307 if(typeof(stylesheets) == 'string'){
23308 Roo.get(this.iframe.contentDocument.head).createChild({
23310 rel : 'stylesheet',
23319 Roo.each(stylesheets, function(s) {
23324 Roo.get(_this.iframe.contentDocument.head).createChild({
23326 rel : 'stylesheet',
23335 removeStylesheets : function()
23339 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23344 setStyle : function(style)
23346 Roo.get(this.iframe.contentDocument.head).createChild({
23355 // hide stuff that is not compatible
23369 * @event specialkey
23373 * @cfg {String} fieldClass @hide
23376 * @cfg {String} focusClass @hide
23379 * @cfg {String} autoCreate @hide
23382 * @cfg {String} inputType @hide
23385 * @cfg {String} invalidClass @hide
23388 * @cfg {String} invalidText @hide
23391 * @cfg {String} msgFx @hide
23394 * @cfg {String} validateOnBlur @hide
23398 Roo.HtmlEditorCore.white = [
23399 'area', 'br', 'img', 'input', 'hr', 'wbr',
23401 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23402 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23403 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23404 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23405 'table', 'ul', 'xmp',
23407 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23410 'dir', 'menu', 'ol', 'ul', 'dl',
23416 Roo.HtmlEditorCore.black = [
23417 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23419 'base', 'basefont', 'bgsound', 'blink', 'body',
23420 'frame', 'frameset', 'head', 'html', 'ilayer',
23421 'iframe', 'layer', 'link', 'meta', 'object',
23422 'script', 'style' ,'title', 'xml' // clean later..
23424 Roo.HtmlEditorCore.clean = [
23425 'script', 'style', 'title', 'xml'
23427 Roo.HtmlEditorCore.remove = [
23432 Roo.HtmlEditorCore.ablack = [
23436 Roo.HtmlEditorCore.aclean = [
23437 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23441 Roo.HtmlEditorCore.pwhite= [
23442 'http', 'https', 'mailto'
23445 // white listed style attributes.
23446 Roo.HtmlEditorCore.cwhite= [
23447 // 'text-align', /// default is to allow most things..
23453 // black listed style attributes.
23454 Roo.HtmlEditorCore.cblack= [
23455 // 'font-size' -- this can be set by the project
23459 Roo.HtmlEditorCore.swapCodes =[
23478 * @class Roo.bootstrap.HtmlEditor
23479 * @extends Roo.bootstrap.TextArea
23480 * Bootstrap HtmlEditor class
23483 * Create a new HtmlEditor
23484 * @param {Object} config The config object
23487 Roo.bootstrap.HtmlEditor = function(config){
23488 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23489 if (!this.toolbars) {
23490 this.toolbars = [];
23493 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23496 * @event initialize
23497 * Fires when the editor is fully initialized (including the iframe)
23498 * @param {HtmlEditor} this
23503 * Fires when the editor is first receives the focus. Any insertion must wait
23504 * until after this event.
23505 * @param {HtmlEditor} this
23509 * @event beforesync
23510 * Fires before the textarea is updated with content from the editor iframe. Return false
23511 * to cancel the sync.
23512 * @param {HtmlEditor} this
23513 * @param {String} html
23517 * @event beforepush
23518 * Fires before the iframe editor is updated with content from the textarea. Return false
23519 * to cancel the push.
23520 * @param {HtmlEditor} this
23521 * @param {String} html
23526 * Fires when the textarea is updated with content from the editor iframe.
23527 * @param {HtmlEditor} this
23528 * @param {String} html
23533 * Fires when the iframe editor is updated with content from the textarea.
23534 * @param {HtmlEditor} this
23535 * @param {String} html
23539 * @event editmodechange
23540 * Fires when the editor switches edit modes
23541 * @param {HtmlEditor} this
23542 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23544 editmodechange: true,
23546 * @event editorevent
23547 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23548 * @param {HtmlEditor} this
23552 * @event firstfocus
23553 * Fires when on first focus - needed by toolbars..
23554 * @param {HtmlEditor} this
23559 * Auto save the htmlEditor value as a file into Events
23560 * @param {HtmlEditor} this
23564 * @event savedpreview
23565 * preview the saved version of htmlEditor
23566 * @param {HtmlEditor} this
23573 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23577 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23582 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23587 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23592 * @cfg {Number} height (in pixels)
23596 * @cfg {Number} width (in pixels)
23601 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23604 stylesheets: false,
23609 // private properties
23610 validationEvent : false,
23612 initialized : false,
23615 onFocus : Roo.emptyFn,
23617 hideMode:'offsets',
23619 tbContainer : false,
23623 toolbarContainer :function() {
23624 return this.wrap.select('.x-html-editor-tb',true).first();
23628 * Protected method that will not generally be called directly. It
23629 * is called when the editor creates its toolbar. Override this method if you need to
23630 * add custom toolbar buttons.
23631 * @param {HtmlEditor} editor
23633 createToolbar : function(){
23634 Roo.log('renewing');
23635 Roo.log("create toolbars");
23637 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23638 this.toolbars[0].render(this.toolbarContainer());
23642 // if (!editor.toolbars || !editor.toolbars.length) {
23643 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23646 // for (var i =0 ; i < editor.toolbars.length;i++) {
23647 // editor.toolbars[i] = Roo.factory(
23648 // typeof(editor.toolbars[i]) == 'string' ?
23649 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23650 // Roo.bootstrap.HtmlEditor);
23651 // editor.toolbars[i].init(editor);
23657 onRender : function(ct, position)
23659 // Roo.log("Call onRender: " + this.xtype);
23661 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23663 this.wrap = this.inputEl().wrap({
23664 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23667 this.editorcore.onRender(ct, position);
23669 if (this.resizable) {
23670 this.resizeEl = new Roo.Resizable(this.wrap, {
23674 minHeight : this.height,
23675 height: this.height,
23676 handles : this.resizable,
23679 resize : function(r, w, h) {
23680 _t.onResize(w,h); // -something
23686 this.createToolbar(this);
23689 if(!this.width && this.resizable){
23690 this.setSize(this.wrap.getSize());
23692 if (this.resizeEl) {
23693 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23694 // should trigger onReize..
23700 onResize : function(w, h)
23702 Roo.log('resize: ' +w + ',' + h );
23703 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23707 if(this.inputEl() ){
23708 if(typeof w == 'number'){
23709 var aw = w - this.wrap.getFrameWidth('lr');
23710 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23713 if(typeof h == 'number'){
23714 var tbh = -11; // fixme it needs to tool bar size!
23715 for (var i =0; i < this.toolbars.length;i++) {
23716 // fixme - ask toolbars for heights?
23717 tbh += this.toolbars[i].el.getHeight();
23718 //if (this.toolbars[i].footer) {
23719 // tbh += this.toolbars[i].footer.el.getHeight();
23727 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23728 ah -= 5; // knock a few pixes off for look..
23729 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23733 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23734 this.editorcore.onResize(ew,eh);
23739 * Toggles the editor between standard and source edit mode.
23740 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23742 toggleSourceEdit : function(sourceEditMode)
23744 this.editorcore.toggleSourceEdit(sourceEditMode);
23746 if(this.editorcore.sourceEditMode){
23747 Roo.log('editor - showing textarea');
23750 // Roo.log(this.syncValue());
23752 this.inputEl().removeClass(['hide', 'x-hidden']);
23753 this.inputEl().dom.removeAttribute('tabIndex');
23754 this.inputEl().focus();
23756 Roo.log('editor - hiding textarea');
23758 // Roo.log(this.pushValue());
23761 this.inputEl().addClass(['hide', 'x-hidden']);
23762 this.inputEl().dom.setAttribute('tabIndex', -1);
23763 //this.deferFocus();
23766 if(this.resizable){
23767 this.setSize(this.wrap.getSize());
23770 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23773 // private (for BoxComponent)
23774 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23776 // private (for BoxComponent)
23777 getResizeEl : function(){
23781 // private (for BoxComponent)
23782 getPositionEl : function(){
23787 initEvents : function(){
23788 this.originalValue = this.getValue();
23792 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23795 // markInvalid : Roo.emptyFn,
23797 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23800 // clearInvalid : Roo.emptyFn,
23802 setValue : function(v){
23803 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23804 this.editorcore.pushValue();
23809 deferFocus : function(){
23810 this.focus.defer(10, this);
23814 focus : function(){
23815 this.editorcore.focus();
23821 onDestroy : function(){
23827 for (var i =0; i < this.toolbars.length;i++) {
23828 // fixme - ask toolbars for heights?
23829 this.toolbars[i].onDestroy();
23832 this.wrap.dom.innerHTML = '';
23833 this.wrap.remove();
23838 onFirstFocus : function(){
23839 //Roo.log("onFirstFocus");
23840 this.editorcore.onFirstFocus();
23841 for (var i =0; i < this.toolbars.length;i++) {
23842 this.toolbars[i].onFirstFocus();
23848 syncValue : function()
23850 this.editorcore.syncValue();
23853 pushValue : function()
23855 this.editorcore.pushValue();
23859 // hide stuff that is not compatible
23873 * @event specialkey
23877 * @cfg {String} fieldClass @hide
23880 * @cfg {String} focusClass @hide
23883 * @cfg {String} autoCreate @hide
23886 * @cfg {String} inputType @hide
23889 * @cfg {String} invalidClass @hide
23892 * @cfg {String} invalidText @hide
23895 * @cfg {String} msgFx @hide
23898 * @cfg {String} validateOnBlur @hide
23907 Roo.namespace('Roo.bootstrap.htmleditor');
23909 * @class Roo.bootstrap.HtmlEditorToolbar1
23914 new Roo.bootstrap.HtmlEditor({
23917 new Roo.bootstrap.HtmlEditorToolbar1({
23918 disable : { fonts: 1 , format: 1, ..., ... , ...],
23924 * @cfg {Object} disable List of elements to disable..
23925 * @cfg {Array} btns List of additional buttons.
23929 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23932 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23935 Roo.apply(this, config);
23937 // default disabled, based on 'good practice'..
23938 this.disable = this.disable || {};
23939 Roo.applyIf(this.disable, {
23942 specialElements : true
23944 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23946 this.editor = config.editor;
23947 this.editorcore = config.editor.editorcore;
23949 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23951 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23952 // dont call parent... till later.
23954 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23959 editorcore : false,
23964 "h1","h2","h3","h4","h5","h6",
23966 "abbr", "acronym", "address", "cite", "samp", "var",
23970 onRender : function(ct, position)
23972 // Roo.log("Call onRender: " + this.xtype);
23974 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
23976 this.el.dom.style.marginBottom = '0';
23978 var editorcore = this.editorcore;
23979 var editor= this.editor;
23982 var btn = function(id,cmd , toggle, handler, html){
23984 var event = toggle ? 'toggle' : 'click';
23989 xns: Roo.bootstrap,
23993 enableToggle:toggle !== false,
23995 pressed : toggle ? false : null,
23998 a.listeners[toggle ? 'toggle' : 'click'] = function() {
23999 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24005 // var cb_box = function...
24010 xns: Roo.bootstrap,
24015 xns: Roo.bootstrap,
24019 Roo.each(this.formats, function(f) {
24020 style.menu.items.push({
24022 xns: Roo.bootstrap,
24023 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24028 editorcore.insertTag(this.tagname);
24035 children.push(style);
24037 btn('bold',false,true);
24038 btn('italic',false,true);
24039 btn('align-left', 'justifyleft',true);
24040 btn('align-center', 'justifycenter',true);
24041 btn('align-right' , 'justifyright',true);
24042 btn('link', false, false, function(btn) {
24043 //Roo.log("create link?");
24044 var url = prompt(this.createLinkText, this.defaultLinkValue);
24045 if(url && url != 'http:/'+'/'){
24046 this.editorcore.relayCmd('createlink', url);
24049 btn('list','insertunorderedlist',true);
24050 btn('pencil', false,true, function(btn){
24052 this.toggleSourceEdit(btn.pressed);
24055 if (this.editor.btns.length > 0) {
24056 for (var i = 0; i<this.editor.btns.length; i++) {
24057 children.push(this.editor.btns[i]);
24065 xns: Roo.bootstrap,
24070 xns: Roo.bootstrap,
24075 cog.menu.items.push({
24077 xns: Roo.bootstrap,
24078 html : Clean styles,
24083 editorcore.insertTag(this.tagname);
24092 this.xtype = 'NavSimplebar';
24094 for(var i=0;i< children.length;i++) {
24096 this.buttons.add(this.addxtypeChild(children[i]));
24100 editor.on('editorevent', this.updateToolbar, this);
24102 onBtnClick : function(id)
24104 this.editorcore.relayCmd(id);
24105 this.editorcore.focus();
24109 * Protected method that will not generally be called directly. It triggers
24110 * a toolbar update by reading the markup state of the current selection in the editor.
24112 updateToolbar: function(){
24114 if(!this.editorcore.activated){
24115 this.editor.onFirstFocus(); // is this neeed?
24119 var btns = this.buttons;
24120 var doc = this.editorcore.doc;
24121 btns.get('bold').setActive(doc.queryCommandState('bold'));
24122 btns.get('italic').setActive(doc.queryCommandState('italic'));
24123 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24125 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24126 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24127 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24129 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24130 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24133 var ans = this.editorcore.getAllAncestors();
24134 if (this.formatCombo) {
24137 var store = this.formatCombo.store;
24138 this.formatCombo.setValue("");
24139 for (var i =0; i < ans.length;i++) {
24140 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24142 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24150 // hides menus... - so this cant be on a menu...
24151 Roo.bootstrap.MenuMgr.hideAll();
24153 Roo.bootstrap.MenuMgr.hideAll();
24154 //this.editorsyncValue();
24156 onFirstFocus: function() {
24157 this.buttons.each(function(item){
24161 toggleSourceEdit : function(sourceEditMode){
24164 if(sourceEditMode){
24165 Roo.log("disabling buttons");
24166 this.buttons.each( function(item){
24167 if(item.cmd != 'pencil'){
24173 Roo.log("enabling buttons");
24174 if(this.editorcore.initialized){
24175 this.buttons.each( function(item){
24181 Roo.log("calling toggole on editor");
24182 // tell the editor that it's been pressed..
24183 this.editor.toggleSourceEdit(sourceEditMode);
24193 * @class Roo.bootstrap.Table.AbstractSelectionModel
24194 * @extends Roo.util.Observable
24195 * Abstract base class for grid SelectionModels. It provides the interface that should be
24196 * implemented by descendant classes. This class should not be directly instantiated.
24199 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24200 this.locked = false;
24201 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24205 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24206 /** @ignore Called by the grid automatically. Do not call directly. */
24207 init : function(grid){
24213 * Locks the selections.
24216 this.locked = true;
24220 * Unlocks the selections.
24222 unlock : function(){
24223 this.locked = false;
24227 * Returns true if the selections are locked.
24228 * @return {Boolean}
24230 isLocked : function(){
24231 return this.locked;
24235 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24236 * @class Roo.bootstrap.Table.RowSelectionModel
24237 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24238 * It supports multiple selections and keyboard selection/navigation.
24240 * @param {Object} config
24243 Roo.bootstrap.Table.RowSelectionModel = function(config){
24244 Roo.apply(this, config);
24245 this.selections = new Roo.util.MixedCollection(false, function(o){
24250 this.lastActive = false;
24254 * @event selectionchange
24255 * Fires when the selection changes
24256 * @param {SelectionModel} this
24258 "selectionchange" : true,
24260 * @event afterselectionchange
24261 * Fires after the selection changes (eg. by key press or clicking)
24262 * @param {SelectionModel} this
24264 "afterselectionchange" : true,
24266 * @event beforerowselect
24267 * Fires when a row is selected being selected, return false to cancel.
24268 * @param {SelectionModel} this
24269 * @param {Number} rowIndex The selected index
24270 * @param {Boolean} keepExisting False if other selections will be cleared
24272 "beforerowselect" : true,
24275 * Fires when a row is selected.
24276 * @param {SelectionModel} this
24277 * @param {Number} rowIndex The selected index
24278 * @param {Roo.data.Record} r The record
24280 "rowselect" : true,
24282 * @event rowdeselect
24283 * Fires when a row is deselected.
24284 * @param {SelectionModel} this
24285 * @param {Number} rowIndex The selected index
24287 "rowdeselect" : true
24289 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24290 this.locked = false;
24293 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24295 * @cfg {Boolean} singleSelect
24296 * True to allow selection of only one row at a time (defaults to false)
24298 singleSelect : false,
24301 initEvents : function()
24304 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24305 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24306 //}else{ // allow click to work like normal
24307 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24309 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24310 this.grid.on("rowclick", this.handleMouseDown, this);
24312 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24313 "up" : function(e){
24315 this.selectPrevious(e.shiftKey);
24316 }else if(this.last !== false && this.lastActive !== false){
24317 var last = this.last;
24318 this.selectRange(this.last, this.lastActive-1);
24319 this.grid.getView().focusRow(this.lastActive);
24320 if(last !== false){
24324 this.selectFirstRow();
24326 this.fireEvent("afterselectionchange", this);
24328 "down" : function(e){
24330 this.selectNext(e.shiftKey);
24331 }else if(this.last !== false && this.lastActive !== false){
24332 var last = this.last;
24333 this.selectRange(this.last, this.lastActive+1);
24334 this.grid.getView().focusRow(this.lastActive);
24335 if(last !== false){
24339 this.selectFirstRow();
24341 this.fireEvent("afterselectionchange", this);
24345 this.grid.store.on('load', function(){
24346 this.selections.clear();
24349 var view = this.grid.view;
24350 view.on("refresh", this.onRefresh, this);
24351 view.on("rowupdated", this.onRowUpdated, this);
24352 view.on("rowremoved", this.onRemove, this);
24357 onRefresh : function()
24359 var ds = this.grid.store, i, v = this.grid.view;
24360 var s = this.selections;
24361 s.each(function(r){
24362 if((i = ds.indexOfId(r.id)) != -1){
24371 onRemove : function(v, index, r){
24372 this.selections.remove(r);
24376 onRowUpdated : function(v, index, r){
24377 if(this.isSelected(r)){
24378 v.onRowSelect(index);
24384 * @param {Array} records The records to select
24385 * @param {Boolean} keepExisting (optional) True to keep existing selections
24387 selectRecords : function(records, keepExisting)
24390 this.clearSelections();
24392 var ds = this.grid.store;
24393 for(var i = 0, len = records.length; i < len; i++){
24394 this.selectRow(ds.indexOf(records[i]), true);
24399 * Gets the number of selected rows.
24402 getCount : function(){
24403 return this.selections.length;
24407 * Selects the first row in the grid.
24409 selectFirstRow : function(){
24414 * Select the last row.
24415 * @param {Boolean} keepExisting (optional) True to keep existing selections
24417 selectLastRow : function(keepExisting){
24418 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24419 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24423 * Selects the row immediately following the last selected row.
24424 * @param {Boolean} keepExisting (optional) True to keep existing selections
24426 selectNext : function(keepExisting)
24428 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24429 this.selectRow(this.last+1, keepExisting);
24430 this.grid.getView().focusRow(this.last);
24435 * Selects the row that precedes the last selected row.
24436 * @param {Boolean} keepExisting (optional) True to keep existing selections
24438 selectPrevious : function(keepExisting){
24440 this.selectRow(this.last-1, keepExisting);
24441 this.grid.getView().focusRow(this.last);
24446 * Returns the selected records
24447 * @return {Array} Array of selected records
24449 getSelections : function(){
24450 return [].concat(this.selections.items);
24454 * Returns the first selected record.
24457 getSelected : function(){
24458 return this.selections.itemAt(0);
24463 * Clears all selections.
24465 clearSelections : function(fast)
24471 var ds = this.grid.store;
24472 var s = this.selections;
24473 s.each(function(r){
24474 this.deselectRow(ds.indexOfId(r.id));
24478 this.selections.clear();
24485 * Selects all rows.
24487 selectAll : function(){
24491 this.selections.clear();
24492 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24493 this.selectRow(i, true);
24498 * Returns True if there is a selection.
24499 * @return {Boolean}
24501 hasSelection : function(){
24502 return this.selections.length > 0;
24506 * Returns True if the specified row is selected.
24507 * @param {Number/Record} record The record or index of the record to check
24508 * @return {Boolean}
24510 isSelected : function(index){
24511 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24512 return (r && this.selections.key(r.id) ? true : false);
24516 * Returns True if the specified record id is selected.
24517 * @param {String} id The id of record to check
24518 * @return {Boolean}
24520 isIdSelected : function(id){
24521 return (this.selections.key(id) ? true : false);
24526 handleMouseDBClick : function(e, t){
24530 handleMouseDown : function(e, t)
24532 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24533 if(this.isLocked() || rowIndex < 0 ){
24536 if(e.shiftKey && this.last !== false){
24537 var last = this.last;
24538 this.selectRange(last, rowIndex, e.ctrlKey);
24539 this.last = last; // reset the last
24543 var isSelected = this.isSelected(rowIndex);
24544 //Roo.log("select row:" + rowIndex);
24546 this.deselectRow(rowIndex);
24548 this.selectRow(rowIndex, true);
24552 if(e.button !== 0 && isSelected){
24553 alert('rowIndex 2: ' + rowIndex);
24554 view.focusRow(rowIndex);
24555 }else if(e.ctrlKey && isSelected){
24556 this.deselectRow(rowIndex);
24557 }else if(!isSelected){
24558 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24559 view.focusRow(rowIndex);
24563 this.fireEvent("afterselectionchange", this);
24566 handleDragableRowClick : function(grid, rowIndex, e)
24568 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24569 this.selectRow(rowIndex, false);
24570 grid.view.focusRow(rowIndex);
24571 this.fireEvent("afterselectionchange", this);
24576 * Selects multiple rows.
24577 * @param {Array} rows Array of the indexes of the row to select
24578 * @param {Boolean} keepExisting (optional) True to keep existing selections
24580 selectRows : function(rows, keepExisting){
24582 this.clearSelections();
24584 for(var i = 0, len = rows.length; i < len; i++){
24585 this.selectRow(rows[i], true);
24590 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24591 * @param {Number} startRow The index of the first row in the range
24592 * @param {Number} endRow The index of the last row in the range
24593 * @param {Boolean} keepExisting (optional) True to retain existing selections
24595 selectRange : function(startRow, endRow, keepExisting){
24600 this.clearSelections();
24602 if(startRow <= endRow){
24603 for(var i = startRow; i <= endRow; i++){
24604 this.selectRow(i, true);
24607 for(var i = startRow; i >= endRow; i--){
24608 this.selectRow(i, true);
24614 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24615 * @param {Number} startRow The index of the first row in the range
24616 * @param {Number} endRow The index of the last row in the range
24618 deselectRange : function(startRow, endRow, preventViewNotify){
24622 for(var i = startRow; i <= endRow; i++){
24623 this.deselectRow(i, preventViewNotify);
24629 * @param {Number} row The index of the row to select
24630 * @param {Boolean} keepExisting (optional) True to keep existing selections
24632 selectRow : function(index, keepExisting, preventViewNotify)
24634 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24637 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24638 if(!keepExisting || this.singleSelect){
24639 this.clearSelections();
24642 var r = this.grid.store.getAt(index);
24643 //console.log('selectRow - record id :' + r.id);
24645 this.selections.add(r);
24646 this.last = this.lastActive = index;
24647 if(!preventViewNotify){
24648 var proxy = new Roo.Element(
24649 this.grid.getRowDom(index)
24651 proxy.addClass('bg-info info');
24653 this.fireEvent("rowselect", this, index, r);
24654 this.fireEvent("selectionchange", this);
24660 * @param {Number} row The index of the row to deselect
24662 deselectRow : function(index, preventViewNotify)
24667 if(this.last == index){
24670 if(this.lastActive == index){
24671 this.lastActive = false;
24674 var r = this.grid.store.getAt(index);
24679 this.selections.remove(r);
24680 //.console.log('deselectRow - record id :' + r.id);
24681 if(!preventViewNotify){
24683 var proxy = new Roo.Element(
24684 this.grid.getRowDom(index)
24686 proxy.removeClass('bg-info info');
24688 this.fireEvent("rowdeselect", this, index);
24689 this.fireEvent("selectionchange", this);
24693 restoreLast : function(){
24695 this.last = this._last;
24700 acceptsNav : function(row, col, cm){
24701 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24705 onEditorKey : function(field, e){
24706 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24711 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24713 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24715 }else if(k == e.ENTER && !e.ctrlKey){
24719 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24721 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24723 }else if(k == e.ESC){
24727 g.startEditing(newCell[0], newCell[1]);
24733 * Ext JS Library 1.1.1
24734 * Copyright(c) 2006-2007, Ext JS, LLC.
24736 * Originally Released Under LGPL - original licence link has changed is not relivant.
24739 * <script type="text/javascript">
24743 * @class Roo.bootstrap.PagingToolbar
24744 * @extends Roo.bootstrap.NavSimplebar
24745 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24747 * Create a new PagingToolbar
24748 * @param {Object} config The config object
24749 * @param {Roo.data.Store} store
24751 Roo.bootstrap.PagingToolbar = function(config)
24753 // old args format still supported... - xtype is prefered..
24754 // created from xtype...
24756 this.ds = config.dataSource;
24758 if (config.store && !this.ds) {
24759 this.store= Roo.factory(config.store, Roo.data);
24760 this.ds = this.store;
24761 this.ds.xmodule = this.xmodule || false;
24764 this.toolbarItems = [];
24765 if (config.items) {
24766 this.toolbarItems = config.items;
24769 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24774 this.bind(this.ds);
24777 if (Roo.bootstrap.version == 4) {
24778 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24780 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24785 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24787 * @cfg {Roo.data.Store} dataSource
24788 * The underlying data store providing the paged data
24791 * @cfg {String/HTMLElement/Element} container
24792 * container The id or element that will contain the toolbar
24795 * @cfg {Boolean} displayInfo
24796 * True to display the displayMsg (defaults to false)
24799 * @cfg {Number} pageSize
24800 * The number of records to display per page (defaults to 20)
24804 * @cfg {String} displayMsg
24805 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24807 displayMsg : 'Displaying {0} - {1} of {2}',
24809 * @cfg {String} emptyMsg
24810 * The message to display when no records are found (defaults to "No data to display")
24812 emptyMsg : 'No data to display',
24814 * Customizable piece of the default paging text (defaults to "Page")
24817 beforePageText : "Page",
24819 * Customizable piece of the default paging text (defaults to "of %0")
24822 afterPageText : "of {0}",
24824 * Customizable piece of the default paging text (defaults to "First Page")
24827 firstText : "First Page",
24829 * Customizable piece of the default paging text (defaults to "Previous Page")
24832 prevText : "Previous Page",
24834 * Customizable piece of the default paging text (defaults to "Next Page")
24837 nextText : "Next Page",
24839 * Customizable piece of the default paging text (defaults to "Last Page")
24842 lastText : "Last Page",
24844 * Customizable piece of the default paging text (defaults to "Refresh")
24847 refreshText : "Refresh",
24851 onRender : function(ct, position)
24853 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24854 this.navgroup.parentId = this.id;
24855 this.navgroup.onRender(this.el, null);
24856 // add the buttons to the navgroup
24858 if(this.displayInfo){
24859 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24860 this.displayEl = this.el.select('.x-paging-info', true).first();
24861 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24862 // this.displayEl = navel.el.select('span',true).first();
24868 Roo.each(_this.buttons, function(e){ // this might need to use render????
24869 Roo.factory(e).render(_this.el);
24873 Roo.each(_this.toolbarItems, function(e) {
24874 _this.navgroup.addItem(e);
24878 this.first = this.navgroup.addItem({
24879 tooltip: this.firstText,
24880 cls: "prev btn-outline-secondary",
24881 html : ' <i class="fa fa-step-backward"></i>',
24883 preventDefault: true,
24884 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24887 this.prev = this.navgroup.addItem({
24888 tooltip: this.prevText,
24889 cls: "prev btn-outline-secondary",
24890 html : ' <i class="fa fa-backward"></i>',
24892 preventDefault: true,
24893 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24895 //this.addSeparator();
24898 var field = this.navgroup.addItem( {
24900 cls : 'x-paging-position btn-outline-secondary',
24902 html : this.beforePageText +
24903 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24904 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24907 this.field = field.el.select('input', true).first();
24908 this.field.on("keydown", this.onPagingKeydown, this);
24909 this.field.on("focus", function(){this.dom.select();});
24912 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24913 //this.field.setHeight(18);
24914 //this.addSeparator();
24915 this.next = this.navgroup.addItem({
24916 tooltip: this.nextText,
24917 cls: "next btn-outline-secondary",
24918 html : ' <i class="fa fa-forward"></i>',
24920 preventDefault: true,
24921 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24923 this.last = this.navgroup.addItem({
24924 tooltip: this.lastText,
24925 html : ' <i class="fa fa-step-forward"></i>',
24926 cls: "next btn-outline-secondary",
24928 preventDefault: true,
24929 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24931 //this.addSeparator();
24932 this.loading = this.navgroup.addItem({
24933 tooltip: this.refreshText,
24934 cls: "btn-outline-secondary",
24935 html : ' <i class="fa fa-refresh"></i>',
24936 preventDefault: true,
24937 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24943 updateInfo : function(){
24944 if(this.displayEl){
24945 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24946 var msg = count == 0 ?
24950 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24952 this.displayEl.update(msg);
24957 onLoad : function(ds, r, o)
24959 this.cursor = o.params.start ? o.params.start : 0;
24961 var d = this.getPageData(),
24966 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24967 this.field.dom.value = ap;
24968 this.first.setDisabled(ap == 1);
24969 this.prev.setDisabled(ap == 1);
24970 this.next.setDisabled(ap == ps);
24971 this.last.setDisabled(ap == ps);
24972 this.loading.enable();
24977 getPageData : function(){
24978 var total = this.ds.getTotalCount();
24981 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
24982 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
24987 onLoadError : function(){
24988 this.loading.enable();
24992 onPagingKeydown : function(e){
24993 var k = e.getKey();
24994 var d = this.getPageData();
24996 var v = this.field.dom.value, pageNum;
24997 if(!v || isNaN(pageNum = parseInt(v, 10))){
24998 this.field.dom.value = d.activePage;
25001 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25002 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25005 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))
25007 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25008 this.field.dom.value = pageNum;
25009 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25012 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25014 var v = this.field.dom.value, pageNum;
25015 var increment = (e.shiftKey) ? 10 : 1;
25016 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25019 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25020 this.field.dom.value = d.activePage;
25023 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25025 this.field.dom.value = parseInt(v, 10) + increment;
25026 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25027 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25034 beforeLoad : function(){
25036 this.loading.disable();
25041 onClick : function(which){
25050 ds.load({params:{start: 0, limit: this.pageSize}});
25053 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25056 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25059 var total = ds.getTotalCount();
25060 var extra = total % this.pageSize;
25061 var lastStart = extra ? (total - extra) : total-this.pageSize;
25062 ds.load({params:{start: lastStart, limit: this.pageSize}});
25065 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25071 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25072 * @param {Roo.data.Store} store The data store to unbind
25074 unbind : function(ds){
25075 ds.un("beforeload", this.beforeLoad, this);
25076 ds.un("load", this.onLoad, this);
25077 ds.un("loadexception", this.onLoadError, this);
25078 ds.un("remove", this.updateInfo, this);
25079 ds.un("add", this.updateInfo, this);
25080 this.ds = undefined;
25084 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25085 * @param {Roo.data.Store} store The data store to bind
25087 bind : function(ds){
25088 ds.on("beforeload", this.beforeLoad, this);
25089 ds.on("load", this.onLoad, this);
25090 ds.on("loadexception", this.onLoadError, this);
25091 ds.on("remove", this.updateInfo, this);
25092 ds.on("add", this.updateInfo, this);
25103 * @class Roo.bootstrap.MessageBar
25104 * @extends Roo.bootstrap.Component
25105 * Bootstrap MessageBar class
25106 * @cfg {String} html contents of the MessageBar
25107 * @cfg {String} weight (info | success | warning | danger) default info
25108 * @cfg {String} beforeClass insert the bar before the given class
25109 * @cfg {Boolean} closable (true | false) default false
25110 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25113 * Create a new Element
25114 * @param {Object} config The config object
25117 Roo.bootstrap.MessageBar = function(config){
25118 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25121 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25127 beforeClass: 'bootstrap-sticky-wrap',
25129 getAutoCreate : function(){
25133 cls: 'alert alert-dismissable alert-' + this.weight,
25138 html: this.html || ''
25144 cfg.cls += ' alert-messages-fixed';
25158 onRender : function(ct, position)
25160 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25163 var cfg = Roo.apply({}, this.getAutoCreate());
25167 cfg.cls += ' ' + this.cls;
25170 cfg.style = this.style;
25172 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25174 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25177 this.el.select('>button.close').on('click', this.hide, this);
25183 if (!this.rendered) {
25189 this.fireEvent('show', this);
25195 if (!this.rendered) {
25201 this.fireEvent('hide', this);
25204 update : function()
25206 // var e = this.el.dom.firstChild;
25208 // if(this.closable){
25209 // e = e.nextSibling;
25212 // e.data = this.html || '';
25214 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25230 * @class Roo.bootstrap.Graph
25231 * @extends Roo.bootstrap.Component
25232 * Bootstrap Graph class
25236 @cfg {String} graphtype bar | vbar | pie
25237 @cfg {number} g_x coodinator | centre x (pie)
25238 @cfg {number} g_y coodinator | centre y (pie)
25239 @cfg {number} g_r radius (pie)
25240 @cfg {number} g_height height of the chart (respected by all elements in the set)
25241 @cfg {number} g_width width of the chart (respected by all elements in the set)
25242 @cfg {Object} title The title of the chart
25245 -opts (object) options for the chart
25247 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25248 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25250 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.
25251 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25253 o stretch (boolean)
25255 -opts (object) options for the pie
25258 o startAngle (number)
25259 o endAngle (number)
25263 * Create a new Input
25264 * @param {Object} config The config object
25267 Roo.bootstrap.Graph = function(config){
25268 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25274 * The img click event for the img.
25275 * @param {Roo.EventObject} e
25281 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25292 //g_colors: this.colors,
25299 getAutoCreate : function(){
25310 onRender : function(ct,position){
25313 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25315 if (typeof(Raphael) == 'undefined') {
25316 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25320 this.raphael = Raphael(this.el.dom);
25322 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25323 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25324 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25325 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25327 r.text(160, 10, "Single Series Chart").attr(txtattr);
25328 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25329 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25330 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25332 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25333 r.barchart(330, 10, 300, 220, data1);
25334 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25335 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25338 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25339 // r.barchart(30, 30, 560, 250, xdata, {
25340 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25341 // axis : "0 0 1 1",
25342 // axisxlabels : xdata
25343 // //yvalues : cols,
25346 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25348 // this.load(null,xdata,{
25349 // axis : "0 0 1 1",
25350 // axisxlabels : xdata
25355 load : function(graphtype,xdata,opts)
25357 this.raphael.clear();
25359 graphtype = this.graphtype;
25364 var r = this.raphael,
25365 fin = function () {
25366 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25368 fout = function () {
25369 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25371 pfin = function() {
25372 this.sector.stop();
25373 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25376 this.label[0].stop();
25377 this.label[0].attr({ r: 7.5 });
25378 this.label[1].attr({ "font-weight": 800 });
25381 pfout = function() {
25382 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25385 this.label[0].animate({ r: 5 }, 500, "bounce");
25386 this.label[1].attr({ "font-weight": 400 });
25392 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25395 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25398 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25399 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25401 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25408 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25413 setTitle: function(o)
25418 initEvents: function() {
25421 this.el.on('click', this.onClick, this);
25425 onClick : function(e)
25427 Roo.log('img onclick');
25428 this.fireEvent('click', this, e);
25440 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25443 * @class Roo.bootstrap.dash.NumberBox
25444 * @extends Roo.bootstrap.Component
25445 * Bootstrap NumberBox class
25446 * @cfg {String} headline Box headline
25447 * @cfg {String} content Box content
25448 * @cfg {String} icon Box icon
25449 * @cfg {String} footer Footer text
25450 * @cfg {String} fhref Footer href
25453 * Create a new NumberBox
25454 * @param {Object} config The config object
25458 Roo.bootstrap.dash.NumberBox = function(config){
25459 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25463 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25472 getAutoCreate : function(){
25476 cls : 'small-box ',
25484 cls : 'roo-headline',
25485 html : this.headline
25489 cls : 'roo-content',
25490 html : this.content
25504 cls : 'ion ' + this.icon
25513 cls : 'small-box-footer',
25514 href : this.fhref || '#',
25518 cfg.cn.push(footer);
25525 onRender : function(ct,position){
25526 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25533 setHeadline: function (value)
25535 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25538 setFooter: function (value, href)
25540 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25543 this.el.select('a.small-box-footer',true).first().attr('href', href);
25548 setContent: function (value)
25550 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25553 initEvents: function()
25567 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25570 * @class Roo.bootstrap.dash.TabBox
25571 * @extends Roo.bootstrap.Component
25572 * Bootstrap TabBox class
25573 * @cfg {String} title Title of the TabBox
25574 * @cfg {String} icon Icon of the TabBox
25575 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25576 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25579 * Create a new TabBox
25580 * @param {Object} config The config object
25584 Roo.bootstrap.dash.TabBox = function(config){
25585 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25590 * When a pane is added
25591 * @param {Roo.bootstrap.dash.TabPane} pane
25595 * @event activatepane
25596 * When a pane is activated
25597 * @param {Roo.bootstrap.dash.TabPane} pane
25599 "activatepane" : true
25607 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25612 tabScrollable : false,
25614 getChildContainer : function()
25616 return this.el.select('.tab-content', true).first();
25619 getAutoCreate : function(){
25623 cls: 'pull-left header',
25631 cls: 'fa ' + this.icon
25637 cls: 'nav nav-tabs pull-right',
25643 if(this.tabScrollable){
25650 cls: 'nav nav-tabs pull-right',
25661 cls: 'nav-tabs-custom',
25666 cls: 'tab-content no-padding',
25674 initEvents : function()
25676 //Roo.log('add add pane handler');
25677 this.on('addpane', this.onAddPane, this);
25680 * Updates the box title
25681 * @param {String} html to set the title to.
25683 setTitle : function(value)
25685 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25687 onAddPane : function(pane)
25689 this.panes.push(pane);
25690 //Roo.log('addpane');
25692 // tabs are rendere left to right..
25693 if(!this.showtabs){
25697 var ctr = this.el.select('.nav-tabs', true).first();
25700 var existing = ctr.select('.nav-tab',true);
25701 var qty = existing.getCount();;
25704 var tab = ctr.createChild({
25706 cls : 'nav-tab' + (qty ? '' : ' active'),
25714 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25717 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25719 pane.el.addClass('active');
25724 onTabClick : function(ev,un,ob,pane)
25726 //Roo.log('tab - prev default');
25727 ev.preventDefault();
25730 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25731 pane.tab.addClass('active');
25732 //Roo.log(pane.title);
25733 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25734 // technically we should have a deactivate event.. but maybe add later.
25735 // and it should not de-activate the selected tab...
25736 this.fireEvent('activatepane', pane);
25737 pane.el.addClass('active');
25738 pane.fireEvent('activate');
25743 getActivePane : function()
25746 Roo.each(this.panes, function(p) {
25747 if(p.el.hasClass('active')){
25768 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25770 * @class Roo.bootstrap.TabPane
25771 * @extends Roo.bootstrap.Component
25772 * Bootstrap TabPane class
25773 * @cfg {Boolean} active (false | true) Default false
25774 * @cfg {String} title title of panel
25778 * Create a new TabPane
25779 * @param {Object} config The config object
25782 Roo.bootstrap.dash.TabPane = function(config){
25783 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25789 * When a pane is activated
25790 * @param {Roo.bootstrap.dash.TabPane} pane
25797 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25802 // the tabBox that this is attached to.
25805 getAutoCreate : function()
25813 cfg.cls += ' active';
25818 initEvents : function()
25820 //Roo.log('trigger add pane handler');
25821 this.parent().fireEvent('addpane', this)
25825 * Updates the tab title
25826 * @param {String} html to set the title to.
25828 setTitle: function(str)
25834 this.tab.select('a', true).first().dom.innerHTML = str;
25851 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25854 * @class Roo.bootstrap.menu.Menu
25855 * @extends Roo.bootstrap.Component
25856 * Bootstrap Menu class - container for Menu
25857 * @cfg {String} html Text of the menu
25858 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25859 * @cfg {String} icon Font awesome icon
25860 * @cfg {String} pos Menu align to (top | bottom) default bottom
25864 * Create a new Menu
25865 * @param {Object} config The config object
25869 Roo.bootstrap.menu.Menu = function(config){
25870 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25874 * @event beforeshow
25875 * Fires before this menu is displayed
25876 * @param {Roo.bootstrap.menu.Menu} this
25880 * @event beforehide
25881 * Fires before this menu is hidden
25882 * @param {Roo.bootstrap.menu.Menu} this
25887 * Fires after this menu is displayed
25888 * @param {Roo.bootstrap.menu.Menu} this
25893 * Fires after this menu is hidden
25894 * @param {Roo.bootstrap.menu.Menu} this
25899 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25900 * @param {Roo.bootstrap.menu.Menu} this
25901 * @param {Roo.EventObject} e
25908 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25912 weight : 'default',
25917 getChildContainer : function() {
25918 if(this.isSubMenu){
25922 return this.el.select('ul.dropdown-menu', true).first();
25925 getAutoCreate : function()
25930 cls : 'roo-menu-text',
25938 cls : 'fa ' + this.icon
25949 cls : 'dropdown-button btn btn-' + this.weight,
25954 cls : 'dropdown-toggle btn btn-' + this.weight,
25964 cls : 'dropdown-menu'
25970 if(this.pos == 'top'){
25971 cfg.cls += ' dropup';
25974 if(this.isSubMenu){
25977 cls : 'dropdown-menu'
25984 onRender : function(ct, position)
25986 this.isSubMenu = ct.hasClass('dropdown-submenu');
25988 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
25991 initEvents : function()
25993 if(this.isSubMenu){
25997 this.hidden = true;
25999 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26000 this.triggerEl.on('click', this.onTriggerPress, this);
26002 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26003 this.buttonEl.on('click', this.onClick, this);
26009 if(this.isSubMenu){
26013 return this.el.select('ul.dropdown-menu', true).first();
26016 onClick : function(e)
26018 this.fireEvent("click", this, e);
26021 onTriggerPress : function(e)
26023 if (this.isVisible()) {
26030 isVisible : function(){
26031 return !this.hidden;
26036 this.fireEvent("beforeshow", this);
26038 this.hidden = false;
26039 this.el.addClass('open');
26041 Roo.get(document).on("mouseup", this.onMouseUp, this);
26043 this.fireEvent("show", this);
26050 this.fireEvent("beforehide", this);
26052 this.hidden = true;
26053 this.el.removeClass('open');
26055 Roo.get(document).un("mouseup", this.onMouseUp);
26057 this.fireEvent("hide", this);
26060 onMouseUp : function()
26074 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26077 * @class Roo.bootstrap.menu.Item
26078 * @extends Roo.bootstrap.Component
26079 * Bootstrap MenuItem class
26080 * @cfg {Boolean} submenu (true | false) default false
26081 * @cfg {String} html text of the item
26082 * @cfg {String} href the link
26083 * @cfg {Boolean} disable (true | false) default false
26084 * @cfg {Boolean} preventDefault (true | false) default true
26085 * @cfg {String} icon Font awesome icon
26086 * @cfg {String} pos Submenu align to (left | right) default right
26090 * Create a new Item
26091 * @param {Object} config The config object
26095 Roo.bootstrap.menu.Item = function(config){
26096 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26100 * Fires when the mouse is hovering over this menu
26101 * @param {Roo.bootstrap.menu.Item} this
26102 * @param {Roo.EventObject} e
26107 * Fires when the mouse exits this menu
26108 * @param {Roo.bootstrap.menu.Item} this
26109 * @param {Roo.EventObject} e
26115 * The raw click event for the entire grid.
26116 * @param {Roo.EventObject} e
26122 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26127 preventDefault: true,
26132 getAutoCreate : function()
26137 cls : 'roo-menu-item-text',
26145 cls : 'fa ' + this.icon
26154 href : this.href || '#',
26161 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26165 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26167 if(this.pos == 'left'){
26168 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26175 initEvents : function()
26177 this.el.on('mouseover', this.onMouseOver, this);
26178 this.el.on('mouseout', this.onMouseOut, this);
26180 this.el.select('a', true).first().on('click', this.onClick, this);
26184 onClick : function(e)
26186 if(this.preventDefault){
26187 e.preventDefault();
26190 this.fireEvent("click", this, e);
26193 onMouseOver : function(e)
26195 if(this.submenu && this.pos == 'left'){
26196 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26199 this.fireEvent("mouseover", this, e);
26202 onMouseOut : function(e)
26204 this.fireEvent("mouseout", this, e);
26216 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26219 * @class Roo.bootstrap.menu.Separator
26220 * @extends Roo.bootstrap.Component
26221 * Bootstrap Separator class
26224 * Create a new Separator
26225 * @param {Object} config The config object
26229 Roo.bootstrap.menu.Separator = function(config){
26230 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26233 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26235 getAutoCreate : function(){
26256 * @class Roo.bootstrap.Tooltip
26257 * Bootstrap Tooltip class
26258 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26259 * to determine which dom element triggers the tooltip.
26261 * It needs to add support for additional attributes like tooltip-position
26264 * Create a new Toolti
26265 * @param {Object} config The config object
26268 Roo.bootstrap.Tooltip = function(config){
26269 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26271 this.alignment = Roo.bootstrap.Tooltip.alignment;
26273 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26274 this.alignment = config.alignment;
26279 Roo.apply(Roo.bootstrap.Tooltip, {
26281 * @function init initialize tooltip monitoring.
26285 currentTip : false,
26286 currentRegion : false,
26292 Roo.get(document).on('mouseover', this.enter ,this);
26293 Roo.get(document).on('mouseout', this.leave, this);
26296 this.currentTip = new Roo.bootstrap.Tooltip();
26299 enter : function(ev)
26301 var dom = ev.getTarget();
26303 //Roo.log(['enter',dom]);
26304 var el = Roo.fly(dom);
26305 if (this.currentEl) {
26307 //Roo.log(this.currentEl);
26308 //Roo.log(this.currentEl.contains(dom));
26309 if (this.currentEl == el) {
26312 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26318 if (this.currentTip.el) {
26319 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26323 if(!el || el.dom == document){
26329 // you can not look for children, as if el is the body.. then everythign is the child..
26330 if (!el.attr('tooltip')) { //
26331 if (!el.select("[tooltip]").elements.length) {
26334 // is the mouse over this child...?
26335 bindEl = el.select("[tooltip]").first();
26336 var xy = ev.getXY();
26337 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26338 //Roo.log("not in region.");
26341 //Roo.log("child element over..");
26344 this.currentEl = bindEl;
26345 this.currentTip.bind(bindEl);
26346 this.currentRegion = Roo.lib.Region.getRegion(dom);
26347 this.currentTip.enter();
26350 leave : function(ev)
26352 var dom = ev.getTarget();
26353 //Roo.log(['leave',dom]);
26354 if (!this.currentEl) {
26359 if (dom != this.currentEl.dom) {
26362 var xy = ev.getXY();
26363 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26366 // only activate leave if mouse cursor is outside... bounding box..
26371 if (this.currentTip) {
26372 this.currentTip.leave();
26374 //Roo.log('clear currentEl');
26375 this.currentEl = false;
26380 'left' : ['r-l', [-2,0], 'right'],
26381 'right' : ['l-r', [2,0], 'left'],
26382 'bottom' : ['t-b', [0,2], 'top'],
26383 'top' : [ 'b-t', [0,-2], 'bottom']
26389 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26394 delay : null, // can be { show : 300 , hide: 500}
26398 hoverState : null, //???
26400 placement : 'bottom',
26404 getAutoCreate : function(){
26411 cls : 'tooltip-arrow'
26414 cls : 'tooltip-inner'
26421 bind : function(el)
26427 enter : function () {
26429 if (this.timeout != null) {
26430 clearTimeout(this.timeout);
26433 this.hoverState = 'in';
26434 //Roo.log("enter - show");
26435 if (!this.delay || !this.delay.show) {
26440 this.timeout = setTimeout(function () {
26441 if (_t.hoverState == 'in') {
26444 }, this.delay.show);
26448 clearTimeout(this.timeout);
26450 this.hoverState = 'out';
26451 if (!this.delay || !this.delay.hide) {
26457 this.timeout = setTimeout(function () {
26458 //Roo.log("leave - timeout");
26460 if (_t.hoverState == 'out') {
26462 Roo.bootstrap.Tooltip.currentEl = false;
26467 show : function (msg)
26470 this.render(document.body);
26473 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26475 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26477 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26479 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26481 var placement = typeof this.placement == 'function' ?
26482 this.placement.call(this, this.el, on_el) :
26485 var autoToken = /\s?auto?\s?/i;
26486 var autoPlace = autoToken.test(placement);
26488 placement = placement.replace(autoToken, '') || 'top';
26492 //this.el.setXY([0,0]);
26494 //this.el.dom.style.display='block';
26496 //this.el.appendTo(on_el);
26498 var p = this.getPosition();
26499 var box = this.el.getBox();
26505 var align = this.alignment[placement];
26507 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26509 if(placement == 'top' || placement == 'bottom'){
26511 placement = 'right';
26514 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26515 placement = 'left';
26518 var scroll = Roo.select('body', true).first().getScroll();
26520 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26524 align = this.alignment[placement];
26527 this.el.alignTo(this.bindEl, align[0],align[1]);
26528 //var arrow = this.el.select('.arrow',true).first();
26529 //arrow.set(align[2],
26531 this.el.addClass(placement);
26533 this.el.addClass('in fade');
26535 this.hoverState = null;
26537 if (this.el.hasClass('fade')) {
26548 //this.el.setXY([0,0]);
26549 this.el.removeClass('in');
26565 * @class Roo.bootstrap.LocationPicker
26566 * @extends Roo.bootstrap.Component
26567 * Bootstrap LocationPicker class
26568 * @cfg {Number} latitude Position when init default 0
26569 * @cfg {Number} longitude Position when init default 0
26570 * @cfg {Number} zoom default 15
26571 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26572 * @cfg {Boolean} mapTypeControl default false
26573 * @cfg {Boolean} disableDoubleClickZoom default false
26574 * @cfg {Boolean} scrollwheel default true
26575 * @cfg {Boolean} streetViewControl default false
26576 * @cfg {Number} radius default 0
26577 * @cfg {String} locationName
26578 * @cfg {Boolean} draggable default true
26579 * @cfg {Boolean} enableAutocomplete default false
26580 * @cfg {Boolean} enableReverseGeocode default true
26581 * @cfg {String} markerTitle
26584 * Create a new LocationPicker
26585 * @param {Object} config The config object
26589 Roo.bootstrap.LocationPicker = function(config){
26591 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26596 * Fires when the picker initialized.
26597 * @param {Roo.bootstrap.LocationPicker} this
26598 * @param {Google Location} location
26602 * @event positionchanged
26603 * Fires when the picker position changed.
26604 * @param {Roo.bootstrap.LocationPicker} this
26605 * @param {Google Location} location
26607 positionchanged : true,
26610 * Fires when the map resize.
26611 * @param {Roo.bootstrap.LocationPicker} this
26616 * Fires when the map show.
26617 * @param {Roo.bootstrap.LocationPicker} this
26622 * Fires when the map hide.
26623 * @param {Roo.bootstrap.LocationPicker} this
26628 * Fires when click the map.
26629 * @param {Roo.bootstrap.LocationPicker} this
26630 * @param {Map event} e
26634 * @event mapRightClick
26635 * Fires when right click the map.
26636 * @param {Roo.bootstrap.LocationPicker} this
26637 * @param {Map event} e
26639 mapRightClick : true,
26641 * @event markerClick
26642 * Fires when click the marker.
26643 * @param {Roo.bootstrap.LocationPicker} this
26644 * @param {Map event} e
26646 markerClick : true,
26648 * @event markerRightClick
26649 * Fires when right click the marker.
26650 * @param {Roo.bootstrap.LocationPicker} this
26651 * @param {Map event} e
26653 markerRightClick : true,
26655 * @event OverlayViewDraw
26656 * Fires when OverlayView Draw
26657 * @param {Roo.bootstrap.LocationPicker} this
26659 OverlayViewDraw : true,
26661 * @event OverlayViewOnAdd
26662 * Fires when OverlayView Draw
26663 * @param {Roo.bootstrap.LocationPicker} this
26665 OverlayViewOnAdd : true,
26667 * @event OverlayViewOnRemove
26668 * Fires when OverlayView Draw
26669 * @param {Roo.bootstrap.LocationPicker} this
26671 OverlayViewOnRemove : true,
26673 * @event OverlayViewShow
26674 * Fires when OverlayView Draw
26675 * @param {Roo.bootstrap.LocationPicker} this
26676 * @param {Pixel} cpx
26678 OverlayViewShow : true,
26680 * @event OverlayViewHide
26681 * Fires when OverlayView Draw
26682 * @param {Roo.bootstrap.LocationPicker} this
26684 OverlayViewHide : true,
26686 * @event loadexception
26687 * Fires when load google lib failed.
26688 * @param {Roo.bootstrap.LocationPicker} this
26690 loadexception : true
26695 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26697 gMapContext: false,
26703 mapTypeControl: false,
26704 disableDoubleClickZoom: false,
26706 streetViewControl: false,
26710 enableAutocomplete: false,
26711 enableReverseGeocode: true,
26714 getAutoCreate: function()
26719 cls: 'roo-location-picker'
26725 initEvents: function(ct, position)
26727 if(!this.el.getWidth() || this.isApplied()){
26731 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26736 initial: function()
26738 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26739 this.fireEvent('loadexception', this);
26743 if(!this.mapTypeId){
26744 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26747 this.gMapContext = this.GMapContext();
26749 this.initOverlayView();
26751 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26755 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26756 _this.setPosition(_this.gMapContext.marker.position);
26759 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26760 _this.fireEvent('mapClick', this, event);
26764 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26765 _this.fireEvent('mapRightClick', this, event);
26769 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26770 _this.fireEvent('markerClick', this, event);
26774 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26775 _this.fireEvent('markerRightClick', this, event);
26779 this.setPosition(this.gMapContext.location);
26781 this.fireEvent('initial', this, this.gMapContext.location);
26784 initOverlayView: function()
26788 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26792 _this.fireEvent('OverlayViewDraw', _this);
26797 _this.fireEvent('OverlayViewOnAdd', _this);
26800 onRemove: function()
26802 _this.fireEvent('OverlayViewOnRemove', _this);
26805 show: function(cpx)
26807 _this.fireEvent('OverlayViewShow', _this, cpx);
26812 _this.fireEvent('OverlayViewHide', _this);
26818 fromLatLngToContainerPixel: function(event)
26820 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26823 isApplied: function()
26825 return this.getGmapContext() == false ? false : true;
26828 getGmapContext: function()
26830 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26833 GMapContext: function()
26835 var position = new google.maps.LatLng(this.latitude, this.longitude);
26837 var _map = new google.maps.Map(this.el.dom, {
26840 mapTypeId: this.mapTypeId,
26841 mapTypeControl: this.mapTypeControl,
26842 disableDoubleClickZoom: this.disableDoubleClickZoom,
26843 scrollwheel: this.scrollwheel,
26844 streetViewControl: this.streetViewControl,
26845 locationName: this.locationName,
26846 draggable: this.draggable,
26847 enableAutocomplete: this.enableAutocomplete,
26848 enableReverseGeocode: this.enableReverseGeocode
26851 var _marker = new google.maps.Marker({
26852 position: position,
26854 title: this.markerTitle,
26855 draggable: this.draggable
26862 location: position,
26863 radius: this.radius,
26864 locationName: this.locationName,
26865 addressComponents: {
26866 formatted_address: null,
26867 addressLine1: null,
26868 addressLine2: null,
26870 streetNumber: null,
26874 stateOrProvince: null
26877 domContainer: this.el.dom,
26878 geodecoder: new google.maps.Geocoder()
26882 drawCircle: function(center, radius, options)
26884 if (this.gMapContext.circle != null) {
26885 this.gMapContext.circle.setMap(null);
26889 options = Roo.apply({}, options, {
26890 strokeColor: "#0000FF",
26891 strokeOpacity: .35,
26893 fillColor: "#0000FF",
26897 options.map = this.gMapContext.map;
26898 options.radius = radius;
26899 options.center = center;
26900 this.gMapContext.circle = new google.maps.Circle(options);
26901 return this.gMapContext.circle;
26907 setPosition: function(location)
26909 this.gMapContext.location = location;
26910 this.gMapContext.marker.setPosition(location);
26911 this.gMapContext.map.panTo(location);
26912 this.drawCircle(location, this.gMapContext.radius, {});
26916 if (this.gMapContext.settings.enableReverseGeocode) {
26917 this.gMapContext.geodecoder.geocode({
26918 latLng: this.gMapContext.location
26919 }, function(results, status) {
26921 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26922 _this.gMapContext.locationName = results[0].formatted_address;
26923 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26925 _this.fireEvent('positionchanged', this, location);
26932 this.fireEvent('positionchanged', this, location);
26937 google.maps.event.trigger(this.gMapContext.map, "resize");
26939 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26941 this.fireEvent('resize', this);
26944 setPositionByLatLng: function(latitude, longitude)
26946 this.setPosition(new google.maps.LatLng(latitude, longitude));
26949 getCurrentPosition: function()
26952 latitude: this.gMapContext.location.lat(),
26953 longitude: this.gMapContext.location.lng()
26957 getAddressName: function()
26959 return this.gMapContext.locationName;
26962 getAddressComponents: function()
26964 return this.gMapContext.addressComponents;
26967 address_component_from_google_geocode: function(address_components)
26971 for (var i = 0; i < address_components.length; i++) {
26972 var component = address_components[i];
26973 if (component.types.indexOf("postal_code") >= 0) {
26974 result.postalCode = component.short_name;
26975 } else if (component.types.indexOf("street_number") >= 0) {
26976 result.streetNumber = component.short_name;
26977 } else if (component.types.indexOf("route") >= 0) {
26978 result.streetName = component.short_name;
26979 } else if (component.types.indexOf("neighborhood") >= 0) {
26980 result.city = component.short_name;
26981 } else if (component.types.indexOf("locality") >= 0) {
26982 result.city = component.short_name;
26983 } else if (component.types.indexOf("sublocality") >= 0) {
26984 result.district = component.short_name;
26985 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
26986 result.stateOrProvince = component.short_name;
26987 } else if (component.types.indexOf("country") >= 0) {
26988 result.country = component.short_name;
26992 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
26993 result.addressLine2 = "";
26997 setZoomLevel: function(zoom)
26999 this.gMapContext.map.setZoom(zoom);
27012 this.fireEvent('show', this);
27023 this.fireEvent('hide', this);
27028 Roo.apply(Roo.bootstrap.LocationPicker, {
27030 OverlayView : function(map, options)
27032 options = options || {};
27046 * @class Roo.bootstrap.Alert
27047 * @extends Roo.bootstrap.Component
27048 * Bootstrap Alert class
27049 * @cfg {String} title The title of alert
27050 * @cfg {String} html The content of alert
27051 * @cfg {String} weight ( success | info | warning | danger )
27052 * @cfg {String} faicon font-awesomeicon
27055 * Create a new alert
27056 * @param {Object} config The config object
27060 Roo.bootstrap.Alert = function(config){
27061 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27065 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27072 getAutoCreate : function()
27081 cls : 'roo-alert-icon'
27086 cls : 'roo-alert-title',
27091 cls : 'roo-alert-text',
27098 cfg.cn[0].cls += ' fa ' + this.faicon;
27102 cfg.cls += ' alert-' + this.weight;
27108 initEvents: function()
27110 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27113 setTitle : function(str)
27115 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27118 setText : function(str)
27120 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27123 setWeight : function(weight)
27126 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27129 this.weight = weight;
27131 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27134 setIcon : function(icon)
27137 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27140 this.faicon = icon;
27142 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27163 * @class Roo.bootstrap.UploadCropbox
27164 * @extends Roo.bootstrap.Component
27165 * Bootstrap UploadCropbox class
27166 * @cfg {String} emptyText show when image has been loaded
27167 * @cfg {String} rotateNotify show when image too small to rotate
27168 * @cfg {Number} errorTimeout default 3000
27169 * @cfg {Number} minWidth default 300
27170 * @cfg {Number} minHeight default 300
27171 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27172 * @cfg {Boolean} isDocument (true|false) default false
27173 * @cfg {String} url action url
27174 * @cfg {String} paramName default 'imageUpload'
27175 * @cfg {String} method default POST
27176 * @cfg {Boolean} loadMask (true|false) default true
27177 * @cfg {Boolean} loadingText default 'Loading...'
27180 * Create a new UploadCropbox
27181 * @param {Object} config The config object
27184 Roo.bootstrap.UploadCropbox = function(config){
27185 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27189 * @event beforeselectfile
27190 * Fire before select file
27191 * @param {Roo.bootstrap.UploadCropbox} this
27193 "beforeselectfile" : true,
27196 * Fire after initEvent
27197 * @param {Roo.bootstrap.UploadCropbox} this
27202 * Fire after initEvent
27203 * @param {Roo.bootstrap.UploadCropbox} this
27204 * @param {String} data
27209 * Fire when preparing the file data
27210 * @param {Roo.bootstrap.UploadCropbox} this
27211 * @param {Object} file
27216 * Fire when get exception
27217 * @param {Roo.bootstrap.UploadCropbox} this
27218 * @param {XMLHttpRequest} xhr
27220 "exception" : true,
27222 * @event beforeloadcanvas
27223 * Fire before load the canvas
27224 * @param {Roo.bootstrap.UploadCropbox} this
27225 * @param {String} src
27227 "beforeloadcanvas" : true,
27230 * Fire when trash image
27231 * @param {Roo.bootstrap.UploadCropbox} this
27236 * Fire when download the image
27237 * @param {Roo.bootstrap.UploadCropbox} this
27241 * @event footerbuttonclick
27242 * Fire when footerbuttonclick
27243 * @param {Roo.bootstrap.UploadCropbox} this
27244 * @param {String} type
27246 "footerbuttonclick" : true,
27250 * @param {Roo.bootstrap.UploadCropbox} this
27255 * Fire when rotate the image
27256 * @param {Roo.bootstrap.UploadCropbox} this
27257 * @param {String} pos
27262 * Fire when inspect the file
27263 * @param {Roo.bootstrap.UploadCropbox} this
27264 * @param {Object} file
27269 * Fire when xhr upload the file
27270 * @param {Roo.bootstrap.UploadCropbox} this
27271 * @param {Object} data
27276 * Fire when arrange the file data
27277 * @param {Roo.bootstrap.UploadCropbox} this
27278 * @param {Object} formData
27283 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27286 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27288 emptyText : 'Click to upload image',
27289 rotateNotify : 'Image is too small to rotate',
27290 errorTimeout : 3000,
27304 cropType : 'image/jpeg',
27306 canvasLoaded : false,
27307 isDocument : false,
27309 paramName : 'imageUpload',
27311 loadingText : 'Loading...',
27314 getAutoCreate : function()
27318 cls : 'roo-upload-cropbox',
27322 cls : 'roo-upload-cropbox-selector',
27327 cls : 'roo-upload-cropbox-body',
27328 style : 'cursor:pointer',
27332 cls : 'roo-upload-cropbox-preview'
27336 cls : 'roo-upload-cropbox-thumb'
27340 cls : 'roo-upload-cropbox-empty-notify',
27341 html : this.emptyText
27345 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27346 html : this.rotateNotify
27352 cls : 'roo-upload-cropbox-footer',
27355 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27365 onRender : function(ct, position)
27367 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27369 if (this.buttons.length) {
27371 Roo.each(this.buttons, function(bb) {
27373 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27375 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27381 this.maskEl = this.el;
27385 initEvents : function()
27387 this.urlAPI = (window.createObjectURL && window) ||
27388 (window.URL && URL.revokeObjectURL && URL) ||
27389 (window.webkitURL && webkitURL);
27391 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27392 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27394 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27395 this.selectorEl.hide();
27397 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27398 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27400 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27401 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27402 this.thumbEl.hide();
27404 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27405 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27407 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27408 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27409 this.errorEl.hide();
27411 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27412 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27413 this.footerEl.hide();
27415 this.setThumbBoxSize();
27421 this.fireEvent('initial', this);
27428 window.addEventListener("resize", function() { _this.resize(); } );
27430 this.bodyEl.on('click', this.beforeSelectFile, this);
27433 this.bodyEl.on('touchstart', this.onTouchStart, this);
27434 this.bodyEl.on('touchmove', this.onTouchMove, this);
27435 this.bodyEl.on('touchend', this.onTouchEnd, this);
27439 this.bodyEl.on('mousedown', this.onMouseDown, this);
27440 this.bodyEl.on('mousemove', this.onMouseMove, this);
27441 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27442 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27443 Roo.get(document).on('mouseup', this.onMouseUp, this);
27446 this.selectorEl.on('change', this.onFileSelected, this);
27452 this.baseScale = 1;
27454 this.baseRotate = 1;
27455 this.dragable = false;
27456 this.pinching = false;
27459 this.cropData = false;
27460 this.notifyEl.dom.innerHTML = this.emptyText;
27462 this.selectorEl.dom.value = '';
27466 resize : function()
27468 if(this.fireEvent('resize', this) != false){
27469 this.setThumbBoxPosition();
27470 this.setCanvasPosition();
27474 onFooterButtonClick : function(e, el, o, type)
27477 case 'rotate-left' :
27478 this.onRotateLeft(e);
27480 case 'rotate-right' :
27481 this.onRotateRight(e);
27484 this.beforeSelectFile(e);
27499 this.fireEvent('footerbuttonclick', this, type);
27502 beforeSelectFile : function(e)
27504 e.preventDefault();
27506 if(this.fireEvent('beforeselectfile', this) != false){
27507 this.selectorEl.dom.click();
27511 onFileSelected : function(e)
27513 e.preventDefault();
27515 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27519 var file = this.selectorEl.dom.files[0];
27521 if(this.fireEvent('inspect', this, file) != false){
27522 this.prepare(file);
27527 trash : function(e)
27529 this.fireEvent('trash', this);
27532 download : function(e)
27534 this.fireEvent('download', this);
27537 loadCanvas : function(src)
27539 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27543 this.imageEl = document.createElement('img');
27547 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27549 this.imageEl.src = src;
27553 onLoadCanvas : function()
27555 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27556 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27558 this.bodyEl.un('click', this.beforeSelectFile, this);
27560 this.notifyEl.hide();
27561 this.thumbEl.show();
27562 this.footerEl.show();
27564 this.baseRotateLevel();
27566 if(this.isDocument){
27567 this.setThumbBoxSize();
27570 this.setThumbBoxPosition();
27572 this.baseScaleLevel();
27578 this.canvasLoaded = true;
27581 this.maskEl.unmask();
27586 setCanvasPosition : function()
27588 if(!this.canvasEl){
27592 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27593 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27595 this.previewEl.setLeft(pw);
27596 this.previewEl.setTop(ph);
27600 onMouseDown : function(e)
27604 this.dragable = true;
27605 this.pinching = false;
27607 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27608 this.dragable = false;
27612 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27613 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27617 onMouseMove : function(e)
27621 if(!this.canvasLoaded){
27625 if (!this.dragable){
27629 var minX = Math.ceil(this.thumbEl.getLeft(true));
27630 var minY = Math.ceil(this.thumbEl.getTop(true));
27632 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27633 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27635 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27636 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27638 x = x - this.mouseX;
27639 y = y - this.mouseY;
27641 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27642 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27644 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27645 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27647 this.previewEl.setLeft(bgX);
27648 this.previewEl.setTop(bgY);
27650 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27651 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27654 onMouseUp : function(e)
27658 this.dragable = false;
27661 onMouseWheel : function(e)
27665 this.startScale = this.scale;
27667 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27669 if(!this.zoomable()){
27670 this.scale = this.startScale;
27679 zoomable : function()
27681 var minScale = this.thumbEl.getWidth() / this.minWidth;
27683 if(this.minWidth < this.minHeight){
27684 minScale = this.thumbEl.getHeight() / this.minHeight;
27687 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27688 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27692 (this.rotate == 0 || this.rotate == 180) &&
27694 width > this.imageEl.OriginWidth ||
27695 height > this.imageEl.OriginHeight ||
27696 (width < this.minWidth && height < this.minHeight)
27704 (this.rotate == 90 || this.rotate == 270) &&
27706 width > this.imageEl.OriginWidth ||
27707 height > this.imageEl.OriginHeight ||
27708 (width < this.minHeight && height < this.minWidth)
27715 !this.isDocument &&
27716 (this.rotate == 0 || this.rotate == 180) &&
27718 width < this.minWidth ||
27719 width > this.imageEl.OriginWidth ||
27720 height < this.minHeight ||
27721 height > this.imageEl.OriginHeight
27728 !this.isDocument &&
27729 (this.rotate == 90 || this.rotate == 270) &&
27731 width < this.minHeight ||
27732 width > this.imageEl.OriginWidth ||
27733 height < this.minWidth ||
27734 height > this.imageEl.OriginHeight
27744 onRotateLeft : function(e)
27746 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27748 var minScale = this.thumbEl.getWidth() / this.minWidth;
27750 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27751 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27753 this.startScale = this.scale;
27755 while (this.getScaleLevel() < minScale){
27757 this.scale = this.scale + 1;
27759 if(!this.zoomable()){
27764 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27765 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27770 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27777 this.scale = this.startScale;
27779 this.onRotateFail();
27784 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27786 if(this.isDocument){
27787 this.setThumbBoxSize();
27788 this.setThumbBoxPosition();
27789 this.setCanvasPosition();
27794 this.fireEvent('rotate', this, 'left');
27798 onRotateRight : function(e)
27800 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27802 var minScale = this.thumbEl.getWidth() / this.minWidth;
27804 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27805 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27807 this.startScale = this.scale;
27809 while (this.getScaleLevel() < minScale){
27811 this.scale = this.scale + 1;
27813 if(!this.zoomable()){
27818 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27819 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27824 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27831 this.scale = this.startScale;
27833 this.onRotateFail();
27838 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27840 if(this.isDocument){
27841 this.setThumbBoxSize();
27842 this.setThumbBoxPosition();
27843 this.setCanvasPosition();
27848 this.fireEvent('rotate', this, 'right');
27851 onRotateFail : function()
27853 this.errorEl.show(true);
27857 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27862 this.previewEl.dom.innerHTML = '';
27864 var canvasEl = document.createElement("canvas");
27866 var contextEl = canvasEl.getContext("2d");
27868 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27869 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27870 var center = this.imageEl.OriginWidth / 2;
27872 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27873 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27874 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27875 center = this.imageEl.OriginHeight / 2;
27878 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27880 contextEl.translate(center, center);
27881 contextEl.rotate(this.rotate * Math.PI / 180);
27883 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27885 this.canvasEl = document.createElement("canvas");
27887 this.contextEl = this.canvasEl.getContext("2d");
27889 switch (this.rotate) {
27892 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27893 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27895 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27900 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27901 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27903 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27904 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27908 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27913 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27914 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27916 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27917 this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27921 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27926 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27927 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27929 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27930 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27934 this.contextEl.drawImage(canvasEl, 0, Math.abs(this.canvasEl.width - this.canvasEl.height), this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27941 this.previewEl.appendChild(this.canvasEl);
27943 this.setCanvasPosition();
27948 if(!this.canvasLoaded){
27952 var imageCanvas = document.createElement("canvas");
27954 var imageContext = imageCanvas.getContext("2d");
27956 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27957 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27959 var center = imageCanvas.width / 2;
27961 imageContext.translate(center, center);
27963 imageContext.rotate(this.rotate * Math.PI / 180);
27965 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27967 var canvas = document.createElement("canvas");
27969 var context = canvas.getContext("2d");
27971 canvas.width = this.minWidth;
27972 canvas.height = this.minHeight;
27974 switch (this.rotate) {
27977 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
27978 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
27980 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
27981 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
27983 var targetWidth = this.minWidth - 2 * x;
27984 var targetHeight = this.minHeight - 2 * y;
27988 if((x == 0 && y == 0) || (x == 0 && y > 0)){
27989 scale = targetWidth / width;
27992 if(x > 0 && y == 0){
27993 scale = targetHeight / height;
27996 if(x > 0 && y > 0){
27997 scale = targetWidth / width;
27999 if(width < height){
28000 scale = targetHeight / height;
28004 context.scale(scale, scale);
28006 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28007 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28009 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28010 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28012 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28017 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28018 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28020 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28021 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28023 var targetWidth = this.minWidth - 2 * x;
28024 var targetHeight = this.minHeight - 2 * y;
28028 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28029 scale = targetWidth / width;
28032 if(x > 0 && y == 0){
28033 scale = targetHeight / height;
28036 if(x > 0 && y > 0){
28037 scale = targetWidth / width;
28039 if(width < height){
28040 scale = targetHeight / height;
28044 context.scale(scale, scale);
28046 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28047 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28049 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28050 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28052 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28054 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28059 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28060 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28062 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28063 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28065 var targetWidth = this.minWidth - 2 * x;
28066 var targetHeight = this.minHeight - 2 * y;
28070 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28071 scale = targetWidth / width;
28074 if(x > 0 && y == 0){
28075 scale = targetHeight / height;
28078 if(x > 0 && y > 0){
28079 scale = targetWidth / width;
28081 if(width < height){
28082 scale = targetHeight / height;
28086 context.scale(scale, scale);
28088 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28089 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28091 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28092 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28094 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28095 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28097 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28102 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28103 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28105 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28106 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28108 var targetWidth = this.minWidth - 2 * x;
28109 var targetHeight = this.minHeight - 2 * y;
28113 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28114 scale = targetWidth / width;
28117 if(x > 0 && y == 0){
28118 scale = targetHeight / height;
28121 if(x > 0 && y > 0){
28122 scale = targetWidth / width;
28124 if(width < height){
28125 scale = targetHeight / height;
28129 context.scale(scale, scale);
28131 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28132 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28134 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28135 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28137 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28139 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28146 this.cropData = canvas.toDataURL(this.cropType);
28148 if(this.fireEvent('crop', this, this.cropData) !== false){
28149 this.process(this.file, this.cropData);
28156 setThumbBoxSize : function()
28160 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28161 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28162 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28164 this.minWidth = width;
28165 this.minHeight = height;
28167 if(this.rotate == 90 || this.rotate == 270){
28168 this.minWidth = height;
28169 this.minHeight = width;
28174 width = Math.ceil(this.minWidth * height / this.minHeight);
28176 if(this.minWidth > this.minHeight){
28178 height = Math.ceil(this.minHeight * width / this.minWidth);
28181 this.thumbEl.setStyle({
28182 width : width + 'px',
28183 height : height + 'px'
28190 setThumbBoxPosition : function()
28192 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28193 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28195 this.thumbEl.setLeft(x);
28196 this.thumbEl.setTop(y);
28200 baseRotateLevel : function()
28202 this.baseRotate = 1;
28205 typeof(this.exif) != 'undefined' &&
28206 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28207 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28209 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28212 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28216 baseScaleLevel : function()
28220 if(this.isDocument){
28222 if(this.baseRotate == 6 || this.baseRotate == 8){
28224 height = this.thumbEl.getHeight();
28225 this.baseScale = height / this.imageEl.OriginWidth;
28227 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28228 width = this.thumbEl.getWidth();
28229 this.baseScale = width / this.imageEl.OriginHeight;
28235 height = this.thumbEl.getHeight();
28236 this.baseScale = height / this.imageEl.OriginHeight;
28238 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28239 width = this.thumbEl.getWidth();
28240 this.baseScale = width / this.imageEl.OriginWidth;
28246 if(this.baseRotate == 6 || this.baseRotate == 8){
28248 width = this.thumbEl.getHeight();
28249 this.baseScale = width / this.imageEl.OriginHeight;
28251 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28252 height = this.thumbEl.getWidth();
28253 this.baseScale = height / this.imageEl.OriginHeight;
28256 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28257 height = this.thumbEl.getWidth();
28258 this.baseScale = height / this.imageEl.OriginHeight;
28260 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28261 width = this.thumbEl.getHeight();
28262 this.baseScale = width / this.imageEl.OriginWidth;
28269 width = this.thumbEl.getWidth();
28270 this.baseScale = width / this.imageEl.OriginWidth;
28272 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28273 height = this.thumbEl.getHeight();
28274 this.baseScale = height / this.imageEl.OriginHeight;
28277 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28279 height = this.thumbEl.getHeight();
28280 this.baseScale = height / this.imageEl.OriginHeight;
28282 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28283 width = this.thumbEl.getWidth();
28284 this.baseScale = width / this.imageEl.OriginWidth;
28292 getScaleLevel : function()
28294 return this.baseScale * Math.pow(1.1, this.scale);
28297 onTouchStart : function(e)
28299 if(!this.canvasLoaded){
28300 this.beforeSelectFile(e);
28304 var touches = e.browserEvent.touches;
28310 if(touches.length == 1){
28311 this.onMouseDown(e);
28315 if(touches.length != 2){
28321 for(var i = 0, finger; finger = touches[i]; i++){
28322 coords.push(finger.pageX, finger.pageY);
28325 var x = Math.pow(coords[0] - coords[2], 2);
28326 var y = Math.pow(coords[1] - coords[3], 2);
28328 this.startDistance = Math.sqrt(x + y);
28330 this.startScale = this.scale;
28332 this.pinching = true;
28333 this.dragable = false;
28337 onTouchMove : function(e)
28339 if(!this.pinching && !this.dragable){
28343 var touches = e.browserEvent.touches;
28350 this.onMouseMove(e);
28356 for(var i = 0, finger; finger = touches[i]; i++){
28357 coords.push(finger.pageX, finger.pageY);
28360 var x = Math.pow(coords[0] - coords[2], 2);
28361 var y = Math.pow(coords[1] - coords[3], 2);
28363 this.endDistance = Math.sqrt(x + y);
28365 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28367 if(!this.zoomable()){
28368 this.scale = this.startScale;
28376 onTouchEnd : function(e)
28378 this.pinching = false;
28379 this.dragable = false;
28383 process : function(file, crop)
28386 this.maskEl.mask(this.loadingText);
28389 this.xhr = new XMLHttpRequest();
28391 file.xhr = this.xhr;
28393 this.xhr.open(this.method, this.url, true);
28396 "Accept": "application/json",
28397 "Cache-Control": "no-cache",
28398 "X-Requested-With": "XMLHttpRequest"
28401 for (var headerName in headers) {
28402 var headerValue = headers[headerName];
28404 this.xhr.setRequestHeader(headerName, headerValue);
28410 this.xhr.onload = function()
28412 _this.xhrOnLoad(_this.xhr);
28415 this.xhr.onerror = function()
28417 _this.xhrOnError(_this.xhr);
28420 var formData = new FormData();
28422 formData.append('returnHTML', 'NO');
28425 formData.append('crop', crop);
28428 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28429 formData.append(this.paramName, file, file.name);
28432 if(typeof(file.filename) != 'undefined'){
28433 formData.append('filename', file.filename);
28436 if(typeof(file.mimetype) != 'undefined'){
28437 formData.append('mimetype', file.mimetype);
28440 if(this.fireEvent('arrange', this, formData) != false){
28441 this.xhr.send(formData);
28445 xhrOnLoad : function(xhr)
28448 this.maskEl.unmask();
28451 if (xhr.readyState !== 4) {
28452 this.fireEvent('exception', this, xhr);
28456 var response = Roo.decode(xhr.responseText);
28458 if(!response.success){
28459 this.fireEvent('exception', this, xhr);
28463 var response = Roo.decode(xhr.responseText);
28465 this.fireEvent('upload', this, response);
28469 xhrOnError : function()
28472 this.maskEl.unmask();
28475 Roo.log('xhr on error');
28477 var response = Roo.decode(xhr.responseText);
28483 prepare : function(file)
28486 this.maskEl.mask(this.loadingText);
28492 if(typeof(file) === 'string'){
28493 this.loadCanvas(file);
28497 if(!file || !this.urlAPI){
28502 this.cropType = file.type;
28506 if(this.fireEvent('prepare', this, this.file) != false){
28508 var reader = new FileReader();
28510 reader.onload = function (e) {
28511 if (e.target.error) {
28512 Roo.log(e.target.error);
28516 var buffer = e.target.result,
28517 dataView = new DataView(buffer),
28519 maxOffset = dataView.byteLength - 4,
28523 if (dataView.getUint16(0) === 0xffd8) {
28524 while (offset < maxOffset) {
28525 markerBytes = dataView.getUint16(offset);
28527 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28528 markerLength = dataView.getUint16(offset + 2) + 2;
28529 if (offset + markerLength > dataView.byteLength) {
28530 Roo.log('Invalid meta data: Invalid segment size.');
28534 if(markerBytes == 0xffe1){
28535 _this.parseExifData(
28542 offset += markerLength;
28552 var url = _this.urlAPI.createObjectURL(_this.file);
28554 _this.loadCanvas(url);
28559 reader.readAsArrayBuffer(this.file);
28565 parseExifData : function(dataView, offset, length)
28567 var tiffOffset = offset + 10,
28571 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28572 // No Exif data, might be XMP data instead
28576 // Check for the ASCII code for "Exif" (0x45786966):
28577 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28578 // No Exif data, might be XMP data instead
28581 if (tiffOffset + 8 > dataView.byteLength) {
28582 Roo.log('Invalid Exif data: Invalid segment size.');
28585 // Check for the two null bytes:
28586 if (dataView.getUint16(offset + 8) !== 0x0000) {
28587 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28590 // Check the byte alignment:
28591 switch (dataView.getUint16(tiffOffset)) {
28593 littleEndian = true;
28596 littleEndian = false;
28599 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28602 // Check for the TIFF tag marker (0x002A):
28603 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28604 Roo.log('Invalid Exif data: Missing TIFF marker.');
28607 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28608 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28610 this.parseExifTags(
28613 tiffOffset + dirOffset,
28618 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28623 if (dirOffset + 6 > dataView.byteLength) {
28624 Roo.log('Invalid Exif data: Invalid directory offset.');
28627 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28628 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28629 if (dirEndOffset + 4 > dataView.byteLength) {
28630 Roo.log('Invalid Exif data: Invalid directory size.');
28633 for (i = 0; i < tagsNumber; i += 1) {
28637 dirOffset + 2 + 12 * i, // tag offset
28641 // Return the offset to the next directory:
28642 return dataView.getUint32(dirEndOffset, littleEndian);
28645 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28647 var tag = dataView.getUint16(offset, littleEndian);
28649 this.exif[tag] = this.getExifValue(
28653 dataView.getUint16(offset + 2, littleEndian), // tag type
28654 dataView.getUint32(offset + 4, littleEndian), // tag length
28659 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28661 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28670 Roo.log('Invalid Exif data: Invalid tag type.');
28674 tagSize = tagType.size * length;
28675 // Determine if the value is contained in the dataOffset bytes,
28676 // or if the value at the dataOffset is a pointer to the actual data:
28677 dataOffset = tagSize > 4 ?
28678 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28679 if (dataOffset + tagSize > dataView.byteLength) {
28680 Roo.log('Invalid Exif data: Invalid data offset.');
28683 if (length === 1) {
28684 return tagType.getValue(dataView, dataOffset, littleEndian);
28687 for (i = 0; i < length; i += 1) {
28688 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28691 if (tagType.ascii) {
28693 // Concatenate the chars:
28694 for (i = 0; i < values.length; i += 1) {
28696 // Ignore the terminating NULL byte(s):
28697 if (c === '\u0000') {
28709 Roo.apply(Roo.bootstrap.UploadCropbox, {
28711 'Orientation': 0x0112
28715 1: 0, //'top-left',
28717 3: 180, //'bottom-right',
28718 // 4: 'bottom-left',
28720 6: 90, //'right-top',
28721 // 7: 'right-bottom',
28722 8: 270 //'left-bottom'
28726 // byte, 8-bit unsigned int:
28728 getValue: function (dataView, dataOffset) {
28729 return dataView.getUint8(dataOffset);
28733 // ascii, 8-bit byte:
28735 getValue: function (dataView, dataOffset) {
28736 return String.fromCharCode(dataView.getUint8(dataOffset));
28741 // short, 16 bit int:
28743 getValue: function (dataView, dataOffset, littleEndian) {
28744 return dataView.getUint16(dataOffset, littleEndian);
28748 // long, 32 bit int:
28750 getValue: function (dataView, dataOffset, littleEndian) {
28751 return dataView.getUint32(dataOffset, littleEndian);
28755 // rational = two long values, first is numerator, second is denominator:
28757 getValue: function (dataView, dataOffset, littleEndian) {
28758 return dataView.getUint32(dataOffset, littleEndian) /
28759 dataView.getUint32(dataOffset + 4, littleEndian);
28763 // slong, 32 bit signed int:
28765 getValue: function (dataView, dataOffset, littleEndian) {
28766 return dataView.getInt32(dataOffset, littleEndian);
28770 // srational, two slongs, first is numerator, second is denominator:
28772 getValue: function (dataView, dataOffset, littleEndian) {
28773 return dataView.getInt32(dataOffset, littleEndian) /
28774 dataView.getInt32(dataOffset + 4, littleEndian);
28784 cls : 'btn-group roo-upload-cropbox-rotate-left',
28785 action : 'rotate-left',
28789 cls : 'btn btn-default',
28790 html : '<i class="fa fa-undo"></i>'
28796 cls : 'btn-group roo-upload-cropbox-picture',
28797 action : 'picture',
28801 cls : 'btn btn-default',
28802 html : '<i class="fa fa-picture-o"></i>'
28808 cls : 'btn-group roo-upload-cropbox-rotate-right',
28809 action : 'rotate-right',
28813 cls : 'btn btn-default',
28814 html : '<i class="fa fa-repeat"></i>'
28822 cls : 'btn-group roo-upload-cropbox-rotate-left',
28823 action : 'rotate-left',
28827 cls : 'btn btn-default',
28828 html : '<i class="fa fa-undo"></i>'
28834 cls : 'btn-group roo-upload-cropbox-download',
28835 action : 'download',
28839 cls : 'btn btn-default',
28840 html : '<i class="fa fa-download"></i>'
28846 cls : 'btn-group roo-upload-cropbox-crop',
28851 cls : 'btn btn-default',
28852 html : '<i class="fa fa-crop"></i>'
28858 cls : 'btn-group roo-upload-cropbox-trash',
28863 cls : 'btn btn-default',
28864 html : '<i class="fa fa-trash"></i>'
28870 cls : 'btn-group roo-upload-cropbox-rotate-right',
28871 action : 'rotate-right',
28875 cls : 'btn btn-default',
28876 html : '<i class="fa fa-repeat"></i>'
28884 cls : 'btn-group roo-upload-cropbox-rotate-left',
28885 action : 'rotate-left',
28889 cls : 'btn btn-default',
28890 html : '<i class="fa fa-undo"></i>'
28896 cls : 'btn-group roo-upload-cropbox-rotate-right',
28897 action : 'rotate-right',
28901 cls : 'btn btn-default',
28902 html : '<i class="fa fa-repeat"></i>'
28915 * @class Roo.bootstrap.DocumentManager
28916 * @extends Roo.bootstrap.Component
28917 * Bootstrap DocumentManager class
28918 * @cfg {String} paramName default 'imageUpload'
28919 * @cfg {String} toolTipName default 'filename'
28920 * @cfg {String} method default POST
28921 * @cfg {String} url action url
28922 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28923 * @cfg {Boolean} multiple multiple upload default true
28924 * @cfg {Number} thumbSize default 300
28925 * @cfg {String} fieldLabel
28926 * @cfg {Number} labelWidth default 4
28927 * @cfg {String} labelAlign (left|top) default left
28928 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28929 * @cfg {Number} labellg set the width of label (1-12)
28930 * @cfg {Number} labelmd set the width of label (1-12)
28931 * @cfg {Number} labelsm set the width of label (1-12)
28932 * @cfg {Number} labelxs set the width of label (1-12)
28935 * Create a new DocumentManager
28936 * @param {Object} config The config object
28939 Roo.bootstrap.DocumentManager = function(config){
28940 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28943 this.delegates = [];
28948 * Fire when initial the DocumentManager
28949 * @param {Roo.bootstrap.DocumentManager} this
28954 * inspect selected file
28955 * @param {Roo.bootstrap.DocumentManager} this
28956 * @param {File} file
28961 * Fire when xhr load exception
28962 * @param {Roo.bootstrap.DocumentManager} this
28963 * @param {XMLHttpRequest} xhr
28965 "exception" : true,
28967 * @event afterupload
28968 * Fire when xhr load exception
28969 * @param {Roo.bootstrap.DocumentManager} this
28970 * @param {XMLHttpRequest} xhr
28972 "afterupload" : true,
28975 * prepare the form data
28976 * @param {Roo.bootstrap.DocumentManager} this
28977 * @param {Object} formData
28982 * Fire when remove the file
28983 * @param {Roo.bootstrap.DocumentManager} this
28984 * @param {Object} file
28989 * Fire after refresh the file
28990 * @param {Roo.bootstrap.DocumentManager} this
28995 * Fire after click the image
28996 * @param {Roo.bootstrap.DocumentManager} this
28997 * @param {Object} file
29002 * Fire when upload a image and editable set to true
29003 * @param {Roo.bootstrap.DocumentManager} this
29004 * @param {Object} file
29008 * @event beforeselectfile
29009 * Fire before select file
29010 * @param {Roo.bootstrap.DocumentManager} this
29012 "beforeselectfile" : true,
29015 * Fire before process file
29016 * @param {Roo.bootstrap.DocumentManager} this
29017 * @param {Object} file
29021 * @event previewrendered
29022 * Fire when preview rendered
29023 * @param {Roo.bootstrap.DocumentManager} this
29024 * @param {Object} file
29026 "previewrendered" : true,
29029 "previewResize" : true
29034 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29043 paramName : 'imageUpload',
29044 toolTipName : 'filename',
29047 labelAlign : 'left',
29057 getAutoCreate : function()
29059 var managerWidget = {
29061 cls : 'roo-document-manager',
29065 cls : 'roo-document-manager-selector',
29070 cls : 'roo-document-manager-uploader',
29074 cls : 'roo-document-manager-upload-btn',
29075 html : '<i class="fa fa-plus"></i>'
29086 cls : 'column col-md-12',
29091 if(this.fieldLabel.length){
29096 cls : 'column col-md-12',
29097 html : this.fieldLabel
29101 cls : 'column col-md-12',
29106 if(this.labelAlign == 'left'){
29111 html : this.fieldLabel
29120 if(this.labelWidth > 12){
29121 content[0].style = "width: " + this.labelWidth + 'px';
29124 if(this.labelWidth < 13 && this.labelmd == 0){
29125 this.labelmd = this.labelWidth;
29128 if(this.labellg > 0){
29129 content[0].cls += ' col-lg-' + this.labellg;
29130 content[1].cls += ' col-lg-' + (12 - this.labellg);
29133 if(this.labelmd > 0){
29134 content[0].cls += ' col-md-' + this.labelmd;
29135 content[1].cls += ' col-md-' + (12 - this.labelmd);
29138 if(this.labelsm > 0){
29139 content[0].cls += ' col-sm-' + this.labelsm;
29140 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29143 if(this.labelxs > 0){
29144 content[0].cls += ' col-xs-' + this.labelxs;
29145 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29153 cls : 'row clearfix',
29161 initEvents : function()
29163 this.managerEl = this.el.select('.roo-document-manager', true).first();
29164 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29166 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29167 this.selectorEl.hide();
29170 this.selectorEl.attr('multiple', 'multiple');
29173 this.selectorEl.on('change', this.onFileSelected, this);
29175 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29176 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29178 this.uploader.on('click', this.onUploaderClick, this);
29180 this.renderProgressDialog();
29184 window.addEventListener("resize", function() { _this.refresh(); } );
29186 this.fireEvent('initial', this);
29189 renderProgressDialog : function()
29193 this.progressDialog = new Roo.bootstrap.Modal({
29194 cls : 'roo-document-manager-progress-dialog',
29195 allow_close : false,
29206 btnclick : function() {
29207 _this.uploadCancel();
29213 this.progressDialog.render(Roo.get(document.body));
29215 this.progress = new Roo.bootstrap.Progress({
29216 cls : 'roo-document-manager-progress',
29221 this.progress.render(this.progressDialog.getChildContainer());
29223 this.progressBar = new Roo.bootstrap.ProgressBar({
29224 cls : 'roo-document-manager-progress-bar',
29227 aria_valuemax : 12,
29231 this.progressBar.render(this.progress.getChildContainer());
29234 onUploaderClick : function(e)
29236 e.preventDefault();
29238 if(this.fireEvent('beforeselectfile', this) != false){
29239 this.selectorEl.dom.click();
29244 onFileSelected : function(e)
29246 e.preventDefault();
29248 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29252 Roo.each(this.selectorEl.dom.files, function(file){
29253 if(this.fireEvent('inspect', this, file) != false){
29254 this.files.push(file);
29264 this.selectorEl.dom.value = '';
29266 if(!this.files || !this.files.length){
29270 if(this.boxes > 0 && this.files.length > this.boxes){
29271 this.files = this.files.slice(0, this.boxes);
29274 this.uploader.show();
29276 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29277 this.uploader.hide();
29286 Roo.each(this.files, function(file){
29288 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29289 var f = this.renderPreview(file);
29294 if(file.type.indexOf('image') != -1){
29295 this.delegates.push(
29297 _this.process(file);
29298 }).createDelegate(this)
29306 _this.process(file);
29307 }).createDelegate(this)
29312 this.files = files;
29314 this.delegates = this.delegates.concat(docs);
29316 if(!this.delegates.length){
29321 this.progressBar.aria_valuemax = this.delegates.length;
29328 arrange : function()
29330 if(!this.delegates.length){
29331 this.progressDialog.hide();
29336 var delegate = this.delegates.shift();
29338 this.progressDialog.show();
29340 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29342 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29347 refresh : function()
29349 this.uploader.show();
29351 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29352 this.uploader.hide();
29355 Roo.isTouch ? this.closable(false) : this.closable(true);
29357 this.fireEvent('refresh', this);
29360 onRemove : function(e, el, o)
29362 e.preventDefault();
29364 this.fireEvent('remove', this, o);
29368 remove : function(o)
29372 Roo.each(this.files, function(file){
29373 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29382 this.files = files;
29389 Roo.each(this.files, function(file){
29394 file.target.remove();
29403 onClick : function(e, el, o)
29405 e.preventDefault();
29407 this.fireEvent('click', this, o);
29411 closable : function(closable)
29413 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29415 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29427 xhrOnLoad : function(xhr)
29429 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29433 if (xhr.readyState !== 4) {
29435 this.fireEvent('exception', this, xhr);
29439 var response = Roo.decode(xhr.responseText);
29441 if(!response.success){
29443 this.fireEvent('exception', this, xhr);
29447 var file = this.renderPreview(response.data);
29449 this.files.push(file);
29453 this.fireEvent('afterupload', this, xhr);
29457 xhrOnError : function(xhr)
29459 Roo.log('xhr on error');
29461 var response = Roo.decode(xhr.responseText);
29468 process : function(file)
29470 if(this.fireEvent('process', this, file) !== false){
29471 if(this.editable && file.type.indexOf('image') != -1){
29472 this.fireEvent('edit', this, file);
29476 this.uploadStart(file, false);
29483 uploadStart : function(file, crop)
29485 this.xhr = new XMLHttpRequest();
29487 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29492 file.xhr = this.xhr;
29494 this.managerEl.createChild({
29496 cls : 'roo-document-manager-loading',
29500 tooltip : file.name,
29501 cls : 'roo-document-manager-thumb',
29502 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29508 this.xhr.open(this.method, this.url, true);
29511 "Accept": "application/json",
29512 "Cache-Control": "no-cache",
29513 "X-Requested-With": "XMLHttpRequest"
29516 for (var headerName in headers) {
29517 var headerValue = headers[headerName];
29519 this.xhr.setRequestHeader(headerName, headerValue);
29525 this.xhr.onload = function()
29527 _this.xhrOnLoad(_this.xhr);
29530 this.xhr.onerror = function()
29532 _this.xhrOnError(_this.xhr);
29535 var formData = new FormData();
29537 formData.append('returnHTML', 'NO');
29540 formData.append('crop', crop);
29543 formData.append(this.paramName, file, file.name);
29550 if(this.fireEvent('prepare', this, formData, options) != false){
29552 if(options.manually){
29556 this.xhr.send(formData);
29560 this.uploadCancel();
29563 uploadCancel : function()
29569 this.delegates = [];
29571 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29578 renderPreview : function(file)
29580 if(typeof(file.target) != 'undefined' && file.target){
29584 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29586 var previewEl = this.managerEl.createChild({
29588 cls : 'roo-document-manager-preview',
29592 tooltip : file[this.toolTipName],
29593 cls : 'roo-document-manager-thumb',
29594 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29599 html : '<i class="fa fa-times-circle"></i>'
29604 var close = previewEl.select('button.close', true).first();
29606 close.on('click', this.onRemove, this, file);
29608 file.target = previewEl;
29610 var image = previewEl.select('img', true).first();
29614 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29616 image.on('click', this.onClick, this, file);
29618 this.fireEvent('previewrendered', this, file);
29624 onPreviewLoad : function(file, image)
29626 if(typeof(file.target) == 'undefined' || !file.target){
29630 var width = image.dom.naturalWidth || image.dom.width;
29631 var height = image.dom.naturalHeight || image.dom.height;
29633 if(!this.previewResize) {
29637 if(width > height){
29638 file.target.addClass('wide');
29642 file.target.addClass('tall');
29647 uploadFromSource : function(file, crop)
29649 this.xhr = new XMLHttpRequest();
29651 this.managerEl.createChild({
29653 cls : 'roo-document-manager-loading',
29657 tooltip : file.name,
29658 cls : 'roo-document-manager-thumb',
29659 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29665 this.xhr.open(this.method, this.url, true);
29668 "Accept": "application/json",
29669 "Cache-Control": "no-cache",
29670 "X-Requested-With": "XMLHttpRequest"
29673 for (var headerName in headers) {
29674 var headerValue = headers[headerName];
29676 this.xhr.setRequestHeader(headerName, headerValue);
29682 this.xhr.onload = function()
29684 _this.xhrOnLoad(_this.xhr);
29687 this.xhr.onerror = function()
29689 _this.xhrOnError(_this.xhr);
29692 var formData = new FormData();
29694 formData.append('returnHTML', 'NO');
29696 formData.append('crop', crop);
29698 if(typeof(file.filename) != 'undefined'){
29699 formData.append('filename', file.filename);
29702 if(typeof(file.mimetype) != 'undefined'){
29703 formData.append('mimetype', file.mimetype);
29708 if(this.fireEvent('prepare', this, formData) != false){
29709 this.xhr.send(formData);
29719 * @class Roo.bootstrap.DocumentViewer
29720 * @extends Roo.bootstrap.Component
29721 * Bootstrap DocumentViewer class
29722 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29723 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29726 * Create a new DocumentViewer
29727 * @param {Object} config The config object
29730 Roo.bootstrap.DocumentViewer = function(config){
29731 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29736 * Fire after initEvent
29737 * @param {Roo.bootstrap.DocumentViewer} this
29743 * @param {Roo.bootstrap.DocumentViewer} this
29748 * Fire after download button
29749 * @param {Roo.bootstrap.DocumentViewer} this
29754 * Fire after trash button
29755 * @param {Roo.bootstrap.DocumentViewer} this
29762 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29764 showDownload : true,
29768 getAutoCreate : function()
29772 cls : 'roo-document-viewer',
29776 cls : 'roo-document-viewer-body',
29780 cls : 'roo-document-viewer-thumb',
29784 cls : 'roo-document-viewer-image'
29792 cls : 'roo-document-viewer-footer',
29795 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29799 cls : 'btn-group roo-document-viewer-download',
29803 cls : 'btn btn-default',
29804 html : '<i class="fa fa-download"></i>'
29810 cls : 'btn-group roo-document-viewer-trash',
29814 cls : 'btn btn-default',
29815 html : '<i class="fa fa-trash"></i>'
29828 initEvents : function()
29830 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29831 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29833 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29834 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29836 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29837 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29839 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29840 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29842 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29843 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29845 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29846 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29848 this.bodyEl.on('click', this.onClick, this);
29849 this.downloadBtn.on('click', this.onDownload, this);
29850 this.trashBtn.on('click', this.onTrash, this);
29852 this.downloadBtn.hide();
29853 this.trashBtn.hide();
29855 if(this.showDownload){
29856 this.downloadBtn.show();
29859 if(this.showTrash){
29860 this.trashBtn.show();
29863 if(!this.showDownload && !this.showTrash) {
29864 this.footerEl.hide();
29869 initial : function()
29871 this.fireEvent('initial', this);
29875 onClick : function(e)
29877 e.preventDefault();
29879 this.fireEvent('click', this);
29882 onDownload : function(e)
29884 e.preventDefault();
29886 this.fireEvent('download', this);
29889 onTrash : function(e)
29891 e.preventDefault();
29893 this.fireEvent('trash', this);
29905 * @class Roo.bootstrap.NavProgressBar
29906 * @extends Roo.bootstrap.Component
29907 * Bootstrap NavProgressBar class
29910 * Create a new nav progress bar
29911 * @param {Object} config The config object
29914 Roo.bootstrap.NavProgressBar = function(config){
29915 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29917 this.bullets = this.bullets || [];
29919 // Roo.bootstrap.NavProgressBar.register(this);
29923 * Fires when the active item changes
29924 * @param {Roo.bootstrap.NavProgressBar} this
29925 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29926 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29933 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29938 getAutoCreate : function()
29940 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29944 cls : 'roo-navigation-bar-group',
29948 cls : 'roo-navigation-top-bar'
29952 cls : 'roo-navigation-bullets-bar',
29956 cls : 'roo-navigation-bar'
29963 cls : 'roo-navigation-bottom-bar'
29973 initEvents: function()
29978 onRender : function(ct, position)
29980 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
29982 if(this.bullets.length){
29983 Roo.each(this.bullets, function(b){
29992 addItem : function(cfg)
29994 var item = new Roo.bootstrap.NavProgressItem(cfg);
29996 item.parentId = this.id;
29997 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30000 var top = new Roo.bootstrap.Element({
30002 cls : 'roo-navigation-bar-text'
30005 var bottom = new Roo.bootstrap.Element({
30007 cls : 'roo-navigation-bar-text'
30010 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30011 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30013 var topText = new Roo.bootstrap.Element({
30015 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30018 var bottomText = new Roo.bootstrap.Element({
30020 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30023 topText.onRender(top.el, null);
30024 bottomText.onRender(bottom.el, null);
30027 item.bottomEl = bottom;
30030 this.barItems.push(item);
30035 getActive : function()
30037 var active = false;
30039 Roo.each(this.barItems, function(v){
30041 if (!v.isActive()) {
30053 setActiveItem : function(item)
30057 Roo.each(this.barItems, function(v){
30058 if (v.rid == item.rid) {
30062 if (v.isActive()) {
30063 v.setActive(false);
30068 item.setActive(true);
30070 this.fireEvent('changed', this, item, prev);
30073 getBarItem: function(rid)
30077 Roo.each(this.barItems, function(e) {
30078 if (e.rid != rid) {
30089 indexOfItem : function(item)
30093 Roo.each(this.barItems, function(v, i){
30095 if (v.rid != item.rid) {
30106 setActiveNext : function()
30108 var i = this.indexOfItem(this.getActive());
30110 if (i > this.barItems.length) {
30114 this.setActiveItem(this.barItems[i+1]);
30117 setActivePrev : function()
30119 var i = this.indexOfItem(this.getActive());
30125 this.setActiveItem(this.barItems[i-1]);
30128 format : function()
30130 if(!this.barItems.length){
30134 var width = 100 / this.barItems.length;
30136 Roo.each(this.barItems, function(i){
30137 i.el.setStyle('width', width + '%');
30138 i.topEl.el.setStyle('width', width + '%');
30139 i.bottomEl.el.setStyle('width', width + '%');
30148 * Nav Progress Item
30153 * @class Roo.bootstrap.NavProgressItem
30154 * @extends Roo.bootstrap.Component
30155 * Bootstrap NavProgressItem class
30156 * @cfg {String} rid the reference id
30157 * @cfg {Boolean} active (true|false) Is item active default false
30158 * @cfg {Boolean} disabled (true|false) Is item active default false
30159 * @cfg {String} html
30160 * @cfg {String} position (top|bottom) text position default bottom
30161 * @cfg {String} icon show icon instead of number
30164 * Create a new NavProgressItem
30165 * @param {Object} config The config object
30167 Roo.bootstrap.NavProgressItem = function(config){
30168 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30173 * The raw click event for the entire grid.
30174 * @param {Roo.bootstrap.NavProgressItem} this
30175 * @param {Roo.EventObject} e
30182 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30188 position : 'bottom',
30191 getAutoCreate : function()
30193 var iconCls = 'roo-navigation-bar-item-icon';
30195 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30199 cls: 'roo-navigation-bar-item',
30209 cfg.cls += ' active';
30212 cfg.cls += ' disabled';
30218 disable : function()
30220 this.setDisabled(true);
30223 enable : function()
30225 this.setDisabled(false);
30228 initEvents: function()
30230 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30232 this.iconEl.on('click', this.onClick, this);
30235 onClick : function(e)
30237 e.preventDefault();
30243 if(this.fireEvent('click', this, e) === false){
30247 this.parent().setActiveItem(this);
30250 isActive: function ()
30252 return this.active;
30255 setActive : function(state)
30257 if(this.active == state){
30261 this.active = state;
30264 this.el.addClass('active');
30268 this.el.removeClass('active');
30273 setDisabled : function(state)
30275 if(this.disabled == state){
30279 this.disabled = state;
30282 this.el.addClass('disabled');
30286 this.el.removeClass('disabled');
30289 tooltipEl : function()
30291 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30304 * @class Roo.bootstrap.FieldLabel
30305 * @extends Roo.bootstrap.Component
30306 * Bootstrap FieldLabel class
30307 * @cfg {String} html contents of the element
30308 * @cfg {String} tag tag of the element default label
30309 * @cfg {String} cls class of the element
30310 * @cfg {String} target label target
30311 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30312 * @cfg {String} invalidClass default "text-warning"
30313 * @cfg {String} validClass default "text-success"
30314 * @cfg {String} iconTooltip default "This field is required"
30315 * @cfg {String} indicatorpos (left|right) default left
30318 * Create a new FieldLabel
30319 * @param {Object} config The config object
30322 Roo.bootstrap.FieldLabel = function(config){
30323 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30328 * Fires after the field has been marked as invalid.
30329 * @param {Roo.form.FieldLabel} this
30330 * @param {String} msg The validation message
30335 * Fires after the field has been validated with no errors.
30336 * @param {Roo.form.FieldLabel} this
30342 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30349 invalidClass : 'has-warning',
30350 validClass : 'has-success',
30351 iconTooltip : 'This field is required',
30352 indicatorpos : 'left',
30354 getAutoCreate : function(){
30357 if (!this.allowBlank) {
30363 cls : 'roo-bootstrap-field-label ' + this.cls,
30368 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30369 tooltip : this.iconTooltip
30378 if(this.indicatorpos == 'right'){
30381 cls : 'roo-bootstrap-field-label ' + this.cls,
30390 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30391 tooltip : this.iconTooltip
30400 initEvents: function()
30402 Roo.bootstrap.Element.superclass.initEvents.call(this);
30404 this.indicator = this.indicatorEl();
30406 if(this.indicator){
30407 this.indicator.removeClass('visible');
30408 this.indicator.addClass('invisible');
30411 Roo.bootstrap.FieldLabel.register(this);
30414 indicatorEl : function()
30416 var indicator = this.el.select('i.roo-required-indicator',true).first();
30427 * Mark this field as valid
30429 markValid : function()
30431 if(this.indicator){
30432 this.indicator.removeClass('visible');
30433 this.indicator.addClass('invisible');
30436 this.el.removeClass(this.invalidClass);
30438 this.el.addClass(this.validClass);
30440 this.fireEvent('valid', this);
30444 * Mark this field as invalid
30445 * @param {String} msg The validation message
30447 markInvalid : function(msg)
30449 if(this.indicator){
30450 this.indicator.removeClass('invisible');
30451 this.indicator.addClass('visible');
30454 this.el.removeClass(this.validClass);
30456 this.el.addClass(this.invalidClass);
30458 this.fireEvent('invalid', this, msg);
30464 Roo.apply(Roo.bootstrap.FieldLabel, {
30469 * register a FieldLabel Group
30470 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30472 register : function(label)
30474 if(this.groups.hasOwnProperty(label.target)){
30478 this.groups[label.target] = label;
30482 * fetch a FieldLabel Group based on the target
30483 * @param {string} target
30484 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30486 get: function(target) {
30487 if (typeof(this.groups[target]) == 'undefined') {
30491 return this.groups[target] ;
30500 * page DateSplitField.
30506 * @class Roo.bootstrap.DateSplitField
30507 * @extends Roo.bootstrap.Component
30508 * Bootstrap DateSplitField class
30509 * @cfg {string} fieldLabel - the label associated
30510 * @cfg {Number} labelWidth set the width of label (0-12)
30511 * @cfg {String} labelAlign (top|left)
30512 * @cfg {Boolean} dayAllowBlank (true|false) default false
30513 * @cfg {Boolean} monthAllowBlank (true|false) default false
30514 * @cfg {Boolean} yearAllowBlank (true|false) default false
30515 * @cfg {string} dayPlaceholder
30516 * @cfg {string} monthPlaceholder
30517 * @cfg {string} yearPlaceholder
30518 * @cfg {string} dayFormat default 'd'
30519 * @cfg {string} monthFormat default 'm'
30520 * @cfg {string} yearFormat default 'Y'
30521 * @cfg {Number} labellg set the width of label (1-12)
30522 * @cfg {Number} labelmd set the width of label (1-12)
30523 * @cfg {Number} labelsm set the width of label (1-12)
30524 * @cfg {Number} labelxs set the width of label (1-12)
30528 * Create a new DateSplitField
30529 * @param {Object} config The config object
30532 Roo.bootstrap.DateSplitField = function(config){
30533 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30539 * getting the data of years
30540 * @param {Roo.bootstrap.DateSplitField} this
30541 * @param {Object} years
30546 * getting the data of days
30547 * @param {Roo.bootstrap.DateSplitField} this
30548 * @param {Object} days
30553 * Fires after the field has been marked as invalid.
30554 * @param {Roo.form.Field} this
30555 * @param {String} msg The validation message
30560 * Fires after the field has been validated with no errors.
30561 * @param {Roo.form.Field} this
30567 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30570 labelAlign : 'top',
30572 dayAllowBlank : false,
30573 monthAllowBlank : false,
30574 yearAllowBlank : false,
30575 dayPlaceholder : '',
30576 monthPlaceholder : '',
30577 yearPlaceholder : '',
30581 isFormField : true,
30587 getAutoCreate : function()
30591 cls : 'row roo-date-split-field-group',
30596 cls : 'form-hidden-field roo-date-split-field-group-value',
30602 var labelCls = 'col-md-12';
30603 var contentCls = 'col-md-4';
30605 if(this.fieldLabel){
30609 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30613 html : this.fieldLabel
30618 if(this.labelAlign == 'left'){
30620 if(this.labelWidth > 12){
30621 label.style = "width: " + this.labelWidth + 'px';
30624 if(this.labelWidth < 13 && this.labelmd == 0){
30625 this.labelmd = this.labelWidth;
30628 if(this.labellg > 0){
30629 labelCls = ' col-lg-' + this.labellg;
30630 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30633 if(this.labelmd > 0){
30634 labelCls = ' col-md-' + this.labelmd;
30635 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30638 if(this.labelsm > 0){
30639 labelCls = ' col-sm-' + this.labelsm;
30640 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30643 if(this.labelxs > 0){
30644 labelCls = ' col-xs-' + this.labelxs;
30645 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30649 label.cls += ' ' + labelCls;
30651 cfg.cn.push(label);
30654 Roo.each(['day', 'month', 'year'], function(t){
30657 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30664 inputEl: function ()
30666 return this.el.select('.roo-date-split-field-group-value', true).first();
30669 onRender : function(ct, position)
30673 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30675 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30677 this.dayField = new Roo.bootstrap.ComboBox({
30678 allowBlank : this.dayAllowBlank,
30679 alwaysQuery : true,
30680 displayField : 'value',
30683 forceSelection : true,
30685 placeholder : this.dayPlaceholder,
30686 selectOnFocus : true,
30687 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30688 triggerAction : 'all',
30690 valueField : 'value',
30691 store : new Roo.data.SimpleStore({
30692 data : (function() {
30694 _this.fireEvent('days', _this, days);
30697 fields : [ 'value' ]
30700 select : function (_self, record, index)
30702 _this.setValue(_this.getValue());
30707 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30709 this.monthField = new Roo.bootstrap.MonthField({
30710 after : '<i class=\"fa fa-calendar\"></i>',
30711 allowBlank : this.monthAllowBlank,
30712 placeholder : this.monthPlaceholder,
30715 render : function (_self)
30717 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30718 e.preventDefault();
30722 select : function (_self, oldvalue, newvalue)
30724 _this.setValue(_this.getValue());
30729 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30731 this.yearField = new Roo.bootstrap.ComboBox({
30732 allowBlank : this.yearAllowBlank,
30733 alwaysQuery : true,
30734 displayField : 'value',
30737 forceSelection : true,
30739 placeholder : this.yearPlaceholder,
30740 selectOnFocus : true,
30741 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30742 triggerAction : 'all',
30744 valueField : 'value',
30745 store : new Roo.data.SimpleStore({
30746 data : (function() {
30748 _this.fireEvent('years', _this, years);
30751 fields : [ 'value' ]
30754 select : function (_self, record, index)
30756 _this.setValue(_this.getValue());
30761 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30764 setValue : function(v, format)
30766 this.inputEl.dom.value = v;
30768 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30770 var d = Date.parseDate(v, f);
30777 this.setDay(d.format(this.dayFormat));
30778 this.setMonth(d.format(this.monthFormat));
30779 this.setYear(d.format(this.yearFormat));
30786 setDay : function(v)
30788 this.dayField.setValue(v);
30789 this.inputEl.dom.value = this.getValue();
30794 setMonth : function(v)
30796 this.monthField.setValue(v, true);
30797 this.inputEl.dom.value = this.getValue();
30802 setYear : function(v)
30804 this.yearField.setValue(v);
30805 this.inputEl.dom.value = this.getValue();
30810 getDay : function()
30812 return this.dayField.getValue();
30815 getMonth : function()
30817 return this.monthField.getValue();
30820 getYear : function()
30822 return this.yearField.getValue();
30825 getValue : function()
30827 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30829 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30839 this.inputEl.dom.value = '';
30844 validate : function()
30846 var d = this.dayField.validate();
30847 var m = this.monthField.validate();
30848 var y = this.yearField.validate();
30853 (!this.dayAllowBlank && !d) ||
30854 (!this.monthAllowBlank && !m) ||
30855 (!this.yearAllowBlank && !y)
30860 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30869 this.markInvalid();
30874 markValid : function()
30877 var label = this.el.select('label', true).first();
30878 var icon = this.el.select('i.fa-star', true).first();
30884 this.fireEvent('valid', this);
30888 * Mark this field as invalid
30889 * @param {String} msg The validation message
30891 markInvalid : function(msg)
30894 var label = this.el.select('label', true).first();
30895 var icon = this.el.select('i.fa-star', true).first();
30897 if(label && !icon){
30898 this.el.select('.roo-date-split-field-label', true).createChild({
30900 cls : 'text-danger fa fa-lg fa-star',
30901 tooltip : 'This field is required',
30902 style : 'margin-right:5px;'
30906 this.fireEvent('invalid', this, msg);
30909 clearInvalid : function()
30911 var label = this.el.select('label', true).first();
30912 var icon = this.el.select('i.fa-star', true).first();
30918 this.fireEvent('valid', this);
30921 getName: function()
30931 * http://masonry.desandro.com
30933 * The idea is to render all the bricks based on vertical width...
30935 * The original code extends 'outlayer' - we might need to use that....
30941 * @class Roo.bootstrap.LayoutMasonry
30942 * @extends Roo.bootstrap.Component
30943 * Bootstrap Layout Masonry class
30946 * Create a new Element
30947 * @param {Object} config The config object
30950 Roo.bootstrap.LayoutMasonry = function(config){
30952 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30956 Roo.bootstrap.LayoutMasonry.register(this);
30962 * Fire after layout the items
30963 * @param {Roo.bootstrap.LayoutMasonry} this
30964 * @param {Roo.EventObject} e
30971 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30974 * @cfg {Boolean} isLayoutInstant = no animation?
30976 isLayoutInstant : false, // needed?
30979 * @cfg {Number} boxWidth width of the columns
30984 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
30989 * @cfg {Number} padWidth padding below box..
30994 * @cfg {Number} gutter gutter width..
30999 * @cfg {Number} maxCols maximum number of columns
31005 * @cfg {Boolean} isAutoInitial defalut true
31007 isAutoInitial : true,
31012 * @cfg {Boolean} isHorizontal defalut false
31014 isHorizontal : false,
31016 currentSize : null,
31022 bricks: null, //CompositeElement
31026 _isLayoutInited : false,
31028 // isAlternative : false, // only use for vertical layout...
31031 * @cfg {Number} alternativePadWidth padding below box..
31033 alternativePadWidth : 50,
31035 selectedBrick : [],
31037 getAutoCreate : function(){
31039 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31043 cls: 'blog-masonary-wrapper ' + this.cls,
31045 cls : 'mas-boxes masonary'
31052 getChildContainer: function( )
31054 if (this.boxesEl) {
31055 return this.boxesEl;
31058 this.boxesEl = this.el.select('.mas-boxes').first();
31060 return this.boxesEl;
31064 initEvents : function()
31068 if(this.isAutoInitial){
31069 Roo.log('hook children rendered');
31070 this.on('childrenrendered', function() {
31071 Roo.log('children rendered');
31077 initial : function()
31079 this.selectedBrick = [];
31081 this.currentSize = this.el.getBox(true);
31083 Roo.EventManager.onWindowResize(this.resize, this);
31085 if(!this.isAutoInitial){
31093 //this.layout.defer(500,this);
31097 resize : function()
31099 var cs = this.el.getBox(true);
31102 this.currentSize.width == cs.width &&
31103 this.currentSize.x == cs.x &&
31104 this.currentSize.height == cs.height &&
31105 this.currentSize.y == cs.y
31107 Roo.log("no change in with or X or Y");
31111 this.currentSize = cs;
31117 layout : function()
31119 this._resetLayout();
31121 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31123 this.layoutItems( isInstant );
31125 this._isLayoutInited = true;
31127 this.fireEvent('layout', this);
31131 _resetLayout : function()
31133 if(this.isHorizontal){
31134 this.horizontalMeasureColumns();
31138 this.verticalMeasureColumns();
31142 verticalMeasureColumns : function()
31144 this.getContainerWidth();
31146 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31147 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31151 var boxWidth = this.boxWidth + this.padWidth;
31153 if(this.containerWidth < this.boxWidth){
31154 boxWidth = this.containerWidth
31157 var containerWidth = this.containerWidth;
31159 var cols = Math.floor(containerWidth / boxWidth);
31161 this.cols = Math.max( cols, 1 );
31163 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31165 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31167 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31169 this.colWidth = boxWidth + avail - this.padWidth;
31171 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31172 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31175 horizontalMeasureColumns : function()
31177 this.getContainerWidth();
31179 var boxWidth = this.boxWidth;
31181 if(this.containerWidth < boxWidth){
31182 boxWidth = this.containerWidth;
31185 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31187 this.el.setHeight(boxWidth);
31191 getContainerWidth : function()
31193 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31196 layoutItems : function( isInstant )
31198 Roo.log(this.bricks);
31200 var items = Roo.apply([], this.bricks);
31202 if(this.isHorizontal){
31203 this._horizontalLayoutItems( items , isInstant );
31207 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31208 // this._verticalAlternativeLayoutItems( items , isInstant );
31212 this._verticalLayoutItems( items , isInstant );
31216 _verticalLayoutItems : function ( items , isInstant)
31218 if ( !items || !items.length ) {
31223 ['xs', 'xs', 'xs', 'tall'],
31224 ['xs', 'xs', 'tall'],
31225 ['xs', 'xs', 'sm'],
31226 ['xs', 'xs', 'xs'],
31232 ['sm', 'xs', 'xs'],
31236 ['tall', 'xs', 'xs', 'xs'],
31237 ['tall', 'xs', 'xs'],
31249 Roo.each(items, function(item, k){
31251 switch (item.size) {
31252 // these layouts take up a full box,
31263 boxes.push([item]);
31286 var filterPattern = function(box, length)
31294 var pattern = box.slice(0, length);
31298 Roo.each(pattern, function(i){
31299 format.push(i.size);
31302 Roo.each(standard, function(s){
31304 if(String(s) != String(format)){
31313 if(!match && length == 1){
31318 filterPattern(box, length - 1);
31322 queue.push(pattern);
31324 box = box.slice(length, box.length);
31326 filterPattern(box, 4);
31332 Roo.each(boxes, function(box, k){
31338 if(box.length == 1){
31343 filterPattern(box, 4);
31347 this._processVerticalLayoutQueue( queue, isInstant );
31351 // _verticalAlternativeLayoutItems : function( items , isInstant )
31353 // if ( !items || !items.length ) {
31357 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31361 _horizontalLayoutItems : function ( items , isInstant)
31363 if ( !items || !items.length || items.length < 3) {
31369 var eItems = items.slice(0, 3);
31371 items = items.slice(3, items.length);
31374 ['xs', 'xs', 'xs', 'wide'],
31375 ['xs', 'xs', 'wide'],
31376 ['xs', 'xs', 'sm'],
31377 ['xs', 'xs', 'xs'],
31383 ['sm', 'xs', 'xs'],
31387 ['wide', 'xs', 'xs', 'xs'],
31388 ['wide', 'xs', 'xs'],
31401 Roo.each(items, function(item, k){
31403 switch (item.size) {
31414 boxes.push([item]);
31438 var filterPattern = function(box, length)
31446 var pattern = box.slice(0, length);
31450 Roo.each(pattern, function(i){
31451 format.push(i.size);
31454 Roo.each(standard, function(s){
31456 if(String(s) != String(format)){
31465 if(!match && length == 1){
31470 filterPattern(box, length - 1);
31474 queue.push(pattern);
31476 box = box.slice(length, box.length);
31478 filterPattern(box, 4);
31484 Roo.each(boxes, function(box, k){
31490 if(box.length == 1){
31495 filterPattern(box, 4);
31502 var pos = this.el.getBox(true);
31506 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31508 var hit_end = false;
31510 Roo.each(queue, function(box){
31514 Roo.each(box, function(b){
31516 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31526 Roo.each(box, function(b){
31528 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31531 mx = Math.max(mx, b.x);
31535 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31539 Roo.each(box, function(b){
31541 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31555 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31558 /** Sets position of item in DOM
31559 * @param {Element} item
31560 * @param {Number} x - horizontal position
31561 * @param {Number} y - vertical position
31562 * @param {Boolean} isInstant - disables transitions
31564 _processVerticalLayoutQueue : function( queue, isInstant )
31566 var pos = this.el.getBox(true);
31571 for (var i = 0; i < this.cols; i++){
31575 Roo.each(queue, function(box, k){
31577 var col = k % this.cols;
31579 Roo.each(box, function(b,kk){
31581 b.el.position('absolute');
31583 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31584 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31586 if(b.size == 'md-left' || b.size == 'md-right'){
31587 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31588 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31591 b.el.setWidth(width);
31592 b.el.setHeight(height);
31594 b.el.select('iframe',true).setSize(width,height);
31598 for (var i = 0; i < this.cols; i++){
31600 if(maxY[i] < maxY[col]){
31605 col = Math.min(col, i);
31609 x = pos.x + col * (this.colWidth + this.padWidth);
31613 var positions = [];
31615 switch (box.length){
31617 positions = this.getVerticalOneBoxColPositions(x, y, box);
31620 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31623 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31626 positions = this.getVerticalFourBoxColPositions(x, y, box);
31632 Roo.each(box, function(b,kk){
31634 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31636 var sz = b.el.getSize();
31638 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31646 for (var i = 0; i < this.cols; i++){
31647 mY = Math.max(mY, maxY[i]);
31650 this.el.setHeight(mY - pos.y);
31654 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31656 // var pos = this.el.getBox(true);
31659 // var maxX = pos.right;
31661 // var maxHeight = 0;
31663 // Roo.each(items, function(item, k){
31667 // item.el.position('absolute');
31669 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31671 // item.el.setWidth(width);
31673 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31675 // item.el.setHeight(height);
31678 // item.el.setXY([x, y], isInstant ? false : true);
31680 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31683 // y = y + height + this.alternativePadWidth;
31685 // maxHeight = maxHeight + height + this.alternativePadWidth;
31689 // this.el.setHeight(maxHeight);
31693 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31695 var pos = this.el.getBox(true);
31700 var maxX = pos.right;
31702 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31704 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31706 Roo.each(queue, function(box, k){
31708 Roo.each(box, function(b, kk){
31710 b.el.position('absolute');
31712 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31713 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31715 if(b.size == 'md-left' || b.size == 'md-right'){
31716 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31717 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31720 b.el.setWidth(width);
31721 b.el.setHeight(height);
31729 var positions = [];
31731 switch (box.length){
31733 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31736 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31739 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31742 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31748 Roo.each(box, function(b,kk){
31750 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31752 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31760 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31762 Roo.each(eItems, function(b,k){
31764 b.size = (k == 0) ? 'sm' : 'xs';
31765 b.x = (k == 0) ? 2 : 1;
31766 b.y = (k == 0) ? 2 : 1;
31768 b.el.position('absolute');
31770 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31772 b.el.setWidth(width);
31774 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31776 b.el.setHeight(height);
31780 var positions = [];
31783 x : maxX - this.unitWidth * 2 - this.gutter,
31788 x : maxX - this.unitWidth,
31789 y : minY + (this.unitWidth + this.gutter) * 2
31793 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31797 Roo.each(eItems, function(b,k){
31799 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31805 getVerticalOneBoxColPositions : function(x, y, box)
31809 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31811 if(box[0].size == 'md-left'){
31815 if(box[0].size == 'md-right'){
31820 x : x + (this.unitWidth + this.gutter) * rand,
31827 getVerticalTwoBoxColPositions : function(x, y, box)
31831 if(box[0].size == 'xs'){
31835 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31839 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31853 x : x + (this.unitWidth + this.gutter) * 2,
31854 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31861 getVerticalThreeBoxColPositions : function(x, y, box)
31865 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31873 x : x + (this.unitWidth + this.gutter) * 1,
31878 x : x + (this.unitWidth + this.gutter) * 2,
31886 if(box[0].size == 'xs' && box[1].size == 'xs'){
31895 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31899 x : x + (this.unitWidth + this.gutter) * 1,
31913 x : x + (this.unitWidth + this.gutter) * 2,
31918 x : x + (this.unitWidth + this.gutter) * 2,
31919 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31926 getVerticalFourBoxColPositions : function(x, y, box)
31930 if(box[0].size == 'xs'){
31939 y : y + (this.unitHeight + this.gutter) * 1
31944 y : y + (this.unitHeight + this.gutter) * 2
31948 x : x + (this.unitWidth + this.gutter) * 1,
31962 x : x + (this.unitWidth + this.gutter) * 2,
31967 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31968 y : y + (this.unitHeight + this.gutter) * 1
31972 x : x + (this.unitWidth + this.gutter) * 2,
31973 y : y + (this.unitWidth + this.gutter) * 2
31980 getHorizontalOneBoxColPositions : function(maxX, minY, box)
31984 if(box[0].size == 'md-left'){
31986 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31993 if(box[0].size == 'md-right'){
31995 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
31996 y : minY + (this.unitWidth + this.gutter) * 1
32002 var rand = Math.floor(Math.random() * (4 - box[0].y));
32005 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32006 y : minY + (this.unitWidth + this.gutter) * rand
32013 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32017 if(box[0].size == 'xs'){
32020 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32025 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32026 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32034 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32039 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32040 y : minY + (this.unitWidth + this.gutter) * 2
32047 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32051 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32054 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32059 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32060 y : minY + (this.unitWidth + this.gutter) * 1
32064 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32065 y : minY + (this.unitWidth + this.gutter) * 2
32072 if(box[0].size == 'xs' && box[1].size == 'xs'){
32075 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32080 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32085 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32086 y : minY + (this.unitWidth + this.gutter) * 1
32094 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32099 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32100 y : minY + (this.unitWidth + this.gutter) * 2
32104 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32105 y : minY + (this.unitWidth + this.gutter) * 2
32112 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32116 if(box[0].size == 'xs'){
32119 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32124 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32129 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32134 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32135 y : minY + (this.unitWidth + this.gutter) * 1
32143 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32148 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32149 y : minY + (this.unitWidth + this.gutter) * 2
32153 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32154 y : minY + (this.unitWidth + this.gutter) * 2
32158 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1) - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32159 y : minY + (this.unitWidth + this.gutter) * 2
32167 * remove a Masonry Brick
32168 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32170 removeBrick : function(brick_id)
32176 for (var i = 0; i<this.bricks.length; i++) {
32177 if (this.bricks[i].id == brick_id) {
32178 this.bricks.splice(i,1);
32179 this.el.dom.removeChild(Roo.get(brick_id).dom);
32186 * adds a Masonry Brick
32187 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32189 addBrick : function(cfg)
32191 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32192 //this.register(cn);
32193 cn.parentId = this.id;
32194 cn.render(this.el);
32199 * register a Masonry Brick
32200 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32203 register : function(brick)
32205 this.bricks.push(brick);
32206 brick.masonryId = this.id;
32210 * clear all the Masonry Brick
32212 clearAll : function()
32215 //this.getChildContainer().dom.innerHTML = "";
32216 this.el.dom.innerHTML = '';
32219 getSelected : function()
32221 if (!this.selectedBrick) {
32225 return this.selectedBrick;
32229 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32233 * register a Masonry Layout
32234 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32237 register : function(layout)
32239 this.groups[layout.id] = layout;
32242 * fetch a Masonry Layout based on the masonry layout ID
32243 * @param {string} the masonry layout to add
32244 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32247 get: function(layout_id) {
32248 if (typeof(this.groups[layout_id]) == 'undefined') {
32251 return this.groups[layout_id] ;
32263 * http://masonry.desandro.com
32265 * The idea is to render all the bricks based on vertical width...
32267 * The original code extends 'outlayer' - we might need to use that....
32273 * @class Roo.bootstrap.LayoutMasonryAuto
32274 * @extends Roo.bootstrap.Component
32275 * Bootstrap Layout Masonry class
32278 * Create a new Element
32279 * @param {Object} config The config object
32282 Roo.bootstrap.LayoutMasonryAuto = function(config){
32283 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32286 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32289 * @cfg {Boolean} isFitWidth - resize the width..
32291 isFitWidth : false, // options..
32293 * @cfg {Boolean} isOriginLeft = left align?
32295 isOriginLeft : true,
32297 * @cfg {Boolean} isOriginTop = top align?
32299 isOriginTop : false,
32301 * @cfg {Boolean} isLayoutInstant = no animation?
32303 isLayoutInstant : false, // needed?
32305 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32307 isResizingContainer : true,
32309 * @cfg {Number} columnWidth width of the columns
32315 * @cfg {Number} maxCols maximum number of columns
32320 * @cfg {Number} padHeight padding below box..
32326 * @cfg {Boolean} isAutoInitial defalut true
32329 isAutoInitial : true,
32335 initialColumnWidth : 0,
32336 currentSize : null,
32338 colYs : null, // array.
32345 bricks: null, //CompositeElement
32346 cols : 0, // array?
32347 // element : null, // wrapped now this.el
32348 _isLayoutInited : null,
32351 getAutoCreate : function(){
32355 cls: 'blog-masonary-wrapper ' + this.cls,
32357 cls : 'mas-boxes masonary'
32364 getChildContainer: function( )
32366 if (this.boxesEl) {
32367 return this.boxesEl;
32370 this.boxesEl = this.el.select('.mas-boxes').first();
32372 return this.boxesEl;
32376 initEvents : function()
32380 if(this.isAutoInitial){
32381 Roo.log('hook children rendered');
32382 this.on('childrenrendered', function() {
32383 Roo.log('children rendered');
32390 initial : function()
32392 this.reloadItems();
32394 this.currentSize = this.el.getBox(true);
32396 /// was window resize... - let's see if this works..
32397 Roo.EventManager.onWindowResize(this.resize, this);
32399 if(!this.isAutoInitial){
32404 this.layout.defer(500,this);
32407 reloadItems: function()
32409 this.bricks = this.el.select('.masonry-brick', true);
32411 this.bricks.each(function(b) {
32412 //Roo.log(b.getSize());
32413 if (!b.attr('originalwidth')) {
32414 b.attr('originalwidth', b.getSize().width);
32419 Roo.log(this.bricks.elements.length);
32422 resize : function()
32425 var cs = this.el.getBox(true);
32427 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32428 Roo.log("no change in with or X");
32431 this.currentSize = cs;
32435 layout : function()
32438 this._resetLayout();
32439 //this._manageStamps();
32441 // don't animate first layout
32442 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32443 this.layoutItems( isInstant );
32445 // flag for initalized
32446 this._isLayoutInited = true;
32449 layoutItems : function( isInstant )
32451 //var items = this._getItemsForLayout( this.items );
32452 // original code supports filtering layout items.. we just ignore it..
32454 this._layoutItems( this.bricks , isInstant );
32456 this._postLayout();
32458 _layoutItems : function ( items , isInstant)
32460 //this.fireEvent( 'layout', this, items );
32463 if ( !items || !items.elements.length ) {
32464 // no items, emit event with empty array
32469 items.each(function(item) {
32470 Roo.log("layout item");
32472 // get x/y object from method
32473 var position = this._getItemLayoutPosition( item );
32475 position.item = item;
32476 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32477 queue.push( position );
32480 this._processLayoutQueue( queue );
32482 /** Sets position of item in DOM
32483 * @param {Element} item
32484 * @param {Number} x - horizontal position
32485 * @param {Number} y - vertical position
32486 * @param {Boolean} isInstant - disables transitions
32488 _processLayoutQueue : function( queue )
32490 for ( var i=0, len = queue.length; i < len; i++ ) {
32491 var obj = queue[i];
32492 obj.item.position('absolute');
32493 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32499 * Any logic you want to do after each layout,
32500 * i.e. size the container
32502 _postLayout : function()
32504 this.resizeContainer();
32507 resizeContainer : function()
32509 if ( !this.isResizingContainer ) {
32512 var size = this._getContainerSize();
32514 this.el.setSize(size.width,size.height);
32515 this.boxesEl.setSize(size.width,size.height);
32521 _resetLayout : function()
32523 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32524 this.colWidth = this.el.getWidth();
32525 //this.gutter = this.el.getWidth();
32527 this.measureColumns();
32533 this.colYs.push( 0 );
32539 measureColumns : function()
32541 this.getContainerWidth();
32542 // if columnWidth is 0, default to outerWidth of first item
32543 if ( !this.columnWidth ) {
32544 var firstItem = this.bricks.first();
32545 Roo.log(firstItem);
32546 this.columnWidth = this.containerWidth;
32547 if (firstItem && firstItem.attr('originalwidth') ) {
32548 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32550 // columnWidth fall back to item of first element
32551 Roo.log("set column width?");
32552 this.initialColumnWidth = this.columnWidth ;
32554 // if first elem has no width, default to size of container
32559 if (this.initialColumnWidth) {
32560 this.columnWidth = this.initialColumnWidth;
32565 // column width is fixed at the top - however if container width get's smaller we should
32568 // this bit calcs how man columns..
32570 var columnWidth = this.columnWidth += this.gutter;
32572 // calculate columns
32573 var containerWidth = this.containerWidth + this.gutter;
32575 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32576 // fix rounding errors, typically with gutters
32577 var excess = columnWidth - containerWidth % columnWidth;
32580 // if overshoot is less than a pixel, round up, otherwise floor it
32581 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32582 cols = Math[ mathMethod ]( cols );
32583 this.cols = Math.max( cols, 1 );
32584 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32586 // padding positioning..
32587 var totalColWidth = this.cols * this.columnWidth;
32588 var padavail = this.containerWidth - totalColWidth;
32589 // so for 2 columns - we need 3 'pads'
32591 var padNeeded = (1+this.cols) * this.padWidth;
32593 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32595 this.columnWidth += padExtra
32596 //this.padWidth = Math.floor(padavail / ( this.cols));
32598 // adjust colum width so that padding is fixed??
32600 // we have 3 columns ... total = width * 3
32601 // we have X left over... that should be used by
32603 //if (this.expandC) {
32611 getContainerWidth : function()
32613 /* // container is parent if fit width
32614 var container = this.isFitWidth ? this.element.parentNode : this.element;
32615 // check that this.size and size are there
32616 // IE8 triggers resize on body size change, so they might not be
32618 var size = getSize( container ); //FIXME
32619 this.containerWidth = size && size.innerWidth; //FIXME
32622 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32626 _getItemLayoutPosition : function( item ) // what is item?
32628 // we resize the item to our columnWidth..
32630 item.setWidth(this.columnWidth);
32631 item.autoBoxAdjust = false;
32633 var sz = item.getSize();
32635 // how many columns does this brick span
32636 var remainder = this.containerWidth % this.columnWidth;
32638 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32639 // round if off by 1 pixel, otherwise use ceil
32640 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32641 colSpan = Math.min( colSpan, this.cols );
32643 // normally this should be '1' as we dont' currently allow multi width columns..
32645 var colGroup = this._getColGroup( colSpan );
32646 // get the minimum Y value from the columns
32647 var minimumY = Math.min.apply( Math, colGroup );
32648 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32650 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32652 // position the brick
32654 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32655 y: this.currentSize.y + minimumY + this.padHeight
32659 // apply setHeight to necessary columns
32660 var setHeight = minimumY + sz.height + this.padHeight;
32661 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32663 var setSpan = this.cols + 1 - colGroup.length;
32664 for ( var i = 0; i < setSpan; i++ ) {
32665 this.colYs[ shortColIndex + i ] = setHeight ;
32672 * @param {Number} colSpan - number of columns the element spans
32673 * @returns {Array} colGroup
32675 _getColGroup : function( colSpan )
32677 if ( colSpan < 2 ) {
32678 // if brick spans only one column, use all the column Ys
32683 // how many different places could this brick fit horizontally
32684 var groupCount = this.cols + 1 - colSpan;
32685 // for each group potential horizontal position
32686 for ( var i = 0; i < groupCount; i++ ) {
32687 // make an array of colY values for that one group
32688 var groupColYs = this.colYs.slice( i, i + colSpan );
32689 // and get the max value of the array
32690 colGroup[i] = Math.max.apply( Math, groupColYs );
32695 _manageStamp : function( stamp )
32697 var stampSize = stamp.getSize();
32698 var offset = stamp.getBox();
32699 // get the columns that this stamp affects
32700 var firstX = this.isOriginLeft ? offset.x : offset.right;
32701 var lastX = firstX + stampSize.width;
32702 var firstCol = Math.floor( firstX / this.columnWidth );
32703 firstCol = Math.max( 0, firstCol );
32705 var lastCol = Math.floor( lastX / this.columnWidth );
32706 // lastCol should not go over if multiple of columnWidth #425
32707 lastCol -= lastX % this.columnWidth ? 0 : 1;
32708 lastCol = Math.min( this.cols - 1, lastCol );
32710 // set colYs to bottom of the stamp
32711 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32714 for ( var i = firstCol; i <= lastCol; i++ ) {
32715 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32720 _getContainerSize : function()
32722 this.maxY = Math.max.apply( Math, this.colYs );
32727 if ( this.isFitWidth ) {
32728 size.width = this._getContainerFitWidth();
32734 _getContainerFitWidth : function()
32736 var unusedCols = 0;
32737 // count unused columns
32740 if ( this.colYs[i] !== 0 ) {
32745 // fit container to columns that have been used
32746 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32749 needsResizeLayout : function()
32751 var previousWidth = this.containerWidth;
32752 this.getContainerWidth();
32753 return previousWidth !== this.containerWidth;
32768 * @class Roo.bootstrap.MasonryBrick
32769 * @extends Roo.bootstrap.Component
32770 * Bootstrap MasonryBrick class
32773 * Create a new MasonryBrick
32774 * @param {Object} config The config object
32777 Roo.bootstrap.MasonryBrick = function(config){
32779 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32781 Roo.bootstrap.MasonryBrick.register(this);
32787 * When a MasonryBrick is clcik
32788 * @param {Roo.bootstrap.MasonryBrick} this
32789 * @param {Roo.EventObject} e
32795 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32798 * @cfg {String} title
32802 * @cfg {String} html
32806 * @cfg {String} bgimage
32810 * @cfg {String} videourl
32814 * @cfg {String} cls
32818 * @cfg {String} href
32822 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32827 * @cfg {String} placetitle (center|bottom)
32832 * @cfg {Boolean} isFitContainer defalut true
32834 isFitContainer : true,
32837 * @cfg {Boolean} preventDefault defalut false
32839 preventDefault : false,
32842 * @cfg {Boolean} inverse defalut false
32844 maskInverse : false,
32846 getAutoCreate : function()
32848 if(!this.isFitContainer){
32849 return this.getSplitAutoCreate();
32852 var cls = 'masonry-brick masonry-brick-full';
32854 if(this.href.length){
32855 cls += ' masonry-brick-link';
32858 if(this.bgimage.length){
32859 cls += ' masonry-brick-image';
32862 if(this.maskInverse){
32863 cls += ' mask-inverse';
32866 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32867 cls += ' enable-mask';
32871 cls += ' masonry-' + this.size + '-brick';
32874 if(this.placetitle.length){
32876 switch (this.placetitle) {
32878 cls += ' masonry-center-title';
32881 cls += ' masonry-bottom-title';
32888 if(!this.html.length && !this.bgimage.length){
32889 cls += ' masonry-center-title';
32892 if(!this.html.length && this.bgimage.length){
32893 cls += ' masonry-bottom-title';
32898 cls += ' ' + this.cls;
32902 tag: (this.href.length) ? 'a' : 'div',
32907 cls: 'masonry-brick-mask'
32911 cls: 'masonry-brick-paragraph',
32917 if(this.href.length){
32918 cfg.href = this.href;
32921 var cn = cfg.cn[1].cn;
32923 if(this.title.length){
32926 cls: 'masonry-brick-title',
32931 if(this.html.length){
32934 cls: 'masonry-brick-text',
32939 if (!this.title.length && !this.html.length) {
32940 cfg.cn[1].cls += ' hide';
32943 if(this.bgimage.length){
32946 cls: 'masonry-brick-image-view',
32951 if(this.videourl.length){
32952 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32953 // youtube support only?
32956 cls: 'masonry-brick-image-view',
32959 allowfullscreen : true
32967 getSplitAutoCreate : function()
32969 var cls = 'masonry-brick masonry-brick-split';
32971 if(this.href.length){
32972 cls += ' masonry-brick-link';
32975 if(this.bgimage.length){
32976 cls += ' masonry-brick-image';
32980 cls += ' masonry-' + this.size + '-brick';
32983 switch (this.placetitle) {
32985 cls += ' masonry-center-title';
32988 cls += ' masonry-bottom-title';
32991 if(!this.bgimage.length){
32992 cls += ' masonry-center-title';
32995 if(this.bgimage.length){
32996 cls += ' masonry-bottom-title';
33002 cls += ' ' + this.cls;
33006 tag: (this.href.length) ? 'a' : 'div',
33011 cls: 'masonry-brick-split-head',
33015 cls: 'masonry-brick-paragraph',
33022 cls: 'masonry-brick-split-body',
33028 if(this.href.length){
33029 cfg.href = this.href;
33032 if(this.title.length){
33033 cfg.cn[0].cn[0].cn.push({
33035 cls: 'masonry-brick-title',
33040 if(this.html.length){
33041 cfg.cn[1].cn.push({
33043 cls: 'masonry-brick-text',
33048 if(this.bgimage.length){
33049 cfg.cn[0].cn.push({
33051 cls: 'masonry-brick-image-view',
33056 if(this.videourl.length){
33057 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33058 // youtube support only?
33059 cfg.cn[0].cn.cn.push({
33061 cls: 'masonry-brick-image-view',
33064 allowfullscreen : true
33071 initEvents: function()
33073 switch (this.size) {
33106 this.el.on('touchstart', this.onTouchStart, this);
33107 this.el.on('touchmove', this.onTouchMove, this);
33108 this.el.on('touchend', this.onTouchEnd, this);
33109 this.el.on('contextmenu', this.onContextMenu, this);
33111 this.el.on('mouseenter' ,this.enter, this);
33112 this.el.on('mouseleave', this.leave, this);
33113 this.el.on('click', this.onClick, this);
33116 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33117 this.parent().bricks.push(this);
33122 onClick: function(e, el)
33124 var time = this.endTimer - this.startTimer;
33125 // Roo.log(e.preventDefault());
33128 e.preventDefault();
33133 if(!this.preventDefault){
33137 e.preventDefault();
33139 if (this.activeClass != '') {
33140 this.selectBrick();
33143 this.fireEvent('click', this, e);
33146 enter: function(e, el)
33148 e.preventDefault();
33150 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33154 if(this.bgimage.length && this.html.length){
33155 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33159 leave: function(e, el)
33161 e.preventDefault();
33163 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33167 if(this.bgimage.length && this.html.length){
33168 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33172 onTouchStart: function(e, el)
33174 // e.preventDefault();
33176 this.touchmoved = false;
33178 if(!this.isFitContainer){
33182 if(!this.bgimage.length || !this.html.length){
33186 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33188 this.timer = new Date().getTime();
33192 onTouchMove: function(e, el)
33194 this.touchmoved = true;
33197 onContextMenu : function(e,el)
33199 e.preventDefault();
33200 e.stopPropagation();
33204 onTouchEnd: function(e, el)
33206 // e.preventDefault();
33208 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33215 if(!this.bgimage.length || !this.html.length){
33217 if(this.href.length){
33218 window.location.href = this.href;
33224 if(!this.isFitContainer){
33228 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33230 window.location.href = this.href;
33233 //selection on single brick only
33234 selectBrick : function() {
33236 if (!this.parentId) {
33240 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33241 var index = m.selectedBrick.indexOf(this.id);
33244 m.selectedBrick.splice(index,1);
33245 this.el.removeClass(this.activeClass);
33249 for(var i = 0; i < m.selectedBrick.length; i++) {
33250 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33251 b.el.removeClass(b.activeClass);
33254 m.selectedBrick = [];
33256 m.selectedBrick.push(this.id);
33257 this.el.addClass(this.activeClass);
33261 isSelected : function(){
33262 return this.el.hasClass(this.activeClass);
33267 Roo.apply(Roo.bootstrap.MasonryBrick, {
33270 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33272 * register a Masonry Brick
33273 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33276 register : function(brick)
33278 //this.groups[brick.id] = brick;
33279 this.groups.add(brick.id, brick);
33282 * fetch a masonry brick based on the masonry brick ID
33283 * @param {string} the masonry brick to add
33284 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33287 get: function(brick_id)
33289 // if (typeof(this.groups[brick_id]) == 'undefined') {
33292 // return this.groups[brick_id] ;
33294 if(this.groups.key(brick_id)) {
33295 return this.groups.key(brick_id);
33313 * @class Roo.bootstrap.Brick
33314 * @extends Roo.bootstrap.Component
33315 * Bootstrap Brick class
33318 * Create a new Brick
33319 * @param {Object} config The config object
33322 Roo.bootstrap.Brick = function(config){
33323 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33329 * When a Brick is click
33330 * @param {Roo.bootstrap.Brick} this
33331 * @param {Roo.EventObject} e
33337 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33340 * @cfg {String} title
33344 * @cfg {String} html
33348 * @cfg {String} bgimage
33352 * @cfg {String} cls
33356 * @cfg {String} href
33360 * @cfg {String} video
33364 * @cfg {Boolean} square
33368 getAutoCreate : function()
33370 var cls = 'roo-brick';
33372 if(this.href.length){
33373 cls += ' roo-brick-link';
33376 if(this.bgimage.length){
33377 cls += ' roo-brick-image';
33380 if(!this.html.length && !this.bgimage.length){
33381 cls += ' roo-brick-center-title';
33384 if(!this.html.length && this.bgimage.length){
33385 cls += ' roo-brick-bottom-title';
33389 cls += ' ' + this.cls;
33393 tag: (this.href.length) ? 'a' : 'div',
33398 cls: 'roo-brick-paragraph',
33404 if(this.href.length){
33405 cfg.href = this.href;
33408 var cn = cfg.cn[0].cn;
33410 if(this.title.length){
33413 cls: 'roo-brick-title',
33418 if(this.html.length){
33421 cls: 'roo-brick-text',
33428 if(this.bgimage.length){
33431 cls: 'roo-brick-image-view',
33439 initEvents: function()
33441 if(this.title.length || this.html.length){
33442 this.el.on('mouseenter' ,this.enter, this);
33443 this.el.on('mouseleave', this.leave, this);
33446 Roo.EventManager.onWindowResize(this.resize, this);
33448 if(this.bgimage.length){
33449 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33450 this.imageEl.on('load', this.onImageLoad, this);
33457 onImageLoad : function()
33462 resize : function()
33464 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33466 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33468 if(this.bgimage.length){
33469 var image = this.el.select('.roo-brick-image-view', true).first();
33471 image.setWidth(paragraph.getWidth());
33474 image.setHeight(paragraph.getWidth());
33477 this.el.setHeight(image.getHeight());
33478 paragraph.setHeight(image.getHeight());
33484 enter: function(e, el)
33486 e.preventDefault();
33488 if(this.bgimage.length){
33489 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33490 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33494 leave: function(e, el)
33496 e.preventDefault();
33498 if(this.bgimage.length){
33499 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33500 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33515 * @class Roo.bootstrap.NumberField
33516 * @extends Roo.bootstrap.Input
33517 * Bootstrap NumberField class
33523 * Create a new NumberField
33524 * @param {Object} config The config object
33527 Roo.bootstrap.NumberField = function(config){
33528 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33531 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33534 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33536 allowDecimals : true,
33538 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33540 decimalSeparator : ".",
33542 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33544 decimalPrecision : 2,
33546 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33548 allowNegative : true,
33551 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33555 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33557 minValue : Number.NEGATIVE_INFINITY,
33559 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33561 maxValue : Number.MAX_VALUE,
33563 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33565 minText : "The minimum value for this field is {0}",
33567 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33569 maxText : "The maximum value for this field is {0}",
33571 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33572 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33574 nanText : "{0} is not a valid number",
33576 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33578 thousandsDelimiter : false,
33580 * @cfg {String} valueAlign alignment of value
33582 valueAlign : "left",
33584 getAutoCreate : function()
33586 var hiddenInput = {
33590 cls: 'hidden-number-input'
33594 hiddenInput.name = this.name;
33599 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33601 this.name = hiddenInput.name;
33603 if(cfg.cn.length > 0) {
33604 cfg.cn.push(hiddenInput);
33611 initEvents : function()
33613 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33615 var allowed = "0123456789";
33617 if(this.allowDecimals){
33618 allowed += this.decimalSeparator;
33621 if(this.allowNegative){
33625 if(this.thousandsDelimiter) {
33629 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33631 var keyPress = function(e){
33633 var k = e.getKey();
33635 var c = e.getCharCode();
33638 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33639 allowed.indexOf(String.fromCharCode(c)) === -1
33645 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33649 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33654 this.el.on("keypress", keyPress, this);
33657 validateValue : function(value)
33660 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33664 var num = this.parseValue(value);
33667 this.markInvalid(String.format(this.nanText, value));
33671 if(num < this.minValue){
33672 this.markInvalid(String.format(this.minText, this.minValue));
33676 if(num > this.maxValue){
33677 this.markInvalid(String.format(this.maxText, this.maxValue));
33684 getValue : function()
33686 var v = this.hiddenEl().getValue();
33688 return this.fixPrecision(this.parseValue(v));
33691 parseValue : function(value)
33693 if(this.thousandsDelimiter) {
33695 r = new RegExp(",", "g");
33696 value = value.replace(r, "");
33699 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33700 return isNaN(value) ? '' : value;
33703 fixPrecision : function(value)
33705 if(this.thousandsDelimiter) {
33707 r = new RegExp(",", "g");
33708 value = value.replace(r, "");
33711 var nan = isNaN(value);
33713 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33714 return nan ? '' : value;
33716 return parseFloat(value).toFixed(this.decimalPrecision);
33719 setValue : function(v)
33721 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33727 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33729 this.inputEl().dom.value = (v == '') ? '' :
33730 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33732 if(!this.allowZero && v === '0') {
33733 this.hiddenEl().dom.value = '';
33734 this.inputEl().dom.value = '';
33741 decimalPrecisionFcn : function(v)
33743 return Math.floor(v);
33746 beforeBlur : function()
33748 var v = this.parseValue(this.getRawValue());
33750 if(v || v === 0 || v === ''){
33755 hiddenEl : function()
33757 return this.el.select('input.hidden-number-input',true).first();
33769 * @class Roo.bootstrap.DocumentSlider
33770 * @extends Roo.bootstrap.Component
33771 * Bootstrap DocumentSlider class
33774 * Create a new DocumentViewer
33775 * @param {Object} config The config object
33778 Roo.bootstrap.DocumentSlider = function(config){
33779 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33786 * Fire after initEvent
33787 * @param {Roo.bootstrap.DocumentSlider} this
33792 * Fire after update
33793 * @param {Roo.bootstrap.DocumentSlider} this
33799 * @param {Roo.bootstrap.DocumentSlider} this
33805 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33811 getAutoCreate : function()
33815 cls : 'roo-document-slider',
33819 cls : 'roo-document-slider-header',
33823 cls : 'roo-document-slider-header-title'
33829 cls : 'roo-document-slider-body',
33833 cls : 'roo-document-slider-prev',
33837 cls : 'fa fa-chevron-left'
33843 cls : 'roo-document-slider-thumb',
33847 cls : 'roo-document-slider-image'
33853 cls : 'roo-document-slider-next',
33857 cls : 'fa fa-chevron-right'
33869 initEvents : function()
33871 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33872 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33874 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33875 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33877 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33878 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33880 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33881 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33883 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33884 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33886 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33887 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33889 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33890 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33892 this.thumbEl.on('click', this.onClick, this);
33894 this.prevIndicator.on('click', this.prev, this);
33896 this.nextIndicator.on('click', this.next, this);
33900 initial : function()
33902 if(this.files.length){
33903 this.indicator = 1;
33907 this.fireEvent('initial', this);
33910 update : function()
33912 this.imageEl.attr('src', this.files[this.indicator - 1]);
33914 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33916 this.prevIndicator.show();
33918 if(this.indicator == 1){
33919 this.prevIndicator.hide();
33922 this.nextIndicator.show();
33924 if(this.indicator == this.files.length){
33925 this.nextIndicator.hide();
33928 this.thumbEl.scrollTo('top');
33930 this.fireEvent('update', this);
33933 onClick : function(e)
33935 e.preventDefault();
33937 this.fireEvent('click', this);
33942 e.preventDefault();
33944 this.indicator = Math.max(1, this.indicator - 1);
33951 e.preventDefault();
33953 this.indicator = Math.min(this.files.length, this.indicator + 1);
33967 * @class Roo.bootstrap.RadioSet
33968 * @extends Roo.bootstrap.Input
33969 * Bootstrap RadioSet class
33970 * @cfg {String} indicatorpos (left|right) default left
33971 * @cfg {Boolean} inline (true|false) inline the element (default true)
33972 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33974 * Create a new RadioSet
33975 * @param {Object} config The config object
33978 Roo.bootstrap.RadioSet = function(config){
33980 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
33984 Roo.bootstrap.RadioSet.register(this);
33989 * Fires when the element is checked or unchecked.
33990 * @param {Roo.bootstrap.RadioSet} this This radio
33991 * @param {Roo.bootstrap.Radio} item The checked item
33996 * Fires when the element is click.
33997 * @param {Roo.bootstrap.RadioSet} this This radio set
33998 * @param {Roo.bootstrap.Radio} item The checked item
33999 * @param {Roo.EventObject} e The event object
34006 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34014 indicatorpos : 'left',
34016 getAutoCreate : function()
34020 cls : 'roo-radio-set-label',
34024 html : this.fieldLabel
34029 if(this.indicatorpos == 'left'){
34032 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34033 tooltip : 'This field is required'
34038 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34039 tooltip : 'This field is required'
34045 cls : 'roo-radio-set-items'
34048 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34050 if (align === 'left' && this.fieldLabel.length) {
34053 cls : "roo-radio-set-right",
34059 if(this.labelWidth > 12){
34060 label.style = "width: " + this.labelWidth + 'px';
34063 if(this.labelWidth < 13 && this.labelmd == 0){
34064 this.labelmd = this.labelWidth;
34067 if(this.labellg > 0){
34068 label.cls += ' col-lg-' + this.labellg;
34069 items.cls += ' col-lg-' + (12 - this.labellg);
34072 if(this.labelmd > 0){
34073 label.cls += ' col-md-' + this.labelmd;
34074 items.cls += ' col-md-' + (12 - this.labelmd);
34077 if(this.labelsm > 0){
34078 label.cls += ' col-sm-' + this.labelsm;
34079 items.cls += ' col-sm-' + (12 - this.labelsm);
34082 if(this.labelxs > 0){
34083 label.cls += ' col-xs-' + this.labelxs;
34084 items.cls += ' col-xs-' + (12 - this.labelxs);
34090 cls : 'roo-radio-set',
34094 cls : 'roo-radio-set-input',
34097 value : this.value ? this.value : ''
34104 if(this.weight.length){
34105 cfg.cls += ' roo-radio-' + this.weight;
34109 cfg.cls += ' roo-radio-set-inline';
34113 ['xs','sm','md','lg'].map(function(size){
34114 if (settings[size]) {
34115 cfg.cls += ' col-' + size + '-' + settings[size];
34123 initEvents : function()
34125 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34126 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34128 if(!this.fieldLabel.length){
34129 this.labelEl.hide();
34132 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34133 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34135 this.indicator = this.indicatorEl();
34137 if(this.indicator){
34138 this.indicator.addClass('invisible');
34141 this.originalValue = this.getValue();
34145 inputEl: function ()
34147 return this.el.select('.roo-radio-set-input', true).first();
34150 getChildContainer : function()
34152 return this.itemsEl;
34155 register : function(item)
34157 this.radioes.push(item);
34161 validate : function()
34163 if(this.getVisibilityEl().hasClass('hidden')){
34169 Roo.each(this.radioes, function(i){
34178 if(this.allowBlank) {
34182 if(this.disabled || valid){
34187 this.markInvalid();
34192 markValid : function()
34194 if(this.labelEl.isVisible(true)){
34195 this.indicatorEl().removeClass('visible');
34196 this.indicatorEl().addClass('invisible');
34199 this.el.removeClass([this.invalidClass, this.validClass]);
34200 this.el.addClass(this.validClass);
34202 this.fireEvent('valid', this);
34205 markInvalid : function(msg)
34207 if(this.allowBlank || this.disabled){
34211 if(this.labelEl.isVisible(true)){
34212 this.indicatorEl().removeClass('invisible');
34213 this.indicatorEl().addClass('visible');
34216 this.el.removeClass([this.invalidClass, this.validClass]);
34217 this.el.addClass(this.invalidClass);
34219 this.fireEvent('invalid', this, msg);
34223 setValue : function(v, suppressEvent)
34225 if(this.value === v){
34232 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34235 Roo.each(this.radioes, function(i){
34237 i.el.removeClass('checked');
34240 Roo.each(this.radioes, function(i){
34242 if(i.value === v || i.value.toString() === v.toString()){
34244 i.el.addClass('checked');
34246 if(suppressEvent !== true){
34247 this.fireEvent('check', this, i);
34258 clearInvalid : function(){
34260 if(!this.el || this.preventMark){
34264 this.el.removeClass([this.invalidClass]);
34266 this.fireEvent('valid', this);
34271 Roo.apply(Roo.bootstrap.RadioSet, {
34275 register : function(set)
34277 this.groups[set.name] = set;
34280 get: function(name)
34282 if (typeof(this.groups[name]) == 'undefined') {
34286 return this.groups[name] ;
34292 * Ext JS Library 1.1.1
34293 * Copyright(c) 2006-2007, Ext JS, LLC.
34295 * Originally Released Under LGPL - original licence link has changed is not relivant.
34298 * <script type="text/javascript">
34303 * @class Roo.bootstrap.SplitBar
34304 * @extends Roo.util.Observable
34305 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34309 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34310 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34311 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34312 split.minSize = 100;
34313 split.maxSize = 600;
34314 split.animate = true;
34315 split.on('moved', splitterMoved);
34318 * Create a new SplitBar
34319 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34320 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34321 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34322 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34323 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34324 position of the SplitBar).
34326 Roo.bootstrap.SplitBar = function(cfg){
34331 // dragElement : elm
34332 // resizingElement: el,
34334 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34335 // placement : Roo.bootstrap.SplitBar.LEFT ,
34336 // existingProxy ???
34339 this.el = Roo.get(cfg.dragElement, true);
34340 this.el.dom.unselectable = "on";
34342 this.resizingEl = Roo.get(cfg.resizingElement, true);
34346 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34347 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34350 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34353 * The minimum size of the resizing element. (Defaults to 0)
34359 * The maximum size of the resizing element. (Defaults to 2000)
34362 this.maxSize = 2000;
34365 * Whether to animate the transition to the new size
34368 this.animate = false;
34371 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34374 this.useShim = false;
34379 if(!cfg.existingProxy){
34381 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34383 this.proxy = Roo.get(cfg.existingProxy).dom;
34386 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34389 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34392 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34395 this.dragSpecs = {};
34398 * @private The adapter to use to positon and resize elements
34400 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34401 this.adapter.init(this);
34403 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34405 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34406 this.el.addClass("roo-splitbar-h");
34409 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34410 this.el.addClass("roo-splitbar-v");
34416 * Fires when the splitter is moved (alias for {@link #event-moved})
34417 * @param {Roo.bootstrap.SplitBar} this
34418 * @param {Number} newSize the new width or height
34423 * Fires when the splitter is moved
34424 * @param {Roo.bootstrap.SplitBar} this
34425 * @param {Number} newSize the new width or height
34429 * @event beforeresize
34430 * Fires before the splitter is dragged
34431 * @param {Roo.bootstrap.SplitBar} this
34433 "beforeresize" : true,
34435 "beforeapply" : true
34438 Roo.util.Observable.call(this);
34441 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34442 onStartProxyDrag : function(x, y){
34443 this.fireEvent("beforeresize", this);
34445 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34447 o.enableDisplayMode("block");
34448 // all splitbars share the same overlay
34449 Roo.bootstrap.SplitBar.prototype.overlay = o;
34451 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34452 this.overlay.show();
34453 Roo.get(this.proxy).setDisplayed("block");
34454 var size = this.adapter.getElementSize(this);
34455 this.activeMinSize = this.getMinimumSize();;
34456 this.activeMaxSize = this.getMaximumSize();;
34457 var c1 = size - this.activeMinSize;
34458 var c2 = Math.max(this.activeMaxSize - size, 0);
34459 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34460 this.dd.resetConstraints();
34461 this.dd.setXConstraint(
34462 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34463 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34465 this.dd.setYConstraint(0, 0);
34467 this.dd.resetConstraints();
34468 this.dd.setXConstraint(0, 0);
34469 this.dd.setYConstraint(
34470 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34471 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34474 this.dragSpecs.startSize = size;
34475 this.dragSpecs.startPoint = [x, y];
34476 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34480 * @private Called after the drag operation by the DDProxy
34482 onEndProxyDrag : function(e){
34483 Roo.get(this.proxy).setDisplayed(false);
34484 var endPoint = Roo.lib.Event.getXY(e);
34486 this.overlay.hide();
34489 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34490 newSize = this.dragSpecs.startSize +
34491 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34492 endPoint[0] - this.dragSpecs.startPoint[0] :
34493 this.dragSpecs.startPoint[0] - endPoint[0]
34496 newSize = this.dragSpecs.startSize +
34497 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34498 endPoint[1] - this.dragSpecs.startPoint[1] :
34499 this.dragSpecs.startPoint[1] - endPoint[1]
34502 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34503 if(newSize != this.dragSpecs.startSize){
34504 if(this.fireEvent('beforeapply', this, newSize) !== false){
34505 this.adapter.setElementSize(this, newSize);
34506 this.fireEvent("moved", this, newSize);
34507 this.fireEvent("resize", this, newSize);
34513 * Get the adapter this SplitBar uses
34514 * @return The adapter object
34516 getAdapter : function(){
34517 return this.adapter;
34521 * Set the adapter this SplitBar uses
34522 * @param {Object} adapter A SplitBar adapter object
34524 setAdapter : function(adapter){
34525 this.adapter = adapter;
34526 this.adapter.init(this);
34530 * Gets the minimum size for the resizing element
34531 * @return {Number} The minimum size
34533 getMinimumSize : function(){
34534 return this.minSize;
34538 * Sets the minimum size for the resizing element
34539 * @param {Number} minSize The minimum size
34541 setMinimumSize : function(minSize){
34542 this.minSize = minSize;
34546 * Gets the maximum size for the resizing element
34547 * @return {Number} The maximum size
34549 getMaximumSize : function(){
34550 return this.maxSize;
34554 * Sets the maximum size for the resizing element
34555 * @param {Number} maxSize The maximum size
34557 setMaximumSize : function(maxSize){
34558 this.maxSize = maxSize;
34562 * Sets the initialize size for the resizing element
34563 * @param {Number} size The initial size
34565 setCurrentSize : function(size){
34566 var oldAnimate = this.animate;
34567 this.animate = false;
34568 this.adapter.setElementSize(this, size);
34569 this.animate = oldAnimate;
34573 * Destroy this splitbar.
34574 * @param {Boolean} removeEl True to remove the element
34576 destroy : function(removeEl){
34578 this.shim.remove();
34581 this.proxy.parentNode.removeChild(this.proxy);
34589 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
34591 Roo.bootstrap.SplitBar.createProxy = function(dir){
34592 var proxy = new Roo.Element(document.createElement("div"));
34593 proxy.unselectable();
34594 var cls = 'roo-splitbar-proxy';
34595 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34596 document.body.appendChild(proxy.dom);
34601 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34602 * Default Adapter. It assumes the splitter and resizing element are not positioned
34603 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34605 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34608 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34609 // do nothing for now
34610 init : function(s){
34614 * Called before drag operations to get the current size of the resizing element.
34615 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34617 getElementSize : function(s){
34618 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34619 return s.resizingEl.getWidth();
34621 return s.resizingEl.getHeight();
34626 * Called after drag operations to set the size of the resizing element.
34627 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34628 * @param {Number} newSize The new size to set
34629 * @param {Function} onComplete A function to be invoked when resizing is complete
34631 setElementSize : function(s, newSize, onComplete){
34632 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34634 s.resizingEl.setWidth(newSize);
34636 onComplete(s, newSize);
34639 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34644 s.resizingEl.setHeight(newSize);
34646 onComplete(s, newSize);
34649 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34656 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34657 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34658 * Adapter that moves the splitter element to align with the resized sizing element.
34659 * Used with an absolute positioned SplitBar.
34660 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34661 * document.body, make sure you assign an id to the body element.
34663 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34664 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34665 this.container = Roo.get(container);
34668 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34669 init : function(s){
34670 this.basic.init(s);
34673 getElementSize : function(s){
34674 return this.basic.getElementSize(s);
34677 setElementSize : function(s, newSize, onComplete){
34678 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34681 moveSplitter : function(s){
34682 var yes = Roo.bootstrap.SplitBar;
34683 switch(s.placement){
34685 s.el.setX(s.resizingEl.getRight());
34688 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34691 s.el.setY(s.resizingEl.getBottom());
34694 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34701 * Orientation constant - Create a vertical SplitBar
34705 Roo.bootstrap.SplitBar.VERTICAL = 1;
34708 * Orientation constant - Create a horizontal SplitBar
34712 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34715 * Placement constant - The resizing element is to the left of the splitter element
34719 Roo.bootstrap.SplitBar.LEFT = 1;
34722 * Placement constant - The resizing element is to the right of the splitter element
34726 Roo.bootstrap.SplitBar.RIGHT = 2;
34729 * Placement constant - The resizing element is positioned above the splitter element
34733 Roo.bootstrap.SplitBar.TOP = 3;
34736 * Placement constant - The resizing element is positioned under splitter element
34740 Roo.bootstrap.SplitBar.BOTTOM = 4;
34741 Roo.namespace("Roo.bootstrap.layout");/*
34743 * Ext JS Library 1.1.1
34744 * Copyright(c) 2006-2007, Ext JS, LLC.
34746 * Originally Released Under LGPL - original licence link has changed is not relivant.
34749 * <script type="text/javascript">
34753 * @class Roo.bootstrap.layout.Manager
34754 * @extends Roo.bootstrap.Component
34755 * Base class for layout managers.
34757 Roo.bootstrap.layout.Manager = function(config)
34759 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34765 /** false to disable window resize monitoring @type Boolean */
34766 this.monitorWindowResize = true;
34771 * Fires when a layout is performed.
34772 * @param {Roo.LayoutManager} this
34776 * @event regionresized
34777 * Fires when the user resizes a region.
34778 * @param {Roo.LayoutRegion} region The resized region
34779 * @param {Number} newSize The new size (width for east/west, height for north/south)
34781 "regionresized" : true,
34783 * @event regioncollapsed
34784 * Fires when a region is collapsed.
34785 * @param {Roo.LayoutRegion} region The collapsed region
34787 "regioncollapsed" : true,
34789 * @event regionexpanded
34790 * Fires when a region is expanded.
34791 * @param {Roo.LayoutRegion} region The expanded region
34793 "regionexpanded" : true
34795 this.updating = false;
34798 this.el = Roo.get(config.el);
34804 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34809 monitorWindowResize : true,
34815 onRender : function(ct, position)
34818 this.el = Roo.get(ct);
34821 //this.fireEvent('render',this);
34825 initEvents: function()
34829 // ie scrollbar fix
34830 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34831 document.body.scroll = "no";
34832 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34833 this.el.position('relative');
34835 this.id = this.el.id;
34836 this.el.addClass("roo-layout-container");
34837 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34838 if(this.el.dom != document.body ) {
34839 this.el.on('resize', this.layout,this);
34840 this.el.on('show', this.layout,this);
34846 * Returns true if this layout is currently being updated
34847 * @return {Boolean}
34849 isUpdating : function(){
34850 return this.updating;
34854 * Suspend the LayoutManager from doing auto-layouts while
34855 * making multiple add or remove calls
34857 beginUpdate : function(){
34858 this.updating = true;
34862 * Restore auto-layouts and optionally disable the manager from performing a layout
34863 * @param {Boolean} noLayout true to disable a layout update
34865 endUpdate : function(noLayout){
34866 this.updating = false;
34872 layout: function(){
34876 onRegionResized : function(region, newSize){
34877 this.fireEvent("regionresized", region, newSize);
34881 onRegionCollapsed : function(region){
34882 this.fireEvent("regioncollapsed", region);
34885 onRegionExpanded : function(region){
34886 this.fireEvent("regionexpanded", region);
34890 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34891 * performs box-model adjustments.
34892 * @return {Object} The size as an object {width: (the width), height: (the height)}
34894 getViewSize : function()
34897 if(this.el.dom != document.body){
34898 size = this.el.getSize();
34900 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34902 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34903 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34908 * Returns the Element this layout is bound to.
34909 * @return {Roo.Element}
34911 getEl : function(){
34916 * Returns the specified region.
34917 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34918 * @return {Roo.LayoutRegion}
34920 getRegion : function(target){
34921 return this.regions[target.toLowerCase()];
34924 onWindowResize : function(){
34925 if(this.monitorWindowResize){
34932 * Ext JS Library 1.1.1
34933 * Copyright(c) 2006-2007, Ext JS, LLC.
34935 * Originally Released Under LGPL - original licence link has changed is not relivant.
34938 * <script type="text/javascript">
34941 * @class Roo.bootstrap.layout.Border
34942 * @extends Roo.bootstrap.layout.Manager
34943 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34944 * please see: examples/bootstrap/nested.html<br><br>
34946 <b>The container the layout is rendered into can be either the body element or any other element.
34947 If it is not the body element, the container needs to either be an absolute positioned element,
34948 or you will need to add "position:relative" to the css of the container. You will also need to specify
34949 the container size if it is not the body element.</b>
34952 * Create a new Border
34953 * @param {Object} config Configuration options
34955 Roo.bootstrap.layout.Border = function(config){
34956 config = config || {};
34957 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34961 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34962 if(config[region]){
34963 config[region].region = region;
34964 this.addRegion(config[region]);
34970 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34972 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34974 * Creates and adds a new region if it doesn't already exist.
34975 * @param {String} target The target region key (north, south, east, west or center).
34976 * @param {Object} config The regions config object
34977 * @return {BorderLayoutRegion} The new region
34979 addRegion : function(config)
34981 if(!this.regions[config.region]){
34982 var r = this.factory(config);
34983 this.bindRegion(r);
34985 return this.regions[config.region];
34989 bindRegion : function(r){
34990 this.regions[r.config.region] = r;
34992 r.on("visibilitychange", this.layout, this);
34993 r.on("paneladded", this.layout, this);
34994 r.on("panelremoved", this.layout, this);
34995 r.on("invalidated", this.layout, this);
34996 r.on("resized", this.onRegionResized, this);
34997 r.on("collapsed", this.onRegionCollapsed, this);
34998 r.on("expanded", this.onRegionExpanded, this);
35002 * Performs a layout update.
35004 layout : function()
35006 if(this.updating) {
35010 // render all the rebions if they have not been done alreayd?
35011 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35012 if(this.regions[region] && !this.regions[region].bodyEl){
35013 this.regions[region].onRender(this.el)
35017 var size = this.getViewSize();
35018 var w = size.width;
35019 var h = size.height;
35024 //var x = 0, y = 0;
35026 var rs = this.regions;
35027 var north = rs["north"];
35028 var south = rs["south"];
35029 var west = rs["west"];
35030 var east = rs["east"];
35031 var center = rs["center"];
35032 //if(this.hideOnLayout){ // not supported anymore
35033 //c.el.setStyle("display", "none");
35035 if(north && north.isVisible()){
35036 var b = north.getBox();
35037 var m = north.getMargins();
35038 b.width = w - (m.left+m.right);
35041 centerY = b.height + b.y + m.bottom;
35042 centerH -= centerY;
35043 north.updateBox(this.safeBox(b));
35045 if(south && south.isVisible()){
35046 var b = south.getBox();
35047 var m = south.getMargins();
35048 b.width = w - (m.left+m.right);
35050 var totalHeight = (b.height + m.top + m.bottom);
35051 b.y = h - totalHeight + m.top;
35052 centerH -= totalHeight;
35053 south.updateBox(this.safeBox(b));
35055 if(west && west.isVisible()){
35056 var b = west.getBox();
35057 var m = west.getMargins();
35058 b.height = centerH - (m.top+m.bottom);
35060 b.y = centerY + m.top;
35061 var totalWidth = (b.width + m.left + m.right);
35062 centerX += totalWidth;
35063 centerW -= totalWidth;
35064 west.updateBox(this.safeBox(b));
35066 if(east && east.isVisible()){
35067 var b = east.getBox();
35068 var m = east.getMargins();
35069 b.height = centerH - (m.top+m.bottom);
35070 var totalWidth = (b.width + m.left + m.right);
35071 b.x = w - totalWidth + m.left;
35072 b.y = centerY + m.top;
35073 centerW -= totalWidth;
35074 east.updateBox(this.safeBox(b));
35077 var m = center.getMargins();
35079 x: centerX + m.left,
35080 y: centerY + m.top,
35081 width: centerW - (m.left+m.right),
35082 height: centerH - (m.top+m.bottom)
35084 //if(this.hideOnLayout){
35085 //center.el.setStyle("display", "block");
35087 center.updateBox(this.safeBox(centerBox));
35090 this.fireEvent("layout", this);
35094 safeBox : function(box){
35095 box.width = Math.max(0, box.width);
35096 box.height = Math.max(0, box.height);
35101 * Adds a ContentPanel (or subclass) to this layout.
35102 * @param {String} target The target region key (north, south, east, west or center).
35103 * @param {Roo.ContentPanel} panel The panel to add
35104 * @return {Roo.ContentPanel} The added panel
35106 add : function(target, panel){
35108 target = target.toLowerCase();
35109 return this.regions[target].add(panel);
35113 * Remove a ContentPanel (or subclass) to this layout.
35114 * @param {String} target The target region key (north, south, east, west or center).
35115 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35116 * @return {Roo.ContentPanel} The removed panel
35118 remove : function(target, panel){
35119 target = target.toLowerCase();
35120 return this.regions[target].remove(panel);
35124 * Searches all regions for a panel with the specified id
35125 * @param {String} panelId
35126 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35128 findPanel : function(panelId){
35129 var rs = this.regions;
35130 for(var target in rs){
35131 if(typeof rs[target] != "function"){
35132 var p = rs[target].getPanel(panelId);
35142 * Searches all regions for a panel with the specified id and activates (shows) it.
35143 * @param {String/ContentPanel} panelId The panels id or the panel itself
35144 * @return {Roo.ContentPanel} The shown panel or null
35146 showPanel : function(panelId) {
35147 var rs = this.regions;
35148 for(var target in rs){
35149 var r = rs[target];
35150 if(typeof r != "function"){
35151 if(r.hasPanel(panelId)){
35152 return r.showPanel(panelId);
35160 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35161 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35164 restoreState : function(provider){
35166 provider = Roo.state.Manager;
35168 var sm = new Roo.LayoutStateManager();
35169 sm.init(this, provider);
35175 * Adds a xtype elements to the layout.
35179 xtype : 'ContentPanel',
35186 xtype : 'NestedLayoutPanel',
35192 items : [ ... list of content panels or nested layout panels.. ]
35196 * @param {Object} cfg Xtype definition of item to add.
35198 addxtype : function(cfg)
35200 // basically accepts a pannel...
35201 // can accept a layout region..!?!?
35202 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35205 // theory? children can only be panels??
35207 //if (!cfg.xtype.match(/Panel$/)) {
35212 if (typeof(cfg.region) == 'undefined') {
35213 Roo.log("Failed to add Panel, region was not set");
35217 var region = cfg.region;
35223 xitems = cfg.items;
35230 case 'Content': // ContentPanel (el, cfg)
35231 case 'Scroll': // ContentPanel (el, cfg)
35233 cfg.autoCreate = true;
35234 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35236 // var el = this.el.createChild();
35237 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35240 this.add(region, ret);
35244 case 'TreePanel': // our new panel!
35245 cfg.el = this.el.createChild();
35246 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35247 this.add(region, ret);
35252 // create a new Layout (which is a Border Layout...
35254 var clayout = cfg.layout;
35255 clayout.el = this.el.createChild();
35256 clayout.items = clayout.items || [];
35260 // replace this exitems with the clayout ones..
35261 xitems = clayout.items;
35263 // force background off if it's in center...
35264 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35265 cfg.background = false;
35267 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35270 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35271 //console.log('adding nested layout panel ' + cfg.toSource());
35272 this.add(region, ret);
35273 nb = {}; /// find first...
35278 // needs grid and region
35280 //var el = this.getRegion(region).el.createChild();
35282 *var el = this.el.createChild();
35283 // create the grid first...
35284 cfg.grid.container = el;
35285 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35288 if (region == 'center' && this.active ) {
35289 cfg.background = false;
35292 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35294 this.add(region, ret);
35296 if (cfg.background) {
35297 // render grid on panel activation (if panel background)
35298 ret.on('activate', function(gp) {
35299 if (!gp.grid.rendered) {
35300 // gp.grid.render(el);
35304 // cfg.grid.render(el);
35310 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35311 // it was the old xcomponent building that caused this before.
35312 // espeically if border is the top element in the tree.
35322 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35324 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35325 this.add(region, ret);
35329 throw "Can not add '" + cfg.xtype + "' to Border";
35335 this.beginUpdate();
35339 Roo.each(xitems, function(i) {
35340 region = nb && i.region ? i.region : false;
35342 var add = ret.addxtype(i);
35345 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35346 if (!i.background) {
35347 abn[region] = nb[region] ;
35354 // make the last non-background panel active..
35355 //if (nb) { Roo.log(abn); }
35358 for(var r in abn) {
35359 region = this.getRegion(r);
35361 // tried using nb[r], but it does not work..
35363 region.showPanel(abn[r]);
35374 factory : function(cfg)
35377 var validRegions = Roo.bootstrap.layout.Border.regions;
35379 var target = cfg.region;
35382 var r = Roo.bootstrap.layout;
35386 return new r.North(cfg);
35388 return new r.South(cfg);
35390 return new r.East(cfg);
35392 return new r.West(cfg);
35394 return new r.Center(cfg);
35396 throw 'Layout region "'+target+'" not supported.';
35403 * Ext JS Library 1.1.1
35404 * Copyright(c) 2006-2007, Ext JS, LLC.
35406 * Originally Released Under LGPL - original licence link has changed is not relivant.
35409 * <script type="text/javascript">
35413 * @class Roo.bootstrap.layout.Basic
35414 * @extends Roo.util.Observable
35415 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35416 * and does not have a titlebar, tabs or any other features. All it does is size and position
35417 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35418 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35419 * @cfg {string} region the region that it inhabits..
35420 * @cfg {bool} skipConfig skip config?
35424 Roo.bootstrap.layout.Basic = function(config){
35426 this.mgr = config.mgr;
35428 this.position = config.region;
35430 var skipConfig = config.skipConfig;
35434 * @scope Roo.BasicLayoutRegion
35438 * @event beforeremove
35439 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35440 * @param {Roo.LayoutRegion} this
35441 * @param {Roo.ContentPanel} panel The panel
35442 * @param {Object} e The cancel event object
35444 "beforeremove" : true,
35446 * @event invalidated
35447 * Fires when the layout for this region is changed.
35448 * @param {Roo.LayoutRegion} this
35450 "invalidated" : true,
35452 * @event visibilitychange
35453 * Fires when this region is shown or hidden
35454 * @param {Roo.LayoutRegion} this
35455 * @param {Boolean} visibility true or false
35457 "visibilitychange" : true,
35459 * @event paneladded
35460 * Fires when a panel is added.
35461 * @param {Roo.LayoutRegion} this
35462 * @param {Roo.ContentPanel} panel The panel
35464 "paneladded" : true,
35466 * @event panelremoved
35467 * Fires when a panel is removed.
35468 * @param {Roo.LayoutRegion} this
35469 * @param {Roo.ContentPanel} panel The panel
35471 "panelremoved" : true,
35473 * @event beforecollapse
35474 * Fires when this region before collapse.
35475 * @param {Roo.LayoutRegion} this
35477 "beforecollapse" : true,
35480 * Fires when this region is collapsed.
35481 * @param {Roo.LayoutRegion} this
35483 "collapsed" : true,
35486 * Fires when this region is expanded.
35487 * @param {Roo.LayoutRegion} this
35492 * Fires when this region is slid into view.
35493 * @param {Roo.LayoutRegion} this
35495 "slideshow" : true,
35498 * Fires when this region slides out of view.
35499 * @param {Roo.LayoutRegion} this
35501 "slidehide" : true,
35503 * @event panelactivated
35504 * Fires when a panel is activated.
35505 * @param {Roo.LayoutRegion} this
35506 * @param {Roo.ContentPanel} panel The activated panel
35508 "panelactivated" : true,
35511 * Fires when the user resizes this region.
35512 * @param {Roo.LayoutRegion} this
35513 * @param {Number} newSize The new size (width for east/west, height for north/south)
35517 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35518 this.panels = new Roo.util.MixedCollection();
35519 this.panels.getKey = this.getPanelId.createDelegate(this);
35521 this.activePanel = null;
35522 // ensure listeners are added...
35524 if (config.listeners || config.events) {
35525 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35526 listeners : config.listeners || {},
35527 events : config.events || {}
35531 if(skipConfig !== true){
35532 this.applyConfig(config);
35536 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35538 getPanelId : function(p){
35542 applyConfig : function(config){
35543 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35544 this.config = config;
35549 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35550 * the width, for horizontal (north, south) the height.
35551 * @param {Number} newSize The new width or height
35553 resizeTo : function(newSize){
35554 var el = this.el ? this.el :
35555 (this.activePanel ? this.activePanel.getEl() : null);
35557 switch(this.position){
35560 el.setWidth(newSize);
35561 this.fireEvent("resized", this, newSize);
35565 el.setHeight(newSize);
35566 this.fireEvent("resized", this, newSize);
35572 getBox : function(){
35573 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35576 getMargins : function(){
35577 return this.margins;
35580 updateBox : function(box){
35582 var el = this.activePanel.getEl();
35583 el.dom.style.left = box.x + "px";
35584 el.dom.style.top = box.y + "px";
35585 this.activePanel.setSize(box.width, box.height);
35589 * Returns the container element for this region.
35590 * @return {Roo.Element}
35592 getEl : function(){
35593 return this.activePanel;
35597 * Returns true if this region is currently visible.
35598 * @return {Boolean}
35600 isVisible : function(){
35601 return this.activePanel ? true : false;
35604 setActivePanel : function(panel){
35605 panel = this.getPanel(panel);
35606 if(this.activePanel && this.activePanel != panel){
35607 this.activePanel.setActiveState(false);
35608 this.activePanel.getEl().setLeftTop(-10000,-10000);
35610 this.activePanel = panel;
35611 panel.setActiveState(true);
35613 panel.setSize(this.box.width, this.box.height);
35615 this.fireEvent("panelactivated", this, panel);
35616 this.fireEvent("invalidated");
35620 * Show the specified panel.
35621 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35622 * @return {Roo.ContentPanel} The shown panel or null
35624 showPanel : function(panel){
35625 panel = this.getPanel(panel);
35627 this.setActivePanel(panel);
35633 * Get the active panel for this region.
35634 * @return {Roo.ContentPanel} The active panel or null
35636 getActivePanel : function(){
35637 return this.activePanel;
35641 * Add the passed ContentPanel(s)
35642 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35643 * @return {Roo.ContentPanel} The panel added (if only one was added)
35645 add : function(panel){
35646 if(arguments.length > 1){
35647 for(var i = 0, len = arguments.length; i < len; i++) {
35648 this.add(arguments[i]);
35652 if(this.hasPanel(panel)){
35653 this.showPanel(panel);
35656 var el = panel.getEl();
35657 if(el.dom.parentNode != this.mgr.el.dom){
35658 this.mgr.el.dom.appendChild(el.dom);
35660 if(panel.setRegion){
35661 panel.setRegion(this);
35663 this.panels.add(panel);
35664 el.setStyle("position", "absolute");
35665 if(!panel.background){
35666 this.setActivePanel(panel);
35667 if(this.config.initialSize && this.panels.getCount()==1){
35668 this.resizeTo(this.config.initialSize);
35671 this.fireEvent("paneladded", this, panel);
35676 * Returns true if the panel is in this region.
35677 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35678 * @return {Boolean}
35680 hasPanel : function(panel){
35681 if(typeof panel == "object"){ // must be panel obj
35682 panel = panel.getId();
35684 return this.getPanel(panel) ? true : false;
35688 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35689 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35690 * @param {Boolean} preservePanel Overrides the config preservePanel option
35691 * @return {Roo.ContentPanel} The panel that was removed
35693 remove : function(panel, preservePanel){
35694 panel = this.getPanel(panel);
35699 this.fireEvent("beforeremove", this, panel, e);
35700 if(e.cancel === true){
35703 var panelId = panel.getId();
35704 this.panels.removeKey(panelId);
35709 * Returns the panel specified or null if it's not in this region.
35710 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35711 * @return {Roo.ContentPanel}
35713 getPanel : function(id){
35714 if(typeof id == "object"){ // must be panel obj
35717 return this.panels.get(id);
35721 * Returns this regions position (north/south/east/west/center).
35724 getPosition: function(){
35725 return this.position;
35729 * Ext JS Library 1.1.1
35730 * Copyright(c) 2006-2007, Ext JS, LLC.
35732 * Originally Released Under LGPL - original licence link has changed is not relivant.
35735 * <script type="text/javascript">
35739 * @class Roo.bootstrap.layout.Region
35740 * @extends Roo.bootstrap.layout.Basic
35741 * This class represents a region in a layout manager.
35743 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35744 * @cfg {Object} cmargins Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
35745 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35746 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35747 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35748 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35749 * @cfg {String} title The title for the region (overrides panel titles)
35750 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35751 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35752 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35753 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35754 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35755 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35756 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35757 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35758 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35759 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35761 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35762 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35763 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35764 * @cfg {Number} width For East/West panels
35765 * @cfg {Number} height For North/South panels
35766 * @cfg {Boolean} split To show the splitter
35767 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35769 * @cfg {string} cls Extra CSS classes to add to region
35771 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35772 * @cfg {string} region the region that it inhabits..
35775 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35776 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35778 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35779 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35780 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35782 Roo.bootstrap.layout.Region = function(config)
35784 this.applyConfig(config);
35786 var mgr = config.mgr;
35787 var pos = config.region;
35788 config.skipConfig = true;
35789 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35792 this.onRender(mgr.el);
35795 this.visible = true;
35796 this.collapsed = false;
35797 this.unrendered_panels = [];
35800 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35802 position: '', // set by wrapper (eg. north/south etc..)
35803 unrendered_panels : null, // unrendered panels.
35804 createBody : function(){
35805 /** This region's body element
35806 * @type Roo.Element */
35807 this.bodyEl = this.el.createChild({
35809 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35813 onRender: function(ctr, pos)
35815 var dh = Roo.DomHelper;
35816 /** This region's container element
35817 * @type Roo.Element */
35818 this.el = dh.append(ctr.dom, {
35820 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35822 /** This region's title element
35823 * @type Roo.Element */
35825 this.titleEl = dh.append(this.el.dom,
35828 unselectable: "on",
35829 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35831 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35832 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35835 this.titleEl.enableDisplayMode();
35836 /** This region's title text element
35837 * @type HTMLElement */
35838 this.titleTextEl = this.titleEl.dom.firstChild;
35839 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35841 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35842 this.closeBtn.enableDisplayMode();
35843 this.closeBtn.on("click", this.closeClicked, this);
35844 this.closeBtn.hide();
35846 this.createBody(this.config);
35847 if(this.config.hideWhenEmpty){
35849 this.on("paneladded", this.validateVisibility, this);
35850 this.on("panelremoved", this.validateVisibility, this);
35852 if(this.autoScroll){
35853 this.bodyEl.setStyle("overflow", "auto");
35855 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35857 //if(c.titlebar !== false){
35858 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35859 this.titleEl.hide();
35861 this.titleEl.show();
35862 if(this.config.title){
35863 this.titleTextEl.innerHTML = this.config.title;
35867 if(this.config.collapsed){
35868 this.collapse(true);
35870 if(this.config.hidden){
35874 if (this.unrendered_panels && this.unrendered_panels.length) {
35875 for (var i =0;i< this.unrendered_panels.length; i++) {
35876 this.add(this.unrendered_panels[i]);
35878 this.unrendered_panels = null;
35884 applyConfig : function(c)
35887 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35888 var dh = Roo.DomHelper;
35889 if(c.titlebar !== false){
35890 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35891 this.collapseBtn.on("click", this.collapse, this);
35892 this.collapseBtn.enableDisplayMode();
35894 if(c.showPin === true || this.showPin){
35895 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35896 this.stickBtn.enableDisplayMode();
35897 this.stickBtn.on("click", this.expand, this);
35898 this.stickBtn.hide();
35903 /** This region's collapsed element
35904 * @type Roo.Element */
35907 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35908 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35911 if(c.floatable !== false){
35912 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35913 this.collapsedEl.on("click", this.collapseClick, this);
35916 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35917 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35918 id: "message", unselectable: "on", style:{"float":"left"}});
35919 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35921 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35922 this.expandBtn.on("click", this.expand, this);
35926 if(this.collapseBtn){
35927 this.collapseBtn.setVisible(c.collapsible == true);
35930 this.cmargins = c.cmargins || this.cmargins ||
35931 (this.position == "west" || this.position == "east" ?
35932 {top: 0, left: 2, right:2, bottom: 0} :
35933 {top: 2, left: 0, right:0, bottom: 2});
35935 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35938 this.bottomTabs = c.tabPosition != "top";
35940 this.autoScroll = c.autoScroll || false;
35945 this.duration = c.duration || .30;
35946 this.slideDuration = c.slideDuration || .45;
35951 * Returns true if this region is currently visible.
35952 * @return {Boolean}
35954 isVisible : function(){
35955 return this.visible;
35959 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35960 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35962 //setCollapsedTitle : function(title){
35963 // title = title || " ";
35964 // if(this.collapsedTitleTextEl){
35965 // this.collapsedTitleTextEl.innerHTML = title;
35969 getBox : function(){
35971 // if(!this.collapsed){
35972 b = this.el.getBox(false, true);
35974 // b = this.collapsedEl.getBox(false, true);
35979 getMargins : function(){
35980 return this.margins;
35981 //return this.collapsed ? this.cmargins : this.margins;
35984 highlight : function(){
35985 this.el.addClass("x-layout-panel-dragover");
35988 unhighlight : function(){
35989 this.el.removeClass("x-layout-panel-dragover");
35992 updateBox : function(box)
35994 if (!this.bodyEl) {
35995 return; // not rendered yet..
35999 if(!this.collapsed){
36000 this.el.dom.style.left = box.x + "px";
36001 this.el.dom.style.top = box.y + "px";
36002 this.updateBody(box.width, box.height);
36004 this.collapsedEl.dom.style.left = box.x + "px";
36005 this.collapsedEl.dom.style.top = box.y + "px";
36006 this.collapsedEl.setSize(box.width, box.height);
36009 this.tabs.autoSizeTabs();
36013 updateBody : function(w, h)
36016 this.el.setWidth(w);
36017 w -= this.el.getBorderWidth("rl");
36018 if(this.config.adjustments){
36019 w += this.config.adjustments[0];
36022 if(h !== null && h > 0){
36023 this.el.setHeight(h);
36024 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36025 h -= this.el.getBorderWidth("tb");
36026 if(this.config.adjustments){
36027 h += this.config.adjustments[1];
36029 this.bodyEl.setHeight(h);
36031 h = this.tabs.syncHeight(h);
36034 if(this.panelSize){
36035 w = w !== null ? w : this.panelSize.width;
36036 h = h !== null ? h : this.panelSize.height;
36038 if(this.activePanel){
36039 var el = this.activePanel.getEl();
36040 w = w !== null ? w : el.getWidth();
36041 h = h !== null ? h : el.getHeight();
36042 this.panelSize = {width: w, height: h};
36043 this.activePanel.setSize(w, h);
36045 if(Roo.isIE && this.tabs){
36046 this.tabs.el.repaint();
36051 * Returns the container element for this region.
36052 * @return {Roo.Element}
36054 getEl : function(){
36059 * Hides this region.
36062 //if(!this.collapsed){
36063 this.el.dom.style.left = "-2000px";
36066 // this.collapsedEl.dom.style.left = "-2000px";
36067 // this.collapsedEl.hide();
36069 this.visible = false;
36070 this.fireEvent("visibilitychange", this, false);
36074 * Shows this region if it was previously hidden.
36077 //if(!this.collapsed){
36080 // this.collapsedEl.show();
36082 this.visible = true;
36083 this.fireEvent("visibilitychange", this, true);
36086 closeClicked : function(){
36087 if(this.activePanel){
36088 this.remove(this.activePanel);
36092 collapseClick : function(e){
36094 e.stopPropagation();
36097 e.stopPropagation();
36103 * Collapses this region.
36104 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36107 collapse : function(skipAnim, skipCheck = false){
36108 if(this.collapsed) {
36112 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36114 this.collapsed = true;
36116 this.split.el.hide();
36118 if(this.config.animate && skipAnim !== true){
36119 this.fireEvent("invalidated", this);
36120 this.animateCollapse();
36122 this.el.setLocation(-20000,-20000);
36124 this.collapsedEl.show();
36125 this.fireEvent("collapsed", this);
36126 this.fireEvent("invalidated", this);
36132 animateCollapse : function(){
36137 * Expands this region if it was previously collapsed.
36138 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36139 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36142 expand : function(e, skipAnim){
36144 e.stopPropagation();
36146 if(!this.collapsed || this.el.hasActiveFx()) {
36150 this.afterSlideIn();
36153 this.collapsed = false;
36154 if(this.config.animate && skipAnim !== true){
36155 this.animateExpand();
36159 this.split.el.show();
36161 this.collapsedEl.setLocation(-2000,-2000);
36162 this.collapsedEl.hide();
36163 this.fireEvent("invalidated", this);
36164 this.fireEvent("expanded", this);
36168 animateExpand : function(){
36172 initTabs : function()
36174 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36176 var ts = new Roo.bootstrap.panel.Tabs({
36177 el: this.bodyEl.dom,
36178 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36179 disableTooltips: this.config.disableTabTips,
36180 toolbar : this.config.toolbar
36183 if(this.config.hideTabs){
36184 ts.stripWrap.setDisplayed(false);
36187 ts.resizeTabs = this.config.resizeTabs === true;
36188 ts.minTabWidth = this.config.minTabWidth || 40;
36189 ts.maxTabWidth = this.config.maxTabWidth || 250;
36190 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36191 ts.monitorResize = false;
36192 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36193 ts.bodyEl.addClass('roo-layout-tabs-body');
36194 this.panels.each(this.initPanelAsTab, this);
36197 initPanelAsTab : function(panel){
36198 var ti = this.tabs.addTab(
36202 this.config.closeOnTab && panel.isClosable(),
36205 if(panel.tabTip !== undefined){
36206 ti.setTooltip(panel.tabTip);
36208 ti.on("activate", function(){
36209 this.setActivePanel(panel);
36212 if(this.config.closeOnTab){
36213 ti.on("beforeclose", function(t, e){
36215 this.remove(panel);
36219 panel.tabItem = ti;
36224 updatePanelTitle : function(panel, title)
36226 if(this.activePanel == panel){
36227 this.updateTitle(title);
36230 var ti = this.tabs.getTab(panel.getEl().id);
36232 if(panel.tabTip !== undefined){
36233 ti.setTooltip(panel.tabTip);
36238 updateTitle : function(title){
36239 if(this.titleTextEl && !this.config.title){
36240 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36244 setActivePanel : function(panel)
36246 panel = this.getPanel(panel);
36247 if(this.activePanel && this.activePanel != panel){
36248 if(this.activePanel.setActiveState(false) === false){
36252 this.activePanel = panel;
36253 panel.setActiveState(true);
36254 if(this.panelSize){
36255 panel.setSize(this.panelSize.width, this.panelSize.height);
36258 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36260 this.updateTitle(panel.getTitle());
36262 this.fireEvent("invalidated", this);
36264 this.fireEvent("panelactivated", this, panel);
36268 * Shows the specified panel.
36269 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36270 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36272 showPanel : function(panel)
36274 panel = this.getPanel(panel);
36277 var tab = this.tabs.getTab(panel.getEl().id);
36278 if(tab.isHidden()){
36279 this.tabs.unhideTab(tab.id);
36283 this.setActivePanel(panel);
36290 * Get the active panel for this region.
36291 * @return {Roo.ContentPanel} The active panel or null
36293 getActivePanel : function(){
36294 return this.activePanel;
36297 validateVisibility : function(){
36298 if(this.panels.getCount() < 1){
36299 this.updateTitle(" ");
36300 this.closeBtn.hide();
36303 if(!this.isVisible()){
36310 * Adds the passed ContentPanel(s) to this region.
36311 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36312 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36314 add : function(panel)
36316 if(arguments.length > 1){
36317 for(var i = 0, len = arguments.length; i < len; i++) {
36318 this.add(arguments[i]);
36323 // if we have not been rendered yet, then we can not really do much of this..
36324 if (!this.bodyEl) {
36325 this.unrendered_panels.push(panel);
36332 if(this.hasPanel(panel)){
36333 this.showPanel(panel);
36336 panel.setRegion(this);
36337 this.panels.add(panel);
36338 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36339 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36340 // and hide them... ???
36341 this.bodyEl.dom.appendChild(panel.getEl().dom);
36342 if(panel.background !== true){
36343 this.setActivePanel(panel);
36345 this.fireEvent("paneladded", this, panel);
36352 this.initPanelAsTab(panel);
36356 if(panel.background !== true){
36357 this.tabs.activate(panel.getEl().id);
36359 this.fireEvent("paneladded", this, panel);
36364 * Hides the tab for the specified panel.
36365 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36367 hidePanel : function(panel){
36368 if(this.tabs && (panel = this.getPanel(panel))){
36369 this.tabs.hideTab(panel.getEl().id);
36374 * Unhides the tab for a previously hidden panel.
36375 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36377 unhidePanel : function(panel){
36378 if(this.tabs && (panel = this.getPanel(panel))){
36379 this.tabs.unhideTab(panel.getEl().id);
36383 clearPanels : function(){
36384 while(this.panels.getCount() > 0){
36385 this.remove(this.panels.first());
36390 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36391 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36392 * @param {Boolean} preservePanel Overrides the config preservePanel option
36393 * @return {Roo.ContentPanel} The panel that was removed
36395 remove : function(panel, preservePanel)
36397 panel = this.getPanel(panel);
36402 this.fireEvent("beforeremove", this, panel, e);
36403 if(e.cancel === true){
36406 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36407 var panelId = panel.getId();
36408 this.panels.removeKey(panelId);
36410 document.body.appendChild(panel.getEl().dom);
36413 this.tabs.removeTab(panel.getEl().id);
36414 }else if (!preservePanel){
36415 this.bodyEl.dom.removeChild(panel.getEl().dom);
36417 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36418 var p = this.panels.first();
36419 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36420 tempEl.appendChild(p.getEl().dom);
36421 this.bodyEl.update("");
36422 this.bodyEl.dom.appendChild(p.getEl().dom);
36424 this.updateTitle(p.getTitle());
36426 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36427 this.setActivePanel(p);
36429 panel.setRegion(null);
36430 if(this.activePanel == panel){
36431 this.activePanel = null;
36433 if(this.config.autoDestroy !== false && preservePanel !== true){
36434 try{panel.destroy();}catch(e){}
36436 this.fireEvent("panelremoved", this, panel);
36441 * Returns the TabPanel component used by this region
36442 * @return {Roo.TabPanel}
36444 getTabs : function(){
36448 createTool : function(parentEl, className){
36449 var btn = Roo.DomHelper.append(parentEl, {
36451 cls: "x-layout-tools-button",
36454 cls: "roo-layout-tools-button-inner " + className,
36458 btn.addClassOnOver("roo-layout-tools-button-over");
36463 * Ext JS Library 1.1.1
36464 * Copyright(c) 2006-2007, Ext JS, LLC.
36466 * Originally Released Under LGPL - original licence link has changed is not relivant.
36469 * <script type="text/javascript">
36475 * @class Roo.SplitLayoutRegion
36476 * @extends Roo.LayoutRegion
36477 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36479 Roo.bootstrap.layout.Split = function(config){
36480 this.cursor = config.cursor;
36481 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36484 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36486 splitTip : "Drag to resize.",
36487 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36488 useSplitTips : false,
36490 applyConfig : function(config){
36491 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36494 onRender : function(ctr,pos) {
36496 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36497 if(!this.config.split){
36502 var splitEl = Roo.DomHelper.append(ctr.dom, {
36504 id: this.el.id + "-split",
36505 cls: "roo-layout-split roo-layout-split-"+this.position,
36508 /** The SplitBar for this region
36509 * @type Roo.SplitBar */
36510 // does not exist yet...
36511 Roo.log([this.position, this.orientation]);
36513 this.split = new Roo.bootstrap.SplitBar({
36514 dragElement : splitEl,
36515 resizingElement: this.el,
36516 orientation : this.orientation
36519 this.split.on("moved", this.onSplitMove, this);
36520 this.split.useShim = this.config.useShim === true;
36521 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36522 if(this.useSplitTips){
36523 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36525 //if(config.collapsible){
36526 // this.split.el.on("dblclick", this.collapse, this);
36529 if(typeof this.config.minSize != "undefined"){
36530 this.split.minSize = this.config.minSize;
36532 if(typeof this.config.maxSize != "undefined"){
36533 this.split.maxSize = this.config.maxSize;
36535 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36536 this.hideSplitter();
36541 getHMaxSize : function(){
36542 var cmax = this.config.maxSize || 10000;
36543 var center = this.mgr.getRegion("center");
36544 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36547 getVMaxSize : function(){
36548 var cmax = this.config.maxSize || 10000;
36549 var center = this.mgr.getRegion("center");
36550 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36553 onSplitMove : function(split, newSize){
36554 this.fireEvent("resized", this, newSize);
36558 * Returns the {@link Roo.SplitBar} for this region.
36559 * @return {Roo.SplitBar}
36561 getSplitBar : function(){
36566 this.hideSplitter();
36567 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36570 hideSplitter : function(){
36572 this.split.el.setLocation(-2000,-2000);
36573 this.split.el.hide();
36579 this.split.el.show();
36581 Roo.bootstrap.layout.Split.superclass.show.call(this);
36584 beforeSlide: function(){
36585 if(Roo.isGecko){// firefox overflow auto bug workaround
36586 this.bodyEl.clip();
36588 this.tabs.bodyEl.clip();
36590 if(this.activePanel){
36591 this.activePanel.getEl().clip();
36593 if(this.activePanel.beforeSlide){
36594 this.activePanel.beforeSlide();
36600 afterSlide : function(){
36601 if(Roo.isGecko){// firefox overflow auto bug workaround
36602 this.bodyEl.unclip();
36604 this.tabs.bodyEl.unclip();
36606 if(this.activePanel){
36607 this.activePanel.getEl().unclip();
36608 if(this.activePanel.afterSlide){
36609 this.activePanel.afterSlide();
36615 initAutoHide : function(){
36616 if(this.autoHide !== false){
36617 if(!this.autoHideHd){
36618 var st = new Roo.util.DelayedTask(this.slideIn, this);
36619 this.autoHideHd = {
36620 "mouseout": function(e){
36621 if(!e.within(this.el, true)){
36625 "mouseover" : function(e){
36631 this.el.on(this.autoHideHd);
36635 clearAutoHide : function(){
36636 if(this.autoHide !== false){
36637 this.el.un("mouseout", this.autoHideHd.mouseout);
36638 this.el.un("mouseover", this.autoHideHd.mouseover);
36642 clearMonitor : function(){
36643 Roo.get(document).un("click", this.slideInIf, this);
36646 // these names are backwards but not changed for compat
36647 slideOut : function(){
36648 if(this.isSlid || this.el.hasActiveFx()){
36651 this.isSlid = true;
36652 if(this.collapseBtn){
36653 this.collapseBtn.hide();
36655 this.closeBtnState = this.closeBtn.getStyle('display');
36656 this.closeBtn.hide();
36658 this.stickBtn.show();
36661 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36662 this.beforeSlide();
36663 this.el.setStyle("z-index", 10001);
36664 this.el.slideIn(this.getSlideAnchor(), {
36665 callback: function(){
36667 this.initAutoHide();
36668 Roo.get(document).on("click", this.slideInIf, this);
36669 this.fireEvent("slideshow", this);
36676 afterSlideIn : function(){
36677 this.clearAutoHide();
36678 this.isSlid = false;
36679 this.clearMonitor();
36680 this.el.setStyle("z-index", "");
36681 if(this.collapseBtn){
36682 this.collapseBtn.show();
36684 this.closeBtn.setStyle('display', this.closeBtnState);
36686 this.stickBtn.hide();
36688 this.fireEvent("slidehide", this);
36691 slideIn : function(cb){
36692 if(!this.isSlid || this.el.hasActiveFx()){
36696 this.isSlid = false;
36697 this.beforeSlide();
36698 this.el.slideOut(this.getSlideAnchor(), {
36699 callback: function(){
36700 this.el.setLeftTop(-10000, -10000);
36702 this.afterSlideIn();
36710 slideInIf : function(e){
36711 if(!e.within(this.el)){
36716 animateCollapse : function(){
36717 this.beforeSlide();
36718 this.el.setStyle("z-index", 20000);
36719 var anchor = this.getSlideAnchor();
36720 this.el.slideOut(anchor, {
36721 callback : function(){
36722 this.el.setStyle("z-index", "");
36723 this.collapsedEl.slideIn(anchor, {duration:.3});
36725 this.el.setLocation(-10000,-10000);
36727 this.fireEvent("collapsed", this);
36734 animateExpand : function(){
36735 this.beforeSlide();
36736 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36737 this.el.setStyle("z-index", 20000);
36738 this.collapsedEl.hide({
36741 this.el.slideIn(this.getSlideAnchor(), {
36742 callback : function(){
36743 this.el.setStyle("z-index", "");
36746 this.split.el.show();
36748 this.fireEvent("invalidated", this);
36749 this.fireEvent("expanded", this);
36777 getAnchor : function(){
36778 return this.anchors[this.position];
36781 getCollapseAnchor : function(){
36782 return this.canchors[this.position];
36785 getSlideAnchor : function(){
36786 return this.sanchors[this.position];
36789 getAlignAdj : function(){
36790 var cm = this.cmargins;
36791 switch(this.position){
36807 getExpandAdj : function(){
36808 var c = this.collapsedEl, cm = this.cmargins;
36809 switch(this.position){
36811 return [-(cm.right+c.getWidth()+cm.left), 0];
36814 return [cm.right+c.getWidth()+cm.left, 0];
36817 return [0, -(cm.top+cm.bottom+c.getHeight())];
36820 return [0, cm.top+cm.bottom+c.getHeight()];
36826 * Ext JS Library 1.1.1
36827 * Copyright(c) 2006-2007, Ext JS, LLC.
36829 * Originally Released Under LGPL - original licence link has changed is not relivant.
36832 * <script type="text/javascript">
36835 * These classes are private internal classes
36837 Roo.bootstrap.layout.Center = function(config){
36838 config.region = "center";
36839 Roo.bootstrap.layout.Region.call(this, config);
36840 this.visible = true;
36841 this.minWidth = config.minWidth || 20;
36842 this.minHeight = config.minHeight || 20;
36845 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36847 // center panel can't be hidden
36851 // center panel can't be hidden
36854 getMinWidth: function(){
36855 return this.minWidth;
36858 getMinHeight: function(){
36859 return this.minHeight;
36872 Roo.bootstrap.layout.North = function(config)
36874 config.region = 'north';
36875 config.cursor = 'n-resize';
36877 Roo.bootstrap.layout.Split.call(this, config);
36881 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36882 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36883 this.split.el.addClass("roo-layout-split-v");
36885 var size = config.initialSize || config.height;
36886 if(typeof size != "undefined"){
36887 this.el.setHeight(size);
36890 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36892 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36896 getBox : function(){
36897 if(this.collapsed){
36898 return this.collapsedEl.getBox();
36900 var box = this.el.getBox();
36902 box.height += this.split.el.getHeight();
36907 updateBox : function(box){
36908 if(this.split && !this.collapsed){
36909 box.height -= this.split.el.getHeight();
36910 this.split.el.setLeft(box.x);
36911 this.split.el.setTop(box.y+box.height);
36912 this.split.el.setWidth(box.width);
36914 if(this.collapsed){
36915 this.updateBody(box.width, null);
36917 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36925 Roo.bootstrap.layout.South = function(config){
36926 config.region = 'south';
36927 config.cursor = 's-resize';
36928 Roo.bootstrap.layout.Split.call(this, config);
36930 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36931 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36932 this.split.el.addClass("roo-layout-split-v");
36934 var size = config.initialSize || config.height;
36935 if(typeof size != "undefined"){
36936 this.el.setHeight(size);
36940 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36941 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36942 getBox : function(){
36943 if(this.collapsed){
36944 return this.collapsedEl.getBox();
36946 var box = this.el.getBox();
36948 var sh = this.split.el.getHeight();
36955 updateBox : function(box){
36956 if(this.split && !this.collapsed){
36957 var sh = this.split.el.getHeight();
36960 this.split.el.setLeft(box.x);
36961 this.split.el.setTop(box.y-sh);
36962 this.split.el.setWidth(box.width);
36964 if(this.collapsed){
36965 this.updateBody(box.width, null);
36967 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36971 Roo.bootstrap.layout.East = function(config){
36972 config.region = "east";
36973 config.cursor = "e-resize";
36974 Roo.bootstrap.layout.Split.call(this, config);
36976 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
36977 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
36978 this.split.el.addClass("roo-layout-split-h");
36980 var size = config.initialSize || config.width;
36981 if(typeof size != "undefined"){
36982 this.el.setWidth(size);
36985 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
36986 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
36987 getBox : function(){
36988 if(this.collapsed){
36989 return this.collapsedEl.getBox();
36991 var box = this.el.getBox();
36993 var sw = this.split.el.getWidth();
37000 updateBox : function(box){
37001 if(this.split && !this.collapsed){
37002 var sw = this.split.el.getWidth();
37004 this.split.el.setLeft(box.x);
37005 this.split.el.setTop(box.y);
37006 this.split.el.setHeight(box.height);
37009 if(this.collapsed){
37010 this.updateBody(null, box.height);
37012 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37016 Roo.bootstrap.layout.West = function(config){
37017 config.region = "west";
37018 config.cursor = "w-resize";
37020 Roo.bootstrap.layout.Split.call(this, config);
37022 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37023 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37024 this.split.el.addClass("roo-layout-split-h");
37028 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37029 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37031 onRender: function(ctr, pos)
37033 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37034 var size = this.config.initialSize || this.config.width;
37035 if(typeof size != "undefined"){
37036 this.el.setWidth(size);
37040 getBox : function(){
37041 if(this.collapsed){
37042 return this.collapsedEl.getBox();
37044 var box = this.el.getBox();
37046 box.width += this.split.el.getWidth();
37051 updateBox : function(box){
37052 if(this.split && !this.collapsed){
37053 var sw = this.split.el.getWidth();
37055 this.split.el.setLeft(box.x+box.width);
37056 this.split.el.setTop(box.y);
37057 this.split.el.setHeight(box.height);
37059 if(this.collapsed){
37060 this.updateBody(null, box.height);
37062 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37065 Roo.namespace("Roo.bootstrap.panel");/*
37067 * Ext JS Library 1.1.1
37068 * Copyright(c) 2006-2007, Ext JS, LLC.
37070 * Originally Released Under LGPL - original licence link has changed is not relivant.
37073 * <script type="text/javascript">
37076 * @class Roo.ContentPanel
37077 * @extends Roo.util.Observable
37078 * A basic ContentPanel element.
37079 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37080 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37081 * @cfg {Boolean/Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
37082 * @cfg {Boolean} closable True if the panel can be closed/removed
37083 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37084 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37085 * @cfg {Toolbar} toolbar A toolbar for this panel
37086 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37087 * @cfg {String} title The title for this panel
37088 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37089 * @cfg {String} url Calls {@link #setUrl} with this value
37090 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37091 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37092 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37093 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37094 * @cfg {Boolean} badges render the badges
37097 * Create a new ContentPanel.
37098 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37099 * @param {String/Object} config A string to set only the title or a config object
37100 * @param {String} content (optional) Set the HTML content for this panel
37101 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37103 Roo.bootstrap.panel.Content = function( config){
37105 this.tpl = config.tpl || false;
37107 var el = config.el;
37108 var content = config.content;
37110 if(config.autoCreate){ // xtype is available if this is called from factory
37113 this.el = Roo.get(el);
37114 if(!this.el && config && config.autoCreate){
37115 if(typeof config.autoCreate == "object"){
37116 if(!config.autoCreate.id){
37117 config.autoCreate.id = config.id||el;
37119 this.el = Roo.DomHelper.append(document.body,
37120 config.autoCreate, true);
37122 var elcfg = { tag: "div",
37123 cls: "roo-layout-inactive-content",
37127 elcfg.html = config.html;
37131 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37134 this.closable = false;
37135 this.loaded = false;
37136 this.active = false;
37139 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37141 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37143 this.wrapEl = this.el; //this.el.wrap();
37145 if (config.toolbar.items) {
37146 ti = config.toolbar.items ;
37147 delete config.toolbar.items ;
37151 this.toolbar.render(this.wrapEl, 'before');
37152 for(var i =0;i < ti.length;i++) {
37153 // Roo.log(['add child', items[i]]);
37154 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37156 this.toolbar.items = nitems;
37157 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37158 delete config.toolbar;
37162 // xtype created footer. - not sure if will work as we normally have to render first..
37163 if (this.footer && !this.footer.el && this.footer.xtype) {
37164 if (!this.wrapEl) {
37165 this.wrapEl = this.el.wrap();
37168 this.footer.container = this.wrapEl.createChild();
37170 this.footer = Roo.factory(this.footer, Roo);
37175 if(typeof config == "string"){
37176 this.title = config;
37178 Roo.apply(this, config);
37182 this.resizeEl = Roo.get(this.resizeEl, true);
37184 this.resizeEl = this.el;
37186 // handle view.xtype
37194 * Fires when this panel is activated.
37195 * @param {Roo.ContentPanel} this
37199 * @event deactivate
37200 * Fires when this panel is activated.
37201 * @param {Roo.ContentPanel} this
37203 "deactivate" : true,
37207 * Fires when this panel is resized if fitToFrame is true.
37208 * @param {Roo.ContentPanel} this
37209 * @param {Number} width The width after any component adjustments
37210 * @param {Number} height The height after any component adjustments
37216 * Fires when this tab is created
37217 * @param {Roo.ContentPanel} this
37228 if(this.autoScroll){
37229 this.resizeEl.setStyle("overflow", "auto");
37231 // fix randome scrolling
37232 //this.el.on('scroll', function() {
37233 // Roo.log('fix random scolling');
37234 // this.scrollTo('top',0);
37237 content = content || this.content;
37239 this.setContent(content);
37241 if(config && config.url){
37242 this.setUrl(this.url, this.params, this.loadOnce);
37247 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37249 if (this.view && typeof(this.view.xtype) != 'undefined') {
37250 this.view.el = this.el.appendChild(document.createElement("div"));
37251 this.view = Roo.factory(this.view);
37252 this.view.render && this.view.render(false, '');
37256 this.fireEvent('render', this);
37259 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37263 setRegion : function(region){
37264 this.region = region;
37265 this.setActiveClass(region && !this.background);
37269 setActiveClass: function(state)
37272 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37273 this.el.setStyle('position','relative');
37275 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37276 this.el.setStyle('position', 'absolute');
37281 * Returns the toolbar for this Panel if one was configured.
37282 * @return {Roo.Toolbar}
37284 getToolbar : function(){
37285 return this.toolbar;
37288 setActiveState : function(active)
37290 this.active = active;
37291 this.setActiveClass(active);
37293 if(this.fireEvent("deactivate", this) === false){
37298 this.fireEvent("activate", this);
37302 * Updates this panel's element
37303 * @param {String} content The new content
37304 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37306 setContent : function(content, loadScripts){
37307 this.el.update(content, loadScripts);
37310 ignoreResize : function(w, h){
37311 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37314 this.lastSize = {width: w, height: h};
37319 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37320 * @return {Roo.UpdateManager} The UpdateManager
37322 getUpdateManager : function(){
37323 return this.el.getUpdateManager();
37326 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37327 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
37330 url: "your-url.php",
37331 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37332 callback: yourFunction,
37333 scope: yourObject, //(optional scope)
37336 text: "Loading...",
37341 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37342 * are shorthand for <i>disableCaching</i>, <i>indicatorText</i> and <i>loadScripts</i> and are used to set their associated property on this panel UpdateManager instance.
37343 * @param {String/Object} params (optional) The parameters to pass as either a URL encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
37344 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37345 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
37346 * @return {Roo.ContentPanel} this
37349 var um = this.el.getUpdateManager();
37350 um.update.apply(um, arguments);
37356 * Set a URL to be used to load the content for this panel. When this panel is activated, the content will be loaded from that URL.
37357 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37358 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
37359 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this panel is activated. (Defaults to false)
37360 * @return {Roo.UpdateManager} The UpdateManager
37362 setUrl : function(url, params, loadOnce){
37363 if(this.refreshDelegate){
37364 this.removeListener("activate", this.refreshDelegate);
37366 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37367 this.on("activate", this.refreshDelegate);
37368 return this.el.getUpdateManager();
37371 _handleRefresh : function(url, params, loadOnce){
37372 if(!loadOnce || !this.loaded){
37373 var updater = this.el.getUpdateManager();
37374 updater.update(url, params, this._setLoaded.createDelegate(this));
37378 _setLoaded : function(){
37379 this.loaded = true;
37383 * Returns this panel's id
37386 getId : function(){
37391 * Returns this panel's element - used by regiosn to add.
37392 * @return {Roo.Element}
37394 getEl : function(){
37395 return this.wrapEl || this.el;
37400 adjustForComponents : function(width, height)
37402 //Roo.log('adjustForComponents ');
37403 if(this.resizeEl != this.el){
37404 width -= this.el.getFrameWidth('lr');
37405 height -= this.el.getFrameWidth('tb');
37408 var te = this.toolbar.getEl();
37409 te.setWidth(width);
37410 height -= te.getHeight();
37413 var te = this.footer.getEl();
37414 te.setWidth(width);
37415 height -= te.getHeight();
37419 if(this.adjustments){
37420 width += this.adjustments[0];
37421 height += this.adjustments[1];
37423 return {"width": width, "height": height};
37426 setSize : function(width, height){
37427 if(this.fitToFrame && !this.ignoreResize(width, height)){
37428 if(this.fitContainer && this.resizeEl != this.el){
37429 this.el.setSize(width, height);
37431 var size = this.adjustForComponents(width, height);
37432 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37433 this.fireEvent('resize', this, size.width, size.height);
37438 * Returns this panel's title
37441 getTitle : function(){
37443 if (typeof(this.title) != 'object') {
37448 for (var k in this.title) {
37449 if (!this.title.hasOwnProperty(k)) {
37453 if (k.indexOf('-') >= 0) {
37454 var s = k.split('-');
37455 for (var i = 0; i<s.length; i++) {
37456 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37459 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37466 * Set this panel's title
37467 * @param {String} title
37469 setTitle : function(title){
37470 this.title = title;
37472 this.region.updatePanelTitle(this, title);
37477 * Returns true is this panel was configured to be closable
37478 * @return {Boolean}
37480 isClosable : function(){
37481 return this.closable;
37484 beforeSlide : function(){
37486 this.resizeEl.clip();
37489 afterSlide : function(){
37491 this.resizeEl.unclip();
37495 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37496 * Will fail silently if the {@link #setUrl} method has not been called.
37497 * This does not activate the panel, just updates its content.
37499 refresh : function(){
37500 if(this.refreshDelegate){
37501 this.loaded = false;
37502 this.refreshDelegate();
37507 * Destroys this panel
37509 destroy : function(){
37510 this.el.removeAllListeners();
37511 var tempEl = document.createElement("span");
37512 tempEl.appendChild(this.el.dom);
37513 tempEl.innerHTML = "";
37519 * form - if the content panel contains a form - this is a reference to it.
37520 * @type {Roo.form.Form}
37524 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37525 * This contains a reference to it.
37531 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37541 * @param {Object} cfg Xtype definition of item to add.
37545 getChildContainer: function () {
37546 return this.getEl();
37551 var ret = new Roo.factory(cfg);
37556 if (cfg.xtype.match(/^Form$/)) {
37559 //if (this.footer) {
37560 // el = this.footer.container.insertSibling(false, 'before');
37562 el = this.el.createChild();
37565 this.form = new Roo.form.Form(cfg);
37568 if ( this.form.allItems.length) {
37569 this.form.render(el.dom);
37573 // should only have one of theses..
37574 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37575 // views.. should not be just added - used named prop 'view''
37577 cfg.el = this.el.appendChild(document.createElement("div"));
37580 var ret = new Roo.factory(cfg);
37582 ret.render && ret.render(false, ''); // render blank..
37592 * @class Roo.bootstrap.panel.Grid
37593 * @extends Roo.bootstrap.panel.Content
37595 * Create a new GridPanel.
37596 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37597 * @param {Object} config A the config object
37603 Roo.bootstrap.panel.Grid = function(config)
37607 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37608 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37610 config.el = this.wrapper;
37611 //this.el = this.wrapper;
37613 if (config.container) {
37614 // ctor'ed from a Border/panel.grid
37617 this.wrapper.setStyle("overflow", "hidden");
37618 this.wrapper.addClass('roo-grid-container');
37623 if(config.toolbar){
37624 var tool_el = this.wrapper.createChild();
37625 this.toolbar = Roo.factory(config.toolbar);
37627 if (config.toolbar.items) {
37628 ti = config.toolbar.items ;
37629 delete config.toolbar.items ;
37633 this.toolbar.render(tool_el);
37634 for(var i =0;i < ti.length;i++) {
37635 // Roo.log(['add child', items[i]]);
37636 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37638 this.toolbar.items = nitems;
37640 delete config.toolbar;
37643 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37644 config.grid.scrollBody = true;;
37645 config.grid.monitorWindowResize = false; // turn off autosizing
37646 config.grid.autoHeight = false;
37647 config.grid.autoWidth = false;
37649 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37651 if (config.background) {
37652 // render grid on panel activation (if panel background)
37653 this.on('activate', function(gp) {
37654 if (!gp.grid.rendered) {
37655 gp.grid.render(this.wrapper);
37656 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37661 this.grid.render(this.wrapper);
37662 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37665 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37666 // ??? needed ??? config.el = this.wrapper;
37671 // xtype created footer. - not sure if will work as we normally have to render first..
37672 if (this.footer && !this.footer.el && this.footer.xtype) {
37674 var ctr = this.grid.getView().getFooterPanel(true);
37675 this.footer.dataSource = this.grid.dataSource;
37676 this.footer = Roo.factory(this.footer, Roo);
37677 this.footer.render(ctr);
37687 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37688 getId : function(){
37689 return this.grid.id;
37693 * Returns the grid for this panel
37694 * @return {Roo.bootstrap.Table}
37696 getGrid : function(){
37700 setSize : function(width, height){
37701 if(!this.ignoreResize(width, height)){
37702 var grid = this.grid;
37703 var size = this.adjustForComponents(width, height);
37704 var gridel = grid.getGridEl();
37705 gridel.setSize(size.width, size.height);
37707 var thd = grid.getGridEl().select('thead',true).first();
37708 var tbd = grid.getGridEl().select('tbody', true).first();
37710 tbd.setSize(width, height - thd.getHeight());
37719 beforeSlide : function(){
37720 this.grid.getView().scroller.clip();
37723 afterSlide : function(){
37724 this.grid.getView().scroller.unclip();
37727 destroy : function(){
37728 this.grid.destroy();
37730 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37735 * @class Roo.bootstrap.panel.Nest
37736 * @extends Roo.bootstrap.panel.Content
37738 * Create a new Panel, that can contain a layout.Border.
37741 * @param {Roo.BorderLayout} layout The layout for this panel
37742 * @param {String/Object} config A string to set only the title or a config object
37744 Roo.bootstrap.panel.Nest = function(config)
37746 // construct with only one argument..
37747 /* FIXME - implement nicer consturctors
37748 if (layout.layout) {
37750 layout = config.layout;
37751 delete config.layout;
37753 if (layout.xtype && !layout.getEl) {
37754 // then layout needs constructing..
37755 layout = Roo.factory(layout, Roo);
37759 config.el = config.layout.getEl();
37761 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37763 config.layout.monitorWindowResize = false; // turn off autosizing
37764 this.layout = config.layout;
37765 this.layout.getEl().addClass("roo-layout-nested-layout");
37772 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37774 setSize : function(width, height){
37775 if(!this.ignoreResize(width, height)){
37776 var size = this.adjustForComponents(width, height);
37777 var el = this.layout.getEl();
37778 if (size.height < 1) {
37779 el.setWidth(size.width);
37781 el.setSize(size.width, size.height);
37783 var touch = el.dom.offsetWidth;
37784 this.layout.layout();
37785 // ie requires a double layout on the first pass
37786 if(Roo.isIE && !this.initialized){
37787 this.initialized = true;
37788 this.layout.layout();
37793 // activate all subpanels if not currently active..
37795 setActiveState : function(active){
37796 this.active = active;
37797 this.setActiveClass(active);
37800 this.fireEvent("deactivate", this);
37804 this.fireEvent("activate", this);
37805 // not sure if this should happen before or after..
37806 if (!this.layout) {
37807 return; // should not happen..
37810 for (var r in this.layout.regions) {
37811 reg = this.layout.getRegion(r);
37812 if (reg.getActivePanel()) {
37813 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37814 reg.setActivePanel(reg.getActivePanel());
37817 if (!reg.panels.length) {
37820 reg.showPanel(reg.getPanel(0));
37829 * Returns the nested BorderLayout for this panel
37830 * @return {Roo.BorderLayout}
37832 getLayout : function(){
37833 return this.layout;
37837 * Adds a xtype elements to the layout of the nested panel
37841 xtype : 'ContentPanel',
37848 xtype : 'NestedLayoutPanel',
37854 items : [ ... list of content panels or nested layout panels.. ]
37858 * @param {Object} cfg Xtype definition of item to add.
37860 addxtype : function(cfg) {
37861 return this.layout.addxtype(cfg);
37866 * Ext JS Library 1.1.1
37867 * Copyright(c) 2006-2007, Ext JS, LLC.
37869 * Originally Released Under LGPL - original licence link has changed is not relivant.
37872 * <script type="text/javascript">
37875 * @class Roo.TabPanel
37876 * @extends Roo.util.Observable
37877 * A lightweight tab container.
37881 // basic tabs 1, built from existing content
37882 var tabs = new Roo.TabPanel("tabs1");
37883 tabs.addTab("script", "View Script");
37884 tabs.addTab("markup", "View Markup");
37885 tabs.activate("script");
37887 // more advanced tabs, built from javascript
37888 var jtabs = new Roo.TabPanel("jtabs");
37889 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37891 // set up the UpdateManager
37892 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37893 var updater = tab2.getUpdateManager();
37894 updater.setDefaultUrl("ajax1.htm");
37895 tab2.on('activate', updater.refresh, updater, true);
37897 // Use setUrl for Ajax loading
37898 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37899 tab3.setUrl("ajax2.htm", null, true);
37902 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37905 jtabs.activate("jtabs-1");
37908 * Create a new TabPanel.
37909 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37910 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37912 Roo.bootstrap.panel.Tabs = function(config){
37914 * The container element for this TabPanel.
37915 * @type Roo.Element
37917 this.el = Roo.get(config.el);
37920 if(typeof config == "boolean"){
37921 this.tabPosition = config ? "bottom" : "top";
37923 Roo.apply(this, config);
37927 if(this.tabPosition == "bottom"){
37928 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37929 this.el.addClass("roo-tabs-bottom");
37931 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37932 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37933 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
37934 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37936 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37938 if(this.tabPosition != "bottom"){
37939 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37940 * @type Roo.Element
37942 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37943 this.el.addClass("roo-tabs-top");
37947 this.bodyEl.setStyle("position", "relative");
37949 this.active = null;
37950 this.activateDelegate = this.activate.createDelegate(this);
37955 * Fires when the active tab changes
37956 * @param {Roo.TabPanel} this
37957 * @param {Roo.TabPanelItem} activePanel The new active tab
37961 * @event beforetabchange
37962 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37963 * @param {Roo.TabPanel} this
37964 * @param {Object} e Set cancel to true on this object to cancel the tab change
37965 * @param {Roo.TabPanelItem} tab The tab being changed to
37967 "beforetabchange" : true
37970 Roo.EventManager.onWindowResize(this.onResize, this);
37971 this.cpad = this.el.getPadding("lr");
37972 this.hiddenCount = 0;
37975 // toolbar on the tabbar support...
37976 if (this.toolbar) {
37977 alert("no toolbar support yet");
37978 this.toolbar = false;
37980 var tcfg = this.toolbar;
37981 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
37982 this.toolbar = new Roo.Toolbar(tcfg);
37983 if (Roo.isSafari) {
37984 var tbl = tcfg.container.child('table', true);
37985 tbl.setAttribute('width', '100%');
37993 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
37996 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
37998 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38000 tabPosition : "top",
38002 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38004 currentTabWidth : 0,
38006 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38010 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38014 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38016 preferredTabWidth : 175,
38018 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38020 resizeTabs : false,
38022 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38024 monitorResize : true,
38026 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38031 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38032 * @param {String} id The id of the div to use <b>or create</b>
38033 * @param {String} text The text for the tab
38034 * @param {String} content (optional) Content to put in the TabPanelItem body
38035 * @param {Boolean} closable (optional) True to create a close icon on the tab
38036 * @return {Roo.TabPanelItem} The created TabPanelItem
38038 addTab : function(id, text, content, closable, tpl)
38040 var item = new Roo.bootstrap.panel.TabItem({
38044 closable : closable,
38047 this.addTabItem(item);
38049 item.setContent(content);
38055 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38056 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38057 * @return {Roo.TabPanelItem}
38059 getTab : function(id){
38060 return this.items[id];
38064 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38065 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38067 hideTab : function(id){
38068 var t = this.items[id];
38071 this.hiddenCount++;
38072 this.autoSizeTabs();
38077 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38078 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38080 unhideTab : function(id){
38081 var t = this.items[id];
38083 t.setHidden(false);
38084 this.hiddenCount--;
38085 this.autoSizeTabs();
38090 * Adds an existing {@link Roo.TabPanelItem}.
38091 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38093 addTabItem : function(item)
38095 this.items[item.id] = item;
38096 this.items.push(item);
38097 this.autoSizeTabs();
38098 // if(this.resizeTabs){
38099 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38100 // this.autoSizeTabs();
38102 // item.autoSize();
38107 * Removes a {@link Roo.TabPanelItem}.
38108 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38110 removeTab : function(id){
38111 var items = this.items;
38112 var tab = items[id];
38113 if(!tab) { return; }
38114 var index = items.indexOf(tab);
38115 if(this.active == tab && items.length > 1){
38116 var newTab = this.getNextAvailable(index);
38121 this.stripEl.dom.removeChild(tab.pnode.dom);
38122 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38123 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38125 items.splice(index, 1);
38126 delete this.items[tab.id];
38127 tab.fireEvent("close", tab);
38128 tab.purgeListeners();
38129 this.autoSizeTabs();
38132 getNextAvailable : function(start){
38133 var items = this.items;
38135 // look for a next tab that will slide over to
38136 // replace the one being removed
38137 while(index < items.length){
38138 var item = items[++index];
38139 if(item && !item.isHidden()){
38143 // if one isn't found select the previous tab (on the left)
38146 var item = items[--index];
38147 if(item && !item.isHidden()){
38155 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38156 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38158 disableTab : function(id){
38159 var tab = this.items[id];
38160 if(tab && this.active != tab){
38166 * Enables a {@link Roo.TabPanelItem} that is disabled.
38167 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38169 enableTab : function(id){
38170 var tab = this.items[id];
38175 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38176 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38177 * @return {Roo.TabPanelItem} The TabPanelItem.
38179 activate : function(id)
38181 var tab = this.items[id];
38185 if(tab == this.active || tab.disabled){
38189 this.fireEvent("beforetabchange", this, e, tab);
38190 if(e.cancel !== true && !tab.disabled){
38192 this.active.hide();
38194 this.active = this.items[id];
38195 this.active.show();
38196 this.fireEvent("tabchange", this, this.active);
38202 * Gets the active {@link Roo.TabPanelItem}.
38203 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38205 getActiveTab : function(){
38206 return this.active;
38210 * Updates the tab body element to fit the height of the container element
38211 * for overflow scrolling
38212 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38214 syncHeight : function(targetHeight){
38215 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38216 var bm = this.bodyEl.getMargins();
38217 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38218 this.bodyEl.setHeight(newHeight);
38222 onResize : function(){
38223 if(this.monitorResize){
38224 this.autoSizeTabs();
38229 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38231 beginUpdate : function(){
38232 this.updating = true;
38236 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38238 endUpdate : function(){
38239 this.updating = false;
38240 this.autoSizeTabs();
38244 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38246 autoSizeTabs : function()
38248 var count = this.items.length;
38249 var vcount = count - this.hiddenCount;
38252 this.stripEl.hide();
38254 this.stripEl.show();
38257 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38262 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38263 var availWidth = Math.floor(w / vcount);
38264 var b = this.stripBody;
38265 if(b.getWidth() > w){
38266 var tabs = this.items;
38267 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38268 if(availWidth < this.minTabWidth){
38269 /*if(!this.sleft){ // incomplete scrolling code
38270 this.createScrollButtons();
38273 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38276 if(this.currentTabWidth < this.preferredTabWidth){
38277 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38283 * Returns the number of tabs in this TabPanel.
38286 getCount : function(){
38287 return this.items.length;
38291 * Resizes all the tabs to the passed width
38292 * @param {Number} The new width
38294 setTabWidth : function(width){
38295 this.currentTabWidth = width;
38296 for(var i = 0, len = this.items.length; i < len; i++) {
38297 if(!this.items[i].isHidden()) {
38298 this.items[i].setWidth(width);
38304 * Destroys this TabPanel
38305 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38307 destroy : function(removeEl){
38308 Roo.EventManager.removeResizeListener(this.onResize, this);
38309 for(var i = 0, len = this.items.length; i < len; i++){
38310 this.items[i].purgeListeners();
38312 if(removeEl === true){
38313 this.el.update("");
38318 createStrip : function(container)
38320 var strip = document.createElement("nav");
38321 strip.className = Roo.bootstrap.version == 4 ?
38322 "navbar-light bg-light" :
38323 "navbar navbar-default"; //"x-tabs-wrap";
38324 container.appendChild(strip);
38328 createStripList : function(strip)
38330 // div wrapper for retard IE
38331 // returns the "tr" element.
38332 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38333 //'<div class="x-tabs-strip-wrap">'+
38334 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38335 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38336 return strip.firstChild; //.firstChild.firstChild.firstChild;
38338 createBody : function(container)
38340 var body = document.createElement("div");
38341 Roo.id(body, "tab-body");
38342 //Roo.fly(body).addClass("x-tabs-body");
38343 Roo.fly(body).addClass("tab-content");
38344 container.appendChild(body);
38347 createItemBody :function(bodyEl, id){
38348 var body = Roo.getDom(id);
38350 body = document.createElement("div");
38353 //Roo.fly(body).addClass("x-tabs-item-body");
38354 Roo.fly(body).addClass("tab-pane");
38355 bodyEl.insertBefore(body, bodyEl.firstChild);
38359 createStripElements : function(stripEl, text, closable, tpl)
38361 var td = document.createElement("li"); // was td..
38362 td.className = 'nav-item';
38364 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38367 stripEl.appendChild(td);
38369 td.className = "x-tabs-closable";
38370 if(!this.closeTpl){
38371 this.closeTpl = new Roo.Template(
38372 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38373 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38374 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38377 var el = this.closeTpl.overwrite(td, {"text": text});
38378 var close = el.getElementsByTagName("div")[0];
38379 var inner = el.getElementsByTagName("em")[0];
38380 return {"el": el, "close": close, "inner": inner};
38383 // not sure what this is..
38384 // if(!this.tabTpl){
38385 //this.tabTpl = new Roo.Template(
38386 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38387 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38389 // this.tabTpl = new Roo.Template(
38390 // '<a href="#">' +
38391 // '<span unselectable="on"' +
38392 // (this.disableTooltips ? '' : ' title="{text}"') +
38393 // ' >{text}</span></a>'
38399 var template = tpl || this.tabTpl || false;
38402 template = new Roo.Template(
38403 Roo.bootstrap.version == 4 ?
38405 '<a class="nav-link" href="#" unselectable="on"' +
38406 (this.disableTooltips ? '' : ' title="{text}"') +
38409 '<a class="nav-link" href="#">' +
38410 '<span unselectable="on"' +
38411 (this.disableTooltips ? '' : ' title="{text}"') +
38412 ' >{text}</span></a>'
38417 switch (typeof(template)) {
38421 template = new Roo.Template(template);
38427 var el = template.overwrite(td, {"text": text});
38429 var inner = el.getElementsByTagName("span")[0];
38431 return {"el": el, "inner": inner};
38439 * @class Roo.TabPanelItem
38440 * @extends Roo.util.Observable
38441 * Represents an individual item (tab plus body) in a TabPanel.
38442 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38443 * @param {String} id The id of this TabPanelItem
38444 * @param {String} text The text for the tab of this TabPanelItem
38445 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38447 Roo.bootstrap.panel.TabItem = function(config){
38449 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38450 * @type Roo.TabPanel
38452 this.tabPanel = config.panel;
38454 * The id for this TabPanelItem
38457 this.id = config.id;
38459 this.disabled = false;
38461 this.text = config.text;
38463 this.loaded = false;
38464 this.closable = config.closable;
38467 * The body element for this TabPanelItem.
38468 * @type Roo.Element
38470 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38471 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38472 this.bodyEl.setStyle("display", "block");
38473 this.bodyEl.setStyle("zoom", "1");
38474 //this.hideAction();
38476 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38478 this.el = Roo.get(els.el);
38479 this.inner = Roo.get(els.inner, true);
38480 this.textEl = Roo.bootstrap.version == 4 ?
38481 this.el : Roo.get(this.el.dom.firstChild, true);
38483 this.linode = Roo.get(els.el.parentNode, true);
38484 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38487 // this.el.on("mousedown", this.onTabMouseDown, this);
38488 this.el.on("click", this.onTabClick, this);
38490 if(config.closable){
38491 var c = Roo.get(els.close, true);
38492 c.dom.title = this.closeText;
38493 c.addClassOnOver("close-over");
38494 c.on("click", this.closeClick, this);
38500 * Fires when this tab becomes the active tab.
38501 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38502 * @param {Roo.TabPanelItem} this
38506 * @event beforeclose
38507 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38508 * @param {Roo.TabPanelItem} this
38509 * @param {Object} e Set cancel to true on this object to cancel the close.
38511 "beforeclose": true,
38514 * Fires when this tab is closed.
38515 * @param {Roo.TabPanelItem} this
38519 * @event deactivate
38520 * Fires when this tab is no longer the active tab.
38521 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38522 * @param {Roo.TabPanelItem} this
38524 "deactivate" : true
38526 this.hidden = false;
38528 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38531 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38533 purgeListeners : function(){
38534 Roo.util.Observable.prototype.purgeListeners.call(this);
38535 this.el.removeAllListeners();
38538 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38541 this.status_node.addClass("active");
38544 this.tabPanel.stripWrap.repaint();
38546 this.fireEvent("activate", this.tabPanel, this);
38550 * Returns true if this tab is the active tab.
38551 * @return {Boolean}
38553 isActive : function(){
38554 return this.tabPanel.getActiveTab() == this;
38558 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38561 this.status_node.removeClass("active");
38563 this.fireEvent("deactivate", this.tabPanel, this);
38566 hideAction : function(){
38567 this.bodyEl.hide();
38568 this.bodyEl.setStyle("position", "absolute");
38569 this.bodyEl.setLeft("-20000px");
38570 this.bodyEl.setTop("-20000px");
38573 showAction : function(){
38574 this.bodyEl.setStyle("position", "relative");
38575 this.bodyEl.setTop("");
38576 this.bodyEl.setLeft("");
38577 this.bodyEl.show();
38581 * Set the tooltip for the tab.
38582 * @param {String} tooltip The tab's tooltip
38584 setTooltip : function(text){
38585 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38586 this.textEl.dom.qtip = text;
38587 this.textEl.dom.removeAttribute('title');
38589 this.textEl.dom.title = text;
38593 onTabClick : function(e){
38594 e.preventDefault();
38595 this.tabPanel.activate(this.id);
38598 onTabMouseDown : function(e){
38599 e.preventDefault();
38600 this.tabPanel.activate(this.id);
38603 getWidth : function(){
38604 return this.inner.getWidth();
38607 setWidth : function(width){
38608 var iwidth = width - this.linode.getPadding("lr");
38609 this.inner.setWidth(iwidth);
38610 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38611 this.linode.setWidth(width);
38615 * Show or hide the tab
38616 * @param {Boolean} hidden True to hide or false to show.
38618 setHidden : function(hidden){
38619 this.hidden = hidden;
38620 this.linode.setStyle("display", hidden ? "none" : "");
38624 * Returns true if this tab is "hidden"
38625 * @return {Boolean}
38627 isHidden : function(){
38628 return this.hidden;
38632 * Returns the text for this tab
38635 getText : function(){
38639 autoSize : function(){
38640 //this.el.beginMeasure();
38641 this.textEl.setWidth(1);
38643 * #2804 [new] Tabs in Roojs
38644 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38646 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38647 //this.el.endMeasure();
38651 * Sets the text for the tab (Note: this also sets the tooltip text)
38652 * @param {String} text The tab's text and tooltip
38654 setText : function(text){
38656 this.textEl.update(text);
38657 this.setTooltip(text);
38658 //if(!this.tabPanel.resizeTabs){
38659 // this.autoSize();
38663 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38665 activate : function(){
38666 this.tabPanel.activate(this.id);
38670 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38672 disable : function(){
38673 if(this.tabPanel.active != this){
38674 this.disabled = true;
38675 this.status_node.addClass("disabled");
38680 * Enables this TabPanelItem if it was previously disabled.
38682 enable : function(){
38683 this.disabled = false;
38684 this.status_node.removeClass("disabled");
38688 * Sets the content for this TabPanelItem.
38689 * @param {String} content The content
38690 * @param {Boolean} loadScripts true to look for and load scripts
38692 setContent : function(content, loadScripts){
38693 this.bodyEl.update(content, loadScripts);
38697 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38698 * @return {Roo.UpdateManager} The UpdateManager
38700 getUpdateManager : function(){
38701 return this.bodyEl.getUpdateManager();
38705 * Set a URL to be used to load the content for this TabPanelItem.
38706 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38707 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
38708 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
38709 * @return {Roo.UpdateManager} The UpdateManager
38711 setUrl : function(url, params, loadOnce){
38712 if(this.refreshDelegate){
38713 this.un('activate', this.refreshDelegate);
38715 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38716 this.on("activate", this.refreshDelegate);
38717 return this.bodyEl.getUpdateManager();
38721 _handleRefresh : function(url, params, loadOnce){
38722 if(!loadOnce || !this.loaded){
38723 var updater = this.bodyEl.getUpdateManager();
38724 updater.update(url, params, this._setLoaded.createDelegate(this));
38729 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38730 * Will fail silently if the setUrl method has not been called.
38731 * This does not activate the panel, just updates its content.
38733 refresh : function(){
38734 if(this.refreshDelegate){
38735 this.loaded = false;
38736 this.refreshDelegate();
38741 _setLoaded : function(){
38742 this.loaded = true;
38746 closeClick : function(e){
38749 this.fireEvent("beforeclose", this, o);
38750 if(o.cancel !== true){
38751 this.tabPanel.removeTab(this.id);
38755 * The text displayed in the tooltip for the close icon.
38758 closeText : "Close this tab"
38761 * This script refer to:
38762 * Title: International Telephone Input
38763 * Author: Jack O'Connor
38764 * Code version: v12.1.12
38765 * Availability: https://github.com/jackocnr/intl-tel-input.git
38768 Roo.bootstrap.PhoneInputData = function() {
38771 "Afghanistan (افغانستان)",
38776 "Albania (Shqipëri)",
38781 "Algeria (الجزائر)",
38806 "Antigua and Barbuda",
38816 "Armenia (Հայաստան)",
38832 "Austria (Österreich)",
38837 "Azerbaijan (Azərbaycan)",
38847 "Bahrain (البحرين)",
38852 "Bangladesh (বাংলাদেশ)",
38862 "Belarus (Беларусь)",
38867 "Belgium (België)",
38897 "Bosnia and Herzegovina (Босна и Херцеговина)",
38912 "British Indian Ocean Territory",
38917 "British Virgin Islands",
38927 "Bulgaria (България)",
38937 "Burundi (Uburundi)",
38942 "Cambodia (កម្ពុជា)",
38947 "Cameroon (Cameroun)",
38956 ["204", "226", "236", "249", "250", "289", "306", "343", "365", "387", "403", "416", "418", "431", "437", "438", "450", "506", "514", "519", "548", "579", "581", "587", "604", "613", "639", "647", "672", "705", "709", "742", "778", "780", "782", "807", "819", "825", "867", "873", "902", "905"]
38959 "Cape Verde (Kabu Verdi)",
38964 "Caribbean Netherlands",
38975 "Central African Republic (République centrafricaine)",
38995 "Christmas Island",
39001 "Cocos (Keeling) Islands",
39012 "Comoros (جزر القمر)",
39017 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39022 "Congo (Republic) (Congo-Brazzaville)",
39042 "Croatia (Hrvatska)",
39063 "Czech Republic (Česká republika)",
39068 "Denmark (Danmark)",
39083 "Dominican Republic (República Dominicana)",
39087 ["809", "829", "849"]
39105 "Equatorial Guinea (Guinea Ecuatorial)",
39125 "Falkland Islands (Islas Malvinas)",
39130 "Faroe Islands (Føroyar)",
39151 "French Guiana (Guyane française)",
39156 "French Polynesia (Polynésie française)",
39171 "Georgia (საქართველო)",
39176 "Germany (Deutschland)",
39196 "Greenland (Kalaallit Nunaat)",
39233 "Guinea-Bissau (Guiné Bissau)",
39258 "Hungary (Magyarország)",
39263 "Iceland (Ísland)",
39283 "Iraq (العراق)",
39299 "Israel (ישראל)",
39326 "Jordan (الأردن)",
39331 "Kazakhstan (Казахстан)",
39352 "Kuwait (الكويت)",
39357 "Kyrgyzstan (Кыргызстан)",
39367 "Latvia (Latvija)",
39372 "Lebanon (لبنان)",
39387 "Libya (ليبيا)",
39397 "Lithuania (Lietuva)",
39412 "Macedonia (FYROM) (Македонија)",
39417 "Madagascar (Madagasikara)",
39447 "Marshall Islands",
39457 "Mauritania (موريتانيا)",
39462 "Mauritius (Moris)",
39483 "Moldova (Republica Moldova)",
39493 "Mongolia (Монгол)",
39498 "Montenegro (Crna Gora)",
39508 "Morocco (المغرب)",
39514 "Mozambique (Moçambique)",
39519 "Myanmar (Burma) (မြန်မာ)",
39524 "Namibia (Namibië)",
39539 "Netherlands (Nederland)",
39544 "New Caledonia (Nouvelle-Calédonie)",
39579 "North Korea (조선 민주주의 인민 공화국)",
39584 "Northern Mariana Islands",
39600 "Pakistan (پاکستان)",
39610 "Palestine (فلسطين)",
39620 "Papua New Guinea",
39662 "Réunion (La Réunion)",
39668 "Romania (România)",
39684 "Saint Barthélemy",
39695 "Saint Kitts and Nevis",
39705 "Saint Martin (Saint-Martin (partie française))",
39711 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39716 "Saint Vincent and the Grenadines",
39731 "São Tomé and Príncipe (São Tomé e Príncipe)",
39736 "Saudi Arabia (المملكة العربية السعودية)",
39741 "Senegal (Sénégal)",
39771 "Slovakia (Slovensko)",
39776 "Slovenia (Slovenija)",
39786 "Somalia (Soomaaliya)",
39796 "South Korea (대한민국)",
39801 "South Sudan (جنوب السودان)",
39811 "Sri Lanka (ශ්රී ලංකාව)",
39816 "Sudan (السودان)",
39826 "Svalbard and Jan Mayen",
39837 "Sweden (Sverige)",
39842 "Switzerland (Schweiz)",
39847 "Syria (سوريا)",
39892 "Trinidad and Tobago",
39897 "Tunisia (تونس)",
39902 "Turkey (Türkiye)",
39912 "Turks and Caicos Islands",
39922 "U.S. Virgin Islands",
39932 "Ukraine (Україна)",
39937 "United Arab Emirates (الإمارات العربية المتحدة)",
39959 "Uzbekistan (Oʻzbekiston)",
39969 "Vatican City (Città del Vaticano)",
39980 "Vietnam (Việt Nam)",
39985 "Wallis and Futuna (Wallis-et-Futuna)",
39990 "Western Sahara (الصحراء الغربية)",
39996 "Yemen (اليمن)",
40020 * This script refer to:
40021 * Title: International Telephone Input
40022 * Author: Jack O'Connor
40023 * Code version: v12.1.12
40024 * Availability: https://github.com/jackocnr/intl-tel-input.git
40028 * @class Roo.bootstrap.PhoneInput
40029 * @extends Roo.bootstrap.TriggerField
40030 * An input with International dial-code selection
40032 * @cfg {String} defaultDialCode default '+852'
40033 * @cfg {Array} preferedCountries default []
40036 * Create a new PhoneInput.
40037 * @param {Object} config Configuration options
40040 Roo.bootstrap.PhoneInput = function(config) {
40041 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40044 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40046 listWidth: undefined,
40048 selectedClass: 'active',
40050 invalidClass : "has-warning",
40052 validClass: 'has-success',
40054 allowed: '0123456789',
40059 * @cfg {String} defaultDialCode The default dial code when initializing the input
40061 defaultDialCode: '+852',
40064 * @cfg {Array} preferedCountries A list of iso2 in array (e.g. ['hk','us']). Those related countries will show at the top of the input's choices
40066 preferedCountries: false,
40068 getAutoCreate : function()
40070 var data = Roo.bootstrap.PhoneInputData();
40071 var align = this.labelAlign || this.parentLabelAlign();
40074 this.allCountries = [];
40075 this.dialCodeMapping = [];
40077 for (var i = 0; i < data.length; i++) {
40079 this.allCountries[i] = {
40083 priority: c[3] || 0,
40084 areaCodes: c[4] || null
40086 this.dialCodeMapping[c[2]] = {
40089 priority: c[3] || 0,
40090 areaCodes: c[4] || null
40102 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40103 maxlength: this.max_length,
40104 cls : 'form-control tel-input',
40105 autocomplete: 'new-password'
40108 var hiddenInput = {
40111 cls: 'hidden-tel-input'
40115 hiddenInput.name = this.name;
40118 if (this.disabled) {
40119 input.disabled = true;
40122 var flag_container = {
40139 cls: this.hasFeedback ? 'has-feedback' : '',
40145 cls: 'dial-code-holder',
40152 cls: 'roo-select2-container input-group',
40159 if (this.fieldLabel.length) {
40162 tooltip: 'This field is required'
40168 cls: 'control-label',
40174 html: this.fieldLabel
40177 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40183 if(this.indicatorpos == 'right') {
40184 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40191 if(align == 'left') {
40199 if(this.labelWidth > 12){
40200 label.style = "width: " + this.labelWidth + 'px';
40202 if(this.labelWidth < 13 && this.labelmd == 0){
40203 this.labelmd = this.labelWidth;
40205 if(this.labellg > 0){
40206 label.cls += ' col-lg-' + this.labellg;
40207 input.cls += ' col-lg-' + (12 - this.labellg);
40209 if(this.labelmd > 0){
40210 label.cls += ' col-md-' + this.labelmd;
40211 container.cls += ' col-md-' + (12 - this.labelmd);
40213 if(this.labelsm > 0){
40214 label.cls += ' col-sm-' + this.labelsm;
40215 container.cls += ' col-sm-' + (12 - this.labelsm);
40217 if(this.labelxs > 0){
40218 label.cls += ' col-xs-' + this.labelxs;
40219 container.cls += ' col-xs-' + (12 - this.labelxs);
40229 var settings = this;
40231 ['xs','sm','md','lg'].map(function(size){
40232 if (settings[size]) {
40233 cfg.cls += ' col-' + size + '-' + settings[size];
40237 this.store = new Roo.data.Store({
40238 proxy : new Roo.data.MemoryProxy({}),
40239 reader : new Roo.data.JsonReader({
40250 'name' : 'dialCode',
40254 'name' : 'priority',
40258 'name' : 'areaCodes',
40265 if(!this.preferedCountries) {
40266 this.preferedCountries = [
40273 var p = this.preferedCountries.reverse();
40276 for (var i = 0; i < p.length; i++) {
40277 for (var j = 0; j < this.allCountries.length; j++) {
40278 if(this.allCountries[j].iso2 == p[i]) {
40279 var t = this.allCountries[j];
40280 this.allCountries.splice(j,1);
40281 this.allCountries.unshift(t);
40287 this.store.proxy.data = {
40289 data: this.allCountries
40295 initEvents : function()
40298 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40300 this.indicator = this.indicatorEl();
40301 this.flag = this.flagEl();
40302 this.dialCodeHolder = this.dialCodeHolderEl();
40304 this.trigger = this.el.select('div.flag-box',true).first();
40305 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40310 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40311 _this.list.setWidth(lw);
40314 this.list.on('mouseover', this.onViewOver, this);
40315 this.list.on('mousemove', this.onViewMove, this);
40316 this.inputEl().on("keyup", this.onKeyUp, this);
40317 this.inputEl().on("keypress", this.onKeyPress, this);
40319 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40321 this.view = new Roo.View(this.list, this.tpl, {
40322 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40325 this.view.on('click', this.onViewClick, this);
40326 this.setValue(this.defaultDialCode);
40329 onTriggerClick : function(e)
40331 Roo.log('trigger click');
40336 if(this.isExpanded()){
40338 this.hasFocus = false;
40340 this.store.load({});
40341 this.hasFocus = true;
40346 isExpanded : function()
40348 return this.list.isVisible();
40351 collapse : function()
40353 if(!this.isExpanded()){
40357 Roo.get(document).un('mousedown', this.collapseIf, this);
40358 Roo.get(document).un('mousewheel', this.collapseIf, this);
40359 this.fireEvent('collapse', this);
40363 expand : function()
40367 if(this.isExpanded() || !this.hasFocus){
40371 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40372 this.list.setWidth(lw);
40375 this.restrictHeight();
40377 Roo.get(document).on('mousedown', this.collapseIf, this);
40378 Roo.get(document).on('mousewheel', this.collapseIf, this);
40380 this.fireEvent('expand', this);
40383 restrictHeight : function()
40385 this.list.alignTo(this.inputEl(), this.listAlign);
40386 this.list.alignTo(this.inputEl(), this.listAlign);
40389 onViewOver : function(e, t)
40391 if(this.inKeyMode){
40394 var item = this.view.findItemFromChild(t);
40397 var index = this.view.indexOf(item);
40398 this.select(index, false);
40403 onViewClick : function(view, doFocus, el, e)
40405 var index = this.view.getSelectedIndexes()[0];
40407 var r = this.store.getAt(index);
40410 this.onSelect(r, index);
40412 if(doFocus !== false && !this.blockFocus){
40413 this.inputEl().focus();
40417 onViewMove : function(e, t)
40419 this.inKeyMode = false;
40422 select : function(index, scrollIntoView)
40424 this.selectedIndex = index;
40425 this.view.select(index);
40426 if(scrollIntoView !== false){
40427 var el = this.view.getNode(index);
40429 this.list.scrollChildIntoView(el, false);
40434 createList : function()
40436 this.list = Roo.get(document.body).createChild({
40438 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40439 style: 'display:none'
40442 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40445 collapseIf : function(e)
40447 var in_combo = e.within(this.el);
40448 var in_list = e.within(this.list);
40449 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40451 if (in_combo || in_list || is_list) {
40457 onSelect : function(record, index)
40459 if(this.fireEvent('beforeselect', this, record, index) !== false){
40461 this.setFlagClass(record.data.iso2);
40462 this.setDialCode(record.data.dialCode);
40463 this.hasFocus = false;
40465 this.fireEvent('select', this, record, index);
40469 flagEl : function()
40471 var flag = this.el.select('div.flag',true).first();
40478 dialCodeHolderEl : function()
40480 var d = this.el.select('input.dial-code-holder',true).first();
40487 setDialCode : function(v)
40489 this.dialCodeHolder.dom.value = '+'+v;
40492 setFlagClass : function(n)
40494 this.flag.dom.className = 'flag '+n;
40497 getValue : function()
40499 var v = this.inputEl().getValue();
40500 if(this.dialCodeHolder) {
40501 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40506 setValue : function(v)
40508 var d = this.getDialCode(v);
40510 //invalid dial code
40511 if(v.length == 0 || !d || d.length == 0) {
40513 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40514 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40520 this.setFlagClass(this.dialCodeMapping[d].iso2);
40521 this.setDialCode(d);
40522 this.inputEl().dom.value = v.replace('+'+d,'');
40523 this.hiddenEl().dom.value = this.getValue();
40528 getDialCode : function(v)
40532 if (v.length == 0) {
40533 return this.dialCodeHolder.dom.value;
40537 if (v.charAt(0) != "+") {
40540 var numericChars = "";
40541 for (var i = 1; i < v.length; i++) {
40542 var c = v.charAt(i);
40545 if (this.dialCodeMapping[numericChars]) {
40546 dialCode = v.substr(1, i);
40548 if (numericChars.length == 4) {
40558 this.setValue(this.defaultDialCode);
40562 hiddenEl : function()
40564 return this.el.select('input.hidden-tel-input',true).first();
40567 // after setting val
40568 onKeyUp : function(e){
40569 this.setValue(this.getValue());
40572 onKeyPress : function(e){
40573 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40580 * @class Roo.bootstrap.MoneyField
40581 * @extends Roo.bootstrap.ComboBox
40582 * Bootstrap MoneyField class
40585 * Create a new MoneyField.
40586 * @param {Object} config Configuration options
40589 Roo.bootstrap.MoneyField = function(config) {
40591 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40595 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40598 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40600 allowDecimals : true,
40602 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40604 decimalSeparator : ".",
40606 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40608 decimalPrecision : 0,
40610 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40612 allowNegative : true,
40614 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40618 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40620 minValue : Number.NEGATIVE_INFINITY,
40622 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40624 maxValue : Number.MAX_VALUE,
40626 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40628 minText : "The minimum value for this field is {0}",
40630 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40632 maxText : "The maximum value for this field is {0}",
40634 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40635 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40637 nanText : "{0} is not a valid number",
40639 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40643 * @cfg {String} defaults currency of the MoneyField
40644 * value should be in lkey
40646 defaultCurrency : false,
40648 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40650 thousandsDelimiter : false,
40652 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40663 getAutoCreate : function()
40665 var align = this.labelAlign || this.parentLabelAlign();
40677 cls : 'form-control roo-money-amount-input',
40678 autocomplete: 'new-password'
40681 var hiddenInput = {
40685 cls: 'hidden-number-input'
40688 if(this.max_length) {
40689 input.maxlength = this.max_length;
40693 hiddenInput.name = this.name;
40696 if (this.disabled) {
40697 input.disabled = true;
40700 var clg = 12 - this.inputlg;
40701 var cmd = 12 - this.inputmd;
40702 var csm = 12 - this.inputsm;
40703 var cxs = 12 - this.inputxs;
40707 cls : 'row roo-money-field',
40711 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40715 cls: 'roo-select2-container input-group',
40719 cls : 'form-control roo-money-currency-input',
40720 autocomplete: 'new-password',
40722 name : this.currencyName
40726 cls : 'input-group-addon',
40740 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40744 cls: this.hasFeedback ? 'has-feedback' : '',
40755 if (this.fieldLabel.length) {
40758 tooltip: 'This field is required'
40764 cls: 'control-label',
40770 html: this.fieldLabel
40773 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40779 if(this.indicatorpos == 'right') {
40780 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40787 if(align == 'left') {
40795 if(this.labelWidth > 12){
40796 label.style = "width: " + this.labelWidth + 'px';
40798 if(this.labelWidth < 13 && this.labelmd == 0){
40799 this.labelmd = this.labelWidth;
40801 if(this.labellg > 0){
40802 label.cls += ' col-lg-' + this.labellg;
40803 input.cls += ' col-lg-' + (12 - this.labellg);
40805 if(this.labelmd > 0){
40806 label.cls += ' col-md-' + this.labelmd;
40807 container.cls += ' col-md-' + (12 - this.labelmd);
40809 if(this.labelsm > 0){
40810 label.cls += ' col-sm-' + this.labelsm;
40811 container.cls += ' col-sm-' + (12 - this.labelsm);
40813 if(this.labelxs > 0){
40814 label.cls += ' col-xs-' + this.labelxs;
40815 container.cls += ' col-xs-' + (12 - this.labelxs);
40826 var settings = this;
40828 ['xs','sm','md','lg'].map(function(size){
40829 if (settings[size]) {
40830 cfg.cls += ' col-' + size + '-' + settings[size];
40837 initEvents : function()
40839 this.indicator = this.indicatorEl();
40841 this.initCurrencyEvent();
40843 this.initNumberEvent();
40846 initCurrencyEvent : function()
40849 throw "can not find store for combo";
40852 this.store = Roo.factory(this.store, Roo.data);
40853 this.store.parent = this;
40857 this.triggerEl = this.el.select('.input-group-addon', true).first();
40859 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40864 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40865 _this.list.setWidth(lw);
40868 this.list.on('mouseover', this.onViewOver, this);
40869 this.list.on('mousemove', this.onViewMove, this);
40870 this.list.on('scroll', this.onViewScroll, this);
40873 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40876 this.view = new Roo.View(this.list, this.tpl, {
40877 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40880 this.view.on('click', this.onViewClick, this);
40882 this.store.on('beforeload', this.onBeforeLoad, this);
40883 this.store.on('load', this.onLoad, this);
40884 this.store.on('loadexception', this.onLoadException, this);
40886 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40887 "up" : function(e){
40888 this.inKeyMode = true;
40892 "down" : function(e){
40893 if(!this.isExpanded()){
40894 this.onTriggerClick();
40896 this.inKeyMode = true;
40901 "enter" : function(e){
40904 if(this.fireEvent("specialkey", this, e)){
40905 this.onViewClick(false);
40911 "esc" : function(e){
40915 "tab" : function(e){
40918 if(this.fireEvent("specialkey", this, e)){
40919 this.onViewClick(false);
40927 doRelay : function(foo, bar, hname){
40928 if(hname == 'down' || this.scope.isExpanded()){
40929 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40937 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40941 initNumberEvent : function(e)
40943 this.inputEl().on("keydown" , this.fireKey, this);
40944 this.inputEl().on("focus", this.onFocus, this);
40945 this.inputEl().on("blur", this.onBlur, this);
40947 this.inputEl().relayEvent('keyup', this);
40949 if(this.indicator){
40950 this.indicator.addClass('invisible');
40953 this.originalValue = this.getValue();
40955 if(this.validationEvent == 'keyup'){
40956 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40957 this.inputEl().on('keyup', this.filterValidation, this);
40959 else if(this.validationEvent !== false){
40960 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40963 if(this.selectOnFocus){
40964 this.on("focus", this.preFocus, this);
40967 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40968 this.inputEl().on("keypress", this.filterKeys, this);
40970 this.inputEl().relayEvent('keypress', this);
40973 var allowed = "0123456789";
40975 if(this.allowDecimals){
40976 allowed += this.decimalSeparator;
40979 if(this.allowNegative){
40983 if(this.thousandsDelimiter) {
40987 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40989 var keyPress = function(e){
40991 var k = e.getKey();
40993 var c = e.getCharCode();
40996 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
40997 allowed.indexOf(String.fromCharCode(c)) === -1
41003 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41007 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41012 this.inputEl().on("keypress", keyPress, this);
41016 onTriggerClick : function(e)
41023 this.loadNext = false;
41025 if(this.isExpanded()){
41030 this.hasFocus = true;
41032 if(this.triggerAction == 'all') {
41033 this.doQuery(this.allQuery, true);
41037 this.doQuery(this.getRawValue());
41040 getCurrency : function()
41042 var v = this.currencyEl().getValue();
41047 restrictHeight : function()
41049 this.list.alignTo(this.currencyEl(), this.listAlign);
41050 this.list.alignTo(this.currencyEl(), this.listAlign);
41053 onViewClick : function(view, doFocus, el, e)
41055 var index = this.view.getSelectedIndexes()[0];
41057 var r = this.store.getAt(index);
41060 this.onSelect(r, index);
41064 onSelect : function(record, index){
41066 if(this.fireEvent('beforeselect', this, record, index) !== false){
41068 this.setFromCurrencyData(index > -1 ? record.data : false);
41072 this.fireEvent('select', this, record, index);
41076 setFromCurrencyData : function(o)
41080 this.lastCurrency = o;
41082 if (this.currencyField) {
41083 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41085 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41088 this.lastSelectionText = currency;
41090 //setting default currency
41091 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41092 this.setCurrency(this.defaultCurrency);
41096 this.setCurrency(currency);
41099 setFromData : function(o)
41103 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41105 this.setFromCurrencyData(c);
41110 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41112 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41115 this.setValue(value);
41119 setCurrency : function(v)
41121 this.currencyValue = v;
41124 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41129 setValue : function(v)
41131 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41137 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41139 this.inputEl().dom.value = (v == '') ? '' :
41140 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41142 if(!this.allowZero && v === '0') {
41143 this.hiddenEl().dom.value = '';
41144 this.inputEl().dom.value = '';
41151 getRawValue : function()
41153 var v = this.inputEl().getValue();
41158 getValue : function()
41160 return this.fixPrecision(this.parseValue(this.getRawValue()));
41163 parseValue : function(value)
41165 if(this.thousandsDelimiter) {
41167 r = new RegExp(",", "g");
41168 value = value.replace(r, "");
41171 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41172 return isNaN(value) ? '' : value;
41176 fixPrecision : function(value)
41178 if(this.thousandsDelimiter) {
41180 r = new RegExp(",", "g");
41181 value = value.replace(r, "");
41184 var nan = isNaN(value);
41186 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41187 return nan ? '' : value;
41189 return parseFloat(value).toFixed(this.decimalPrecision);
41192 decimalPrecisionFcn : function(v)
41194 return Math.floor(v);
41197 validateValue : function(value)
41199 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41203 var num = this.parseValue(value);
41206 this.markInvalid(String.format(this.nanText, value));
41210 if(num < this.minValue){
41211 this.markInvalid(String.format(this.minText, this.minValue));
41215 if(num > this.maxValue){
41216 this.markInvalid(String.format(this.maxText, this.maxValue));
41223 validate : function()
41225 if(this.disabled || this.allowBlank){
41230 var currency = this.getCurrency();
41232 if(this.validateValue(this.getRawValue()) && currency.length){
41237 this.markInvalid();
41241 getName: function()
41246 beforeBlur : function()
41252 var v = this.parseValue(this.getRawValue());
41259 onBlur : function()
41263 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41264 //this.el.removeClass(this.focusClass);
41267 this.hasFocus = false;
41269 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41273 var v = this.getValue();
41275 if(String(v) !== String(this.startValue)){
41276 this.fireEvent('change', this, v, this.startValue);
41279 this.fireEvent("blur", this);
41282 inputEl : function()
41284 return this.el.select('.roo-money-amount-input', true).first();
41287 currencyEl : function()
41289 return this.el.select('.roo-money-currency-input', true).first();
41292 hiddenEl : function()
41294 return this.el.select('input.hidden-number-input',true).first();