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','d-none']);
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass(['hidden','d-none']);
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);
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.footerEl.hide();
3331 dlg.footerEl.show();
3332 for(var k in buttons){
3333 if(typeof buttons[k] != "function"){
3336 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3337 width += buttons[k].el.getWidth()+15;
3347 var handleEsc = function(d, k, e){
3348 if(opt && opt.closable !== false){
3358 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3359 * @return {Roo.BasicDialog} The BasicDialog element
3361 getDialog : function(){
3363 dlg = new Roo.bootstrap.Modal( {
3366 //constraintoviewport:false,
3368 //collapsible : false,
3373 //buttonAlign:"center",
3374 closeClick : function(){
3375 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3378 handleButton("cancel");
3383 dlg.on("hide", handleHide);
3385 //dlg.addKeyListener(27, handleEsc);
3387 this.buttons = buttons;
3388 var bt = this.buttonText;
3389 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3390 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3391 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3392 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3394 bodyEl = dlg.bodyEl.createChild({
3396 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3397 '<textarea class="roo-mb-textarea"></textarea>' +
3398 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3400 msgEl = bodyEl.dom.firstChild;
3401 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3402 textboxEl.enableDisplayMode();
3403 textboxEl.addKeyListener([10,13], function(){
3404 if(dlg.isVisible() && opt && opt.buttons){
3407 }else if(opt.buttons.yes){
3408 handleButton("yes");
3412 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3413 textareaEl.enableDisplayMode();
3414 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3415 progressEl.enableDisplayMode();
3417 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3418 var pf = progressEl.dom.firstChild;
3420 pp = Roo.get(pf.firstChild);
3421 pp.setHeight(pf.offsetHeight);
3429 * Updates the message box body text
3430 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3431 * the XHTML-compliant non-breaking space character '&#160;')
3432 * @return {Roo.MessageBox} This message box
3434 updateText : function(text)
3436 if(!dlg.isVisible() && !opt.width){
3437 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3438 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3440 msgEl.innerHTML = text || ' ';
3442 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3443 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3445 Math.min(opt.width || cw , this.maxWidth),
3446 Math.max(opt.minWidth || this.minWidth, bwidth)
3449 activeTextEl.setWidth(w);
3451 if(dlg.isVisible()){
3452 dlg.fixedcenter = false;
3454 // to big, make it scroll. = But as usual stupid IE does not support
3457 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3458 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3459 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3461 bodyEl.dom.style.height = '';
3462 bodyEl.dom.style.overflowY = '';
3465 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3467 bodyEl.dom.style.overflowX = '';
3470 dlg.setContentSize(w, bodyEl.getHeight());
3471 if(dlg.isVisible()){
3472 dlg.fixedcenter = true;
3478 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3479 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3480 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3481 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3482 * @return {Roo.MessageBox} This message box
3484 updateProgress : function(value, text){
3486 this.updateText(text);
3489 if (pp) { // weird bug on my firefox - for some reason this is not defined
3490 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3491 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3497 * Returns true if the message box is currently displayed
3498 * @return {Boolean} True if the message box is visible, else false
3500 isVisible : function(){
3501 return dlg && dlg.isVisible();
3505 * Hides the message box if it is displayed
3508 if(this.isVisible()){
3514 * Displays a new message box, or reinitializes an existing message box, based on the config options
3515 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3516 * The following config object properties are supported:
3518 Property Type Description
3519 ---------- --------------- ------------------------------------------------------------------------------------
3520 animEl String/Element An id or Element from which the message box should animate as it opens and
3521 closes (defaults to undefined)
3522 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3523 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3524 closable Boolean False to hide the top-right close button (defaults to true). Note that
3525 progress and wait dialogs will ignore this property and always hide the
3526 close button as they can only be closed programmatically.
3527 cls String A custom CSS class to apply to the message box element
3528 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3529 displayed (defaults to 75)
3530 fn Function A callback function to execute after closing the dialog. The arguments to the
3531 function will be btn (the name of the button that was clicked, if applicable,
3532 e.g. "ok"), and text (the value of the active text field, if applicable).
3533 Progress and wait dialogs will ignore this option since they do not respond to
3534 user actions and can only be closed programmatically, so any required function
3535 should be called by the same code after it closes the dialog.
3536 icon String A CSS class that provides a background image to be used as an icon for
3537 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3538 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3539 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3540 modal Boolean False to allow user interaction with the page while the message box is
3541 displayed (defaults to true)
3542 msg String A string that will replace the existing message box body text (defaults
3543 to the XHTML-compliant non-breaking space character ' ')
3544 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3545 progress Boolean True to display a progress bar (defaults to false)
3546 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3547 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3548 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3549 title String The title text
3550 value String The string value to set into the active textbox element if displayed
3551 wait Boolean True to display a progress bar (defaults to false)
3552 width Number The width of the dialog in pixels
3559 msg: 'Please enter your address:',
3561 buttons: Roo.MessageBox.OKCANCEL,
3564 animEl: 'addAddressBtn'
3567 * @param {Object} config Configuration options
3568 * @return {Roo.MessageBox} This message box
3570 show : function(options)
3573 // this causes nightmares if you show one dialog after another
3574 // especially on callbacks..
3576 if(this.isVisible()){
3579 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3580 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3581 Roo.log("New Dialog Message:" + options.msg )
3582 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3583 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3586 var d = this.getDialog();
3588 d.setTitle(opt.title || " ");
3589 d.closeEl.setDisplayed(opt.closable !== false);
3590 activeTextEl = textboxEl;
3591 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3596 textareaEl.setHeight(typeof opt.multiline == "number" ?
3597 opt.multiline : this.defaultTextHeight);
3598 activeTextEl = textareaEl;
3607 progressEl.setDisplayed(opt.progress === true);
3609 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3611 this.updateProgress(0);
3612 activeTextEl.dom.value = opt.value || "";
3614 dlg.setDefaultButton(activeTextEl);
3616 var bs = opt.buttons;
3620 }else if(bs && bs.yes){
3621 db = buttons["yes"];
3623 dlg.setDefaultButton(db);
3625 bwidth = updateButtons(opt.buttons);
3626 this.updateText(opt.msg);
3628 d.el.addClass(opt.cls);
3630 d.proxyDrag = opt.proxyDrag === true;
3631 d.modal = opt.modal !== false;
3632 d.mask = opt.modal !== false ? mask : false;
3634 // force it to the end of the z-index stack so it gets a cursor in FF
3635 document.body.appendChild(dlg.el.dom);
3636 d.animateTarget = null;
3637 d.show(options.animEl);
3643 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3644 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3645 * and closing the message box when the process is complete.
3646 * @param {String} title The title bar text
3647 * @param {String} msg The message box body text
3648 * @return {Roo.MessageBox} This message box
3650 progress : function(title, msg){
3657 minWidth: this.minProgressWidth,
3664 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3665 * If a callback function is passed it will be called after the user clicks the button, and the
3666 * id of the button that was clicked will be passed as the only parameter to the callback
3667 * (could also be the top-right close button).
3668 * @param {String} title The title bar text
3669 * @param {String} msg The message box body text
3670 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3671 * @param {Object} scope (optional) The scope of the callback function
3672 * @return {Roo.MessageBox} This message box
3674 alert : function(title, msg, fn, scope)
3689 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3690 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3691 * You are responsible for closing the message box when the process is complete.
3692 * @param {String} msg The message box body text
3693 * @param {String} title (optional) The title bar text
3694 * @return {Roo.MessageBox} This message box
3696 wait : function(msg, title){
3707 waitTimer = Roo.TaskMgr.start({
3709 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3717 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3718 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3719 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3720 * @param {String} title The title bar text
3721 * @param {String} msg The message box body text
3722 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3723 * @param {Object} scope (optional) The scope of the callback function
3724 * @return {Roo.MessageBox} This message box
3726 confirm : function(title, msg, fn, scope){
3730 buttons: this.YESNO,
3739 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3740 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3741 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3742 * (could also be the top-right close button) and the text that was entered will be passed as the two
3743 * parameters to the callback.
3744 * @param {String} title The title bar text
3745 * @param {String} msg The message box body text
3746 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3747 * @param {Object} scope (optional) The scope of the callback function
3748 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3749 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3750 * @return {Roo.MessageBox} This message box
3752 prompt : function(title, msg, fn, scope, multiline){
3756 buttons: this.OKCANCEL,
3761 multiline: multiline,
3768 * Button config that displays a single OK button
3773 * Button config that displays Yes and No buttons
3776 YESNO : {yes:true, no:true},
3778 * Button config that displays OK and Cancel buttons
3781 OKCANCEL : {ok:true, cancel:true},
3783 * Button config that displays Yes, No and Cancel buttons
3786 YESNOCANCEL : {yes:true, no:true, cancel:true},
3789 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3792 defaultTextHeight : 75,
3794 * The maximum width in pixels of the message box (defaults to 600)
3799 * The minimum width in pixels of the message box (defaults to 100)
3804 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3805 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3808 minProgressWidth : 250,
3810 * An object containing the default button text strings that can be overriden for localized language support.
3811 * Supported properties are: ok, cancel, yes and no.
3812 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3825 * Shorthand for {@link Roo.MessageBox}
3827 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3828 Roo.Msg = Roo.Msg || Roo.MessageBox;
3837 * @class Roo.bootstrap.Navbar
3838 * @extends Roo.bootstrap.Component
3839 * Bootstrap Navbar class
3842 * Create a new Navbar
3843 * @param {Object} config The config object
3847 Roo.bootstrap.Navbar = function(config){
3848 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3852 * @event beforetoggle
3853 * Fire before toggle the menu
3854 * @param {Roo.EventObject} e
3856 "beforetoggle" : true
3860 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3869 getAutoCreate : function(){
3872 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3876 initEvents :function ()
3878 //Roo.log(this.el.select('.navbar-toggle',true));
3879 this.el.select('.navbar-toggle',true).on('click', function() {
3880 if(this.fireEvent('beforetoggle', this) !== false){
3881 var ce = this.el.select('.navbar-collapse',true).first();
3882 ce.toggleClass('in'); // old...
3883 if (ce.hasClass('collapse')) {
3885 ce.removeClass('collapse');
3886 ce.addClass('show');
3887 var h = ce.getHeight();
3889 ce.removeClass('show');
3890 // at this point we should be able to see it..
3891 ce.addClass('collapsing');
3893 ce.setHeight(0); // resize it ...
3894 ce.on('transitionend', function() {
3895 Roo.log('done transition');
3896 ce.removeClass('collapsing');
3897 ce.addClass('show');
3898 ce.removeClass('collapse');
3900 ce.dom.style.height = '';
3901 }, this, { single: true} );
3905 ce.setHeight(ce.getHeight());
3906 ce.removeClass('show');
3907 ce.addClass('collapsing');
3909 ce.on('transitionend', function() {
3910 ce.dom.style.height = '';
3911 ce.removeClass('collapsing');
3912 ce.addClass('collapse');
3913 }, this, { single: true} );
3925 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3927 var size = this.el.getSize();
3928 this.maskEl.setSize(size.width, size.height);
3929 this.maskEl.enableDisplayMode("block");
3938 getChildContainer : function()
3940 if (this.el.select('.collapse').getCount()) {
3941 return this.el.select('.collapse',true).first();
3974 * @class Roo.bootstrap.NavSimplebar
3975 * @extends Roo.bootstrap.Navbar
3976 * Bootstrap Sidebar class
3978 * @cfg {Boolean} inverse is inverted color
3980 * @cfg {String} type (nav | pills | tabs)
3981 * @cfg {Boolean} arrangement stacked | justified
3982 * @cfg {String} align (left | right) alignment
3984 * @cfg {Boolean} main (true|false) main nav bar? default false
3985 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3987 * @cfg {String} tag (header|footer|nav|div) default is nav
3989 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
3993 * Create a new Sidebar
3994 * @param {Object} config The config object
3998 Roo.bootstrap.NavSimplebar = function(config){
3999 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4002 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4018 getAutoCreate : function(){
4022 tag : this.tag || 'div',
4023 cls : 'navbar navbar-expand-lg'
4025 if (['light','white'].indexOf(this.weight) > -1) {
4026 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4028 cfg.cls += ' bg-' + this.weight;
4031 cfg.cls += ' navbar-inverse';
4035 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4037 if (Roo.bootstrap.version == 4) {
4049 this.type = this.type || 'nav';
4050 if (['tabs','pills'].indexOf(this.type)!==-1) {
4051 cfg.cn[0].cls += ' nav-' + this.type
4055 if (this.type!=='nav') {
4056 Roo.log('nav type must be nav/tabs/pills')
4058 cfg.cn[0].cls += ' navbar-nav'
4064 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
4065 cfg.cn[0].cls += ' nav-' + this.arrangement;
4069 if (this.align === 'right') {
4070 cfg.cn[0].cls += ' navbar-right';
4095 * navbar-expand-md fixed-top
4099 * @class Roo.bootstrap.NavHeaderbar
4100 * @extends Roo.bootstrap.NavSimplebar
4101 * Bootstrap Sidebar class
4103 * @cfg {String} brand what is brand
4104 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4105 * @cfg {String} brand_href href of the brand
4106 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4107 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4108 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4109 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4112 * Create a new Sidebar
4113 * @param {Object} config The config object
4117 Roo.bootstrap.NavHeaderbar = function(config){
4118 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4122 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4129 desktopCenter : false,
4132 getAutoCreate : function(){
4135 tag: this.nav || 'nav',
4136 cls: 'navbar navbar-expand-md',
4142 if (this.desktopCenter) {
4143 cn.push({cls : 'container', cn : []});
4151 cls: 'navbar-toggle navbar-toggler',
4152 'data-toggle': 'collapse',
4157 html: 'Toggle navigation'
4161 cls: 'icon-bar navbar-toggler-icon'
4174 cn.push( Roo.bootstrap.version == 4 ? btn : {
4176 cls: 'navbar-header',
4185 cls: 'collapse navbar-collapse',
4189 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4191 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4192 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4194 // tag can override this..
4196 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4199 if (this.brand !== '') {
4200 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4201 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4203 href: this.brand_href ? this.brand_href : '#',
4204 cls: 'navbar-brand',
4212 cfg.cls += ' main-nav';
4220 getHeaderChildContainer : function()
4222 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4223 return this.el.select('.navbar-header',true).first();
4226 return this.getChildContainer();
4230 initEvents : function()
4232 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4234 if (this.autohide) {
4239 Roo.get(document).on('scroll',function(e) {
4240 var ns = Roo.get(document).getScroll().top;
4241 var os = prevScroll;
4245 ft.removeClass('slideDown');
4246 ft.addClass('slideUp');
4249 ft.removeClass('slideUp');
4250 ft.addClass('slideDown');
4271 * @class Roo.bootstrap.NavSidebar
4272 * @extends Roo.bootstrap.Navbar
4273 * Bootstrap Sidebar class
4276 * Create a new Sidebar
4277 * @param {Object} config The config object
4281 Roo.bootstrap.NavSidebar = function(config){
4282 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4285 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4287 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4289 getAutoCreate : function(){
4294 cls: 'sidebar sidebar-nav'
4316 * @class Roo.bootstrap.NavGroup
4317 * @extends Roo.bootstrap.Component
4318 * Bootstrap NavGroup class
4319 * @cfg {String} align (left|right)
4320 * @cfg {Boolean} inverse
4321 * @cfg {String} type (nav|pills|tab) default nav
4322 * @cfg {String} navId - reference Id for navbar.
4326 * Create a new nav group
4327 * @param {Object} config The config object
4330 Roo.bootstrap.NavGroup = function(config){
4331 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4334 Roo.bootstrap.NavGroup.register(this);
4338 * Fires when the active item changes
4339 * @param {Roo.bootstrap.NavGroup} this
4340 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4341 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4348 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4359 getAutoCreate : function()
4361 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4367 if (Roo.bootstrap.version == 4) {
4368 if (this.type == 'pills') {
4369 cfg.cls = ' nav-pills';
4372 if (['tabs','pills'].indexOf(this.type)!==-1) {
4373 cfg.cls += ' nav-' + this.type
4375 if (this.type !== 'nav') {
4376 Roo.log('nav type must be nav/tabs/pills')
4378 cfg.cls += ' navbar-nav'
4382 if (this.parent() && this.parent().sidebar) {
4385 cls: 'dashboard-menu sidebar-menu'
4391 if (this.form === true) {
4394 cls: 'navbar-form form-inline'
4397 if (this.align === 'right') {
4398 cfg.cls += ' navbar-right ml-md-auto';
4400 cfg.cls += ' navbar-left';
4404 if (this.align === 'right') {
4405 cfg.cls += ' navbar-right ml-md-auto';
4407 cfg.cls += ' mr-auto';
4411 cfg.cls += ' navbar-inverse';
4419 * sets the active Navigation item
4420 * @param {Roo.bootstrap.NavItem} the new current navitem
4422 setActiveItem : function(item)
4425 Roo.each(this.navItems, function(v){
4430 v.setActive(false, true);
4437 item.setActive(true, true);
4438 this.fireEvent('changed', this, item, prev);
4443 * gets the active Navigation item
4444 * @return {Roo.bootstrap.NavItem} the current navitem
4446 getActive : function()
4450 Roo.each(this.navItems, function(v){
4461 indexOfNav : function()
4465 Roo.each(this.navItems, function(v,i){
4476 * adds a Navigation item
4477 * @param {Roo.bootstrap.NavItem} the navitem to add
4479 addItem : function(cfg)
4481 if (this.form && Roo.bootstrap.version == 4) {
4484 var cn = new Roo.bootstrap.NavItem(cfg);
4486 cn.parentId = this.id;
4487 cn.onRender(this.el, null);
4491 * register a Navigation item
4492 * @param {Roo.bootstrap.NavItem} the navitem to add
4494 register : function(item)
4496 this.navItems.push( item);
4497 item.navId = this.navId;
4502 * clear all the Navigation item
4505 clearAll : function()
4508 this.el.dom.innerHTML = '';
4511 getNavItem: function(tabId)
4514 Roo.each(this.navItems, function(e) {
4515 if (e.tabId == tabId) {
4525 setActiveNext : function()
4527 var i = this.indexOfNav(this.getActive());
4528 if (i > this.navItems.length) {
4531 this.setActiveItem(this.navItems[i+1]);
4533 setActivePrev : function()
4535 var i = this.indexOfNav(this.getActive());
4539 this.setActiveItem(this.navItems[i-1]);
4541 clearWasActive : function(except) {
4542 Roo.each(this.navItems, function(e) {
4543 if (e.tabId != except.tabId && e.was_active) {
4544 e.was_active = false;
4551 getWasActive : function ()
4554 Roo.each(this.navItems, function(e) {
4569 Roo.apply(Roo.bootstrap.NavGroup, {
4573 * register a Navigation Group
4574 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4576 register : function(navgrp)
4578 this.groups[navgrp.navId] = navgrp;
4582 * fetch a Navigation Group based on the navigation ID
4583 * @param {string} the navgroup to add
4584 * @returns {Roo.bootstrap.NavGroup} the navgroup
4586 get: function(navId) {
4587 if (typeof(this.groups[navId]) == 'undefined') {
4589 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4591 return this.groups[navId] ;
4606 * @class Roo.bootstrap.NavItem
4607 * @extends Roo.bootstrap.Component
4608 * Bootstrap Navbar.NavItem class
4609 * @cfg {String} href link to
4610 * @cfg {String} html content of button
4611 * @cfg {String} badge text inside badge
4612 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4613 * @cfg {String} glyphicon DEPRICATED - use fa
4614 * @cfg {String} icon DEPRICATED - use fa
4615 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4616 * @cfg {Boolean} active Is item active
4617 * @cfg {Boolean} disabled Is item disabled
4619 * @cfg {Boolean} preventDefault (true | false) default false
4620 * @cfg {String} tabId the tab that this item activates.
4621 * @cfg {String} tagtype (a|span) render as a href or span?
4622 * @cfg {Boolean} animateRef (true|false) link to element default false
4625 * Create a new Navbar Item
4626 * @param {Object} config The config object
4628 Roo.bootstrap.NavItem = function(config){
4629 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4634 * The raw click event for the entire grid.
4635 * @param {Roo.EventObject} e
4640 * Fires when the active item active state changes
4641 * @param {Roo.bootstrap.NavItem} this
4642 * @param {boolean} state the new state
4648 * Fires when scroll to element
4649 * @param {Roo.bootstrap.NavItem} this
4650 * @param {Object} options
4651 * @param {Roo.EventObject} e
4659 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4668 preventDefault : false,
4676 getAutoCreate : function(){
4685 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4687 if (this.disabled) {
4688 cfg.cls += ' disabled';
4691 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4695 href : this.href || "#",
4696 html: this.html || ''
4699 if (this.tagtype == 'a') {
4700 cfg.cn[0].cls = 'nav-link';
4703 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
4706 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>'
4708 if(this.glyphicon) {
4709 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4714 cfg.cn[0].html += " <span class='caret'></span>";
4718 if (this.badge !== '') {
4720 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4728 onRender : function(ct, position)
4730 // Roo.log("Call onRender: " + this.xtype);
4731 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4735 return Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4739 initEvents: function()
4741 if (typeof (this.menu) != 'undefined') {
4742 this.menu.parentType = this.xtype;
4743 this.menu.triggerEl = this.el;
4744 this.menu = this.addxtype(Roo.apply({}, this.menu));
4747 this.el.select('a',true).on('click', this.onClick, this);
4749 if(this.tagtype == 'span'){
4750 this.el.select('span',true).on('click', this.onClick, this);
4753 // at this point parent should be available..
4754 this.parent().register(this);
4757 onClick : function(e)
4759 if (e.getTarget('.dropdown-menu-item')) {
4760 // did you click on a menu itemm.... - then don't trigger onclick..
4765 this.preventDefault ||
4768 Roo.log("NavItem - prevent Default?");
4772 if (this.disabled) {
4776 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4777 if (tg && tg.transition) {
4778 Roo.log("waiting for the transitionend");
4784 //Roo.log("fire event clicked");
4785 if(this.fireEvent('click', this, e) === false){
4789 if(this.tagtype == 'span'){
4793 //Roo.log(this.href);
4794 var ael = this.el.select('a',true).first();
4797 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4798 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4799 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4800 return; // ignore... - it's a 'hash' to another page.
4802 Roo.log("NavItem - prevent Default?");
4804 this.scrollToElement(e);
4808 var p = this.parent();
4810 if (['tabs','pills'].indexOf(p.type)!==-1) {
4811 if (typeof(p.setActiveItem) !== 'undefined') {
4812 p.setActiveItem(this);
4816 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4817 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4818 // remove the collapsed menu expand...
4819 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4823 isActive: function () {
4826 setActive : function(state, fire, is_was_active)
4828 if (this.active && !state && this.navId) {
4829 this.was_active = true;
4830 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4832 nv.clearWasActive(this);
4836 this.active = state;
4839 this.el.removeClass('active');
4840 } else if (!this.el.hasClass('active')) {
4841 this.el.addClass('active');
4844 this.fireEvent('changed', this, state);
4847 // show a panel if it's registered and related..
4849 if (!this.navId || !this.tabId || !state || is_was_active) {
4853 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4857 var pan = tg.getPanelByName(this.tabId);
4861 // if we can not flip to new panel - go back to old nav highlight..
4862 if (false == tg.showPanel(pan)) {
4863 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4865 var onav = nv.getWasActive();
4867 onav.setActive(true, false, true);
4876 // this should not be here...
4877 setDisabled : function(state)
4879 this.disabled = state;
4881 this.el.removeClass('disabled');
4882 } else if (!this.el.hasClass('disabled')) {
4883 this.el.addClass('disabled');
4889 * Fetch the element to display the tooltip on.
4890 * @return {Roo.Element} defaults to this.el
4892 tooltipEl : function()
4894 return this.el.select('' + this.tagtype + '', true).first();
4897 scrollToElement : function(e)
4899 var c = document.body;
4902 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4904 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4905 c = document.documentElement;
4908 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4914 var o = target.calcOffsetsTo(c);
4921 this.fireEvent('scrollto', this, options, e);
4923 Roo.get(c).scrollTo('top', options.value, true);
4936 * <span> icon </span>
4937 * <span> text </span>
4938 * <span>badge </span>
4942 * @class Roo.bootstrap.NavSidebarItem
4943 * @extends Roo.bootstrap.NavItem
4944 * Bootstrap Navbar.NavSidebarItem class
4945 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4946 * {Boolean} open is the menu open
4947 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4948 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4949 * {String} buttonSize (sm|md|lg)the extra classes for the button
4950 * {Boolean} showArrow show arrow next to the text (default true)
4952 * Create a new Navbar Button
4953 * @param {Object} config The config object
4955 Roo.bootstrap.NavSidebarItem = function(config){
4956 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
4961 * The raw click event for the entire grid.
4962 * @param {Roo.EventObject} e
4967 * Fires when the active item active state changes
4968 * @param {Roo.bootstrap.NavSidebarItem} this
4969 * @param {boolean} state the new state
4977 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
4979 badgeWeight : 'default',
4985 buttonWeight : 'default',
4991 getAutoCreate : function(){
4996 href : this.href || '#',
5002 if(this.buttonView){
5005 href : this.href || '#',
5006 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5019 cfg.cls += ' active';
5022 if (this.disabled) {
5023 cfg.cls += ' disabled';
5026 cfg.cls += ' open x-open';
5029 if (this.glyphicon || this.icon) {
5030 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5031 a.cn.push({ tag : 'i', cls : c }) ;
5034 if(!this.buttonView){
5037 html : this.html || ''
5044 if (this.badge !== '') {
5045 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5051 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5054 a.cls += ' dropdown-toggle treeview' ;
5060 initEvents : function()
5062 if (typeof (this.menu) != 'undefined') {
5063 this.menu.parentType = this.xtype;
5064 this.menu.triggerEl = this.el;
5065 this.menu = this.addxtype(Roo.apply({}, this.menu));
5068 this.el.on('click', this.onClick, this);
5070 if(this.badge !== ''){
5071 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5076 onClick : function(e)
5083 if(this.preventDefault){
5087 this.fireEvent('click', this);
5090 disable : function()
5092 this.setDisabled(true);
5097 this.setDisabled(false);
5100 setDisabled : function(state)
5102 if(this.disabled == state){
5106 this.disabled = state;
5109 this.el.addClass('disabled');
5113 this.el.removeClass('disabled');
5118 setActive : function(state)
5120 if(this.active == state){
5124 this.active = state;
5127 this.el.addClass('active');
5131 this.el.removeClass('active');
5136 isActive: function ()
5141 setBadge : function(str)
5147 this.badgeEl.dom.innerHTML = str;
5164 * @class Roo.bootstrap.Row
5165 * @extends Roo.bootstrap.Component
5166 * Bootstrap Row class (contains columns...)
5170 * @param {Object} config The config object
5173 Roo.bootstrap.Row = function(config){
5174 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5177 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5179 getAutoCreate : function(){
5198 * @class Roo.bootstrap.Element
5199 * @extends Roo.bootstrap.Component
5200 * Bootstrap Element class
5201 * @cfg {String} html contents of the element
5202 * @cfg {String} tag tag of the element
5203 * @cfg {String} cls class of the element
5204 * @cfg {Boolean} preventDefault (true|false) default false
5205 * @cfg {Boolean} clickable (true|false) default false
5208 * Create a new Element
5209 * @param {Object} config The config object
5212 Roo.bootstrap.Element = function(config){
5213 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5219 * When a element is chick
5220 * @param {Roo.bootstrap.Element} this
5221 * @param {Roo.EventObject} e
5227 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5232 preventDefault: false,
5235 getAutoCreate : function(){
5239 // cls: this.cls, double assign in parent class Component.js :: onRender
5246 initEvents: function()
5248 Roo.bootstrap.Element.superclass.initEvents.call(this);
5251 this.el.on('click', this.onClick, this);
5256 onClick : function(e)
5258 if(this.preventDefault){
5262 this.fireEvent('click', this, e);
5265 getValue : function()
5267 return this.el.dom.innerHTML;
5270 setValue : function(value)
5272 this.el.dom.innerHTML = value;
5287 * @class Roo.bootstrap.Pagination
5288 * @extends Roo.bootstrap.Component
5289 * Bootstrap Pagination class
5290 * @cfg {String} size xs | sm | md | lg
5291 * @cfg {Boolean} inverse false | true
5294 * Create a new Pagination
5295 * @param {Object} config The config object
5298 Roo.bootstrap.Pagination = function(config){
5299 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5302 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5308 getAutoCreate : function(){
5314 cfg.cls += ' inverse';
5320 cfg.cls += " " + this.cls;
5338 * @class Roo.bootstrap.PaginationItem
5339 * @extends Roo.bootstrap.Component
5340 * Bootstrap PaginationItem class
5341 * @cfg {String} html text
5342 * @cfg {String} href the link
5343 * @cfg {Boolean} preventDefault (true | false) default true
5344 * @cfg {Boolean} active (true | false) default false
5345 * @cfg {Boolean} disabled default false
5349 * Create a new PaginationItem
5350 * @param {Object} config The config object
5354 Roo.bootstrap.PaginationItem = function(config){
5355 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5360 * The raw click event for the entire grid.
5361 * @param {Roo.EventObject} e
5367 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5371 preventDefault: true,
5376 getAutoCreate : function(){
5382 href : this.href ? this.href : '#',
5383 html : this.html ? this.html : ''
5393 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5397 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5403 initEvents: function() {
5405 this.el.on('click', this.onClick, this);
5408 onClick : function(e)
5410 Roo.log('PaginationItem on click ');
5411 if(this.preventDefault){
5419 this.fireEvent('click', this, e);
5435 * @class Roo.bootstrap.Slider
5436 * @extends Roo.bootstrap.Component
5437 * Bootstrap Slider class
5440 * Create a new Slider
5441 * @param {Object} config The config object
5444 Roo.bootstrap.Slider = function(config){
5445 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5448 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5450 getAutoCreate : function(){
5454 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5458 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5470 * Ext JS Library 1.1.1
5471 * Copyright(c) 2006-2007, Ext JS, LLC.
5473 * Originally Released Under LGPL - original licence link has changed is not relivant.
5476 * <script type="text/javascript">
5481 * @class Roo.grid.ColumnModel
5482 * @extends Roo.util.Observable
5483 * This is the default implementation of a ColumnModel used by the Grid. It defines
5484 * the columns in the grid.
5487 var colModel = new Roo.grid.ColumnModel([
5488 {header: "Ticker", width: 60, sortable: true, locked: true},
5489 {header: "Company Name", width: 150, sortable: true},
5490 {header: "Market Cap.", width: 100, sortable: true},
5491 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5492 {header: "Employees", width: 100, sortable: true, resizable: false}
5497 * The config options listed for this class are options which may appear in each
5498 * individual column definition.
5499 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5501 * @param {Object} config An Array of column config objects. See this class's
5502 * config objects for details.
5504 Roo.grid.ColumnModel = function(config){
5506 * The config passed into the constructor
5508 this.config = config;
5511 // if no id, create one
5512 // if the column does not have a dataIndex mapping,
5513 // map it to the order it is in the config
5514 for(var i = 0, len = config.length; i < len; i++){
5516 if(typeof c.dataIndex == "undefined"){
5519 if(typeof c.renderer == "string"){
5520 c.renderer = Roo.util.Format[c.renderer];
5522 if(typeof c.id == "undefined"){
5525 if(c.editor && c.editor.xtype){
5526 c.editor = Roo.factory(c.editor, Roo.grid);
5528 if(c.editor && c.editor.isFormField){
5529 c.editor = new Roo.grid.GridEditor(c.editor);
5531 this.lookup[c.id] = c;
5535 * The width of columns which have no width specified (defaults to 100)
5538 this.defaultWidth = 100;
5541 * Default sortable of columns which have no sortable specified (defaults to false)
5544 this.defaultSortable = false;
5548 * @event widthchange
5549 * Fires when the width of a column changes.
5550 * @param {ColumnModel} this
5551 * @param {Number} columnIndex The column index
5552 * @param {Number} newWidth The new width
5554 "widthchange": true,
5556 * @event headerchange
5557 * Fires when the text of a header changes.
5558 * @param {ColumnModel} this
5559 * @param {Number} columnIndex The column index
5560 * @param {Number} newText The new header text
5562 "headerchange": true,
5564 * @event hiddenchange
5565 * Fires when a column is hidden or "unhidden".
5566 * @param {ColumnModel} this
5567 * @param {Number} columnIndex The column index
5568 * @param {Boolean} hidden true if hidden, false otherwise
5570 "hiddenchange": true,
5572 * @event columnmoved
5573 * Fires when a column is moved.
5574 * @param {ColumnModel} this
5575 * @param {Number} oldIndex
5576 * @param {Number} newIndex
5578 "columnmoved" : true,
5580 * @event columlockchange
5581 * Fires when a column's locked state is changed
5582 * @param {ColumnModel} this
5583 * @param {Number} colIndex
5584 * @param {Boolean} locked true if locked
5586 "columnlockchange" : true
5588 Roo.grid.ColumnModel.superclass.constructor.call(this);
5590 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5592 * @cfg {String} header The header text to display in the Grid view.
5595 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5596 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5597 * specified, the column's index is used as an index into the Record's data Array.
5600 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5601 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5604 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5605 * Defaults to the value of the {@link #defaultSortable} property.
5606 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5609 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5612 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5615 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5618 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5621 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5622 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5623 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5624 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5627 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5630 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5633 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5636 * @cfg {String} cursor (Optional)
5639 * @cfg {String} tooltip (Optional)
5642 * @cfg {Number} xs (Optional)
5645 * @cfg {Number} sm (Optional)
5648 * @cfg {Number} md (Optional)
5651 * @cfg {Number} lg (Optional)
5654 * Returns the id of the column at the specified index.
5655 * @param {Number} index The column index
5656 * @return {String} the id
5658 getColumnId : function(index){
5659 return this.config[index].id;
5663 * Returns the column for a specified id.
5664 * @param {String} id The column id
5665 * @return {Object} the column
5667 getColumnById : function(id){
5668 return this.lookup[id];
5673 * Returns the column for a specified dataIndex.
5674 * @param {String} dataIndex The column dataIndex
5675 * @return {Object|Boolean} the column or false if not found
5677 getColumnByDataIndex: function(dataIndex){
5678 var index = this.findColumnIndex(dataIndex);
5679 return index > -1 ? this.config[index] : false;
5683 * Returns the index for a specified column id.
5684 * @param {String} id The column id
5685 * @return {Number} the index, or -1 if not found
5687 getIndexById : function(id){
5688 for(var i = 0, len = this.config.length; i < len; i++){
5689 if(this.config[i].id == id){
5697 * Returns the index for a specified column dataIndex.
5698 * @param {String} dataIndex The column dataIndex
5699 * @return {Number} the index, or -1 if not found
5702 findColumnIndex : function(dataIndex){
5703 for(var i = 0, len = this.config.length; i < len; i++){
5704 if(this.config[i].dataIndex == dataIndex){
5712 moveColumn : function(oldIndex, newIndex){
5713 var c = this.config[oldIndex];
5714 this.config.splice(oldIndex, 1);
5715 this.config.splice(newIndex, 0, c);
5716 this.dataMap = null;
5717 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5720 isLocked : function(colIndex){
5721 return this.config[colIndex].locked === true;
5724 setLocked : function(colIndex, value, suppressEvent){
5725 if(this.isLocked(colIndex) == value){
5728 this.config[colIndex].locked = value;
5730 this.fireEvent("columnlockchange", this, colIndex, value);
5734 getTotalLockedWidth : function(){
5736 for(var i = 0; i < this.config.length; i++){
5737 if(this.isLocked(i) && !this.isHidden(i)){
5738 this.totalWidth += this.getColumnWidth(i);
5744 getLockedCount : function(){
5745 for(var i = 0, len = this.config.length; i < len; i++){
5746 if(!this.isLocked(i)){
5751 return this.config.length;
5755 * Returns the number of columns.
5758 getColumnCount : function(visibleOnly){
5759 if(visibleOnly === true){
5761 for(var i = 0, len = this.config.length; i < len; i++){
5762 if(!this.isHidden(i)){
5768 return this.config.length;
5772 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5773 * @param {Function} fn
5774 * @param {Object} scope (optional)
5775 * @return {Array} result
5777 getColumnsBy : function(fn, scope){
5779 for(var i = 0, len = this.config.length; i < len; i++){
5780 var c = this.config[i];
5781 if(fn.call(scope||this, c, i) === true){
5789 * Returns true if the specified column is sortable.
5790 * @param {Number} col The column index
5793 isSortable : function(col){
5794 if(typeof this.config[col].sortable == "undefined"){
5795 return this.defaultSortable;
5797 return this.config[col].sortable;
5801 * Returns the rendering (formatting) function defined for the column.
5802 * @param {Number} col The column index.
5803 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5805 getRenderer : function(col){
5806 if(!this.config[col].renderer){
5807 return Roo.grid.ColumnModel.defaultRenderer;
5809 return this.config[col].renderer;
5813 * Sets the rendering (formatting) function for a column.
5814 * @param {Number} col The column index
5815 * @param {Function} fn The function to use to process the cell's raw data
5816 * to return HTML markup for the grid view. The render function is called with
5817 * the following parameters:<ul>
5818 * <li>Data value.</li>
5819 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5820 * <li>css A CSS style string to apply to the table cell.</li>
5821 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5822 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5823 * <li>Row index</li>
5824 * <li>Column index</li>
5825 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5827 setRenderer : function(col, fn){
5828 this.config[col].renderer = fn;
5832 * Returns the width for the specified column.
5833 * @param {Number} col The column index
5836 getColumnWidth : function(col){
5837 return this.config[col].width * 1 || this.defaultWidth;
5841 * Sets the width for a column.
5842 * @param {Number} col The column index
5843 * @param {Number} width The new width
5845 setColumnWidth : function(col, width, suppressEvent){
5846 this.config[col].width = width;
5847 this.totalWidth = null;
5849 this.fireEvent("widthchange", this, col, width);
5854 * Returns the total width of all columns.
5855 * @param {Boolean} includeHidden True to include hidden column widths
5858 getTotalWidth : function(includeHidden){
5859 if(!this.totalWidth){
5860 this.totalWidth = 0;
5861 for(var i = 0, len = this.config.length; i < len; i++){
5862 if(includeHidden || !this.isHidden(i)){
5863 this.totalWidth += this.getColumnWidth(i);
5867 return this.totalWidth;
5871 * Returns the header for the specified column.
5872 * @param {Number} col The column index
5875 getColumnHeader : function(col){
5876 return this.config[col].header;
5880 * Sets the header for a column.
5881 * @param {Number} col The column index
5882 * @param {String} header The new header
5884 setColumnHeader : function(col, header){
5885 this.config[col].header = header;
5886 this.fireEvent("headerchange", this, col, header);
5890 * Returns the tooltip for the specified column.
5891 * @param {Number} col The column index
5894 getColumnTooltip : function(col){
5895 return this.config[col].tooltip;
5898 * Sets the tooltip for a column.
5899 * @param {Number} col The column index
5900 * @param {String} tooltip The new tooltip
5902 setColumnTooltip : function(col, tooltip){
5903 this.config[col].tooltip = tooltip;
5907 * Returns the dataIndex for the specified column.
5908 * @param {Number} col The column index
5911 getDataIndex : function(col){
5912 return this.config[col].dataIndex;
5916 * Sets the dataIndex for a column.
5917 * @param {Number} col The column index
5918 * @param {Number} dataIndex The new dataIndex
5920 setDataIndex : function(col, dataIndex){
5921 this.config[col].dataIndex = dataIndex;
5927 * Returns true if the cell is editable.
5928 * @param {Number} colIndex The column index
5929 * @param {Number} rowIndex The row index - this is nto actually used..?
5932 isCellEditable : function(colIndex, rowIndex){
5933 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5937 * Returns the editor defined for the cell/column.
5938 * return false or null to disable editing.
5939 * @param {Number} colIndex The column index
5940 * @param {Number} rowIndex The row index
5943 getCellEditor : function(colIndex, rowIndex){
5944 return this.config[colIndex].editor;
5948 * Sets if a column is editable.
5949 * @param {Number} col The column index
5950 * @param {Boolean} editable True if the column is editable
5952 setEditable : function(col, editable){
5953 this.config[col].editable = editable;
5958 * Returns true if the column is hidden.
5959 * @param {Number} colIndex The column index
5962 isHidden : function(colIndex){
5963 return this.config[colIndex].hidden;
5968 * Returns true if the column width cannot be changed
5970 isFixed : function(colIndex){
5971 return this.config[colIndex].fixed;
5975 * Returns true if the column can be resized
5978 isResizable : function(colIndex){
5979 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
5982 * Sets if a column is hidden.
5983 * @param {Number} colIndex The column index
5984 * @param {Boolean} hidden True if the column is hidden
5986 setHidden : function(colIndex, hidden){
5987 this.config[colIndex].hidden = hidden;
5988 this.totalWidth = null;
5989 this.fireEvent("hiddenchange", this, colIndex, hidden);
5993 * Sets the editor for a column.
5994 * @param {Number} col The column index
5995 * @param {Object} editor The editor object
5997 setEditor : function(col, editor){
5998 this.config[col].editor = editor;
6002 Roo.grid.ColumnModel.defaultRenderer = function(value)
6004 if(typeof value == "object") {
6007 if(typeof value == "string" && value.length < 1){
6011 return String.format("{0}", value);
6014 // Alias for backwards compatibility
6015 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6018 * Ext JS Library 1.1.1
6019 * Copyright(c) 2006-2007, Ext JS, LLC.
6021 * Originally Released Under LGPL - original licence link has changed is not relivant.
6024 * <script type="text/javascript">
6028 * @class Roo.LoadMask
6029 * A simple utility class for generically masking elements while loading data. If the element being masked has
6030 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6031 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6032 * element's UpdateManager load indicator and will be destroyed after the initial load.
6034 * Create a new LoadMask
6035 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6036 * @param {Object} config The config object
6038 Roo.LoadMask = function(el, config){
6039 this.el = Roo.get(el);
6040 Roo.apply(this, config);
6042 this.store.on('beforeload', this.onBeforeLoad, this);
6043 this.store.on('load', this.onLoad, this);
6044 this.store.on('loadexception', this.onLoadException, this);
6045 this.removeMask = false;
6047 var um = this.el.getUpdateManager();
6048 um.showLoadIndicator = false; // disable the default indicator
6049 um.on('beforeupdate', this.onBeforeLoad, this);
6050 um.on('update', this.onLoad, this);
6051 um.on('failure', this.onLoad, this);
6052 this.removeMask = true;
6056 Roo.LoadMask.prototype = {
6058 * @cfg {Boolean} removeMask
6059 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6060 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6064 * The text to display in a centered loading message box (defaults to 'Loading...')
6068 * @cfg {String} msgCls
6069 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6071 msgCls : 'x-mask-loading',
6074 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6080 * Disables the mask to prevent it from being displayed
6082 disable : function(){
6083 this.disabled = true;
6087 * Enables the mask so that it can be displayed
6089 enable : function(){
6090 this.disabled = false;
6093 onLoadException : function()
6097 if (typeof(arguments[3]) != 'undefined') {
6098 Roo.MessageBox.alert("Error loading",arguments[3]);
6102 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6103 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6110 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6115 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6119 onBeforeLoad : function(){
6121 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6126 destroy : function(){
6128 this.store.un('beforeload', this.onBeforeLoad, this);
6129 this.store.un('load', this.onLoad, this);
6130 this.store.un('loadexception', this.onLoadException, this);
6132 var um = this.el.getUpdateManager();
6133 um.un('beforeupdate', this.onBeforeLoad, this);
6134 um.un('update', this.onLoad, this);
6135 um.un('failure', this.onLoad, this);
6146 * @class Roo.bootstrap.Table
6147 * @extends Roo.bootstrap.Component
6148 * Bootstrap Table class
6149 * @cfg {String} cls table class
6150 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6151 * @cfg {String} bgcolor Specifies the background color for a table
6152 * @cfg {Number} border Specifies whether the table cells should have borders or not
6153 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6154 * @cfg {Number} cellspacing Specifies the space between cells
6155 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6156 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6157 * @cfg {String} sortable Specifies that the table should be sortable
6158 * @cfg {String} summary Specifies a summary of the content of a table
6159 * @cfg {Number} width Specifies the width of a table
6160 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6162 * @cfg {boolean} striped Should the rows be alternative striped
6163 * @cfg {boolean} bordered Add borders to the table
6164 * @cfg {boolean} hover Add hover highlighting
6165 * @cfg {boolean} condensed Format condensed
6166 * @cfg {boolean} responsive Format condensed
6167 * @cfg {Boolean} loadMask (true|false) default false
6168 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6169 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6170 * @cfg {Boolean} rowSelection (true|false) default false
6171 * @cfg {Boolean} cellSelection (true|false) default false
6172 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6173 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6174 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6175 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6179 * Create a new Table
6180 * @param {Object} config The config object
6183 Roo.bootstrap.Table = function(config){
6184 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6189 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6190 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6191 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6192 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6194 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6196 this.sm.grid = this;
6197 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6198 this.sm = this.selModel;
6199 this.sm.xmodule = this.xmodule || false;
6202 if (this.cm && typeof(this.cm.config) == 'undefined') {
6203 this.colModel = new Roo.grid.ColumnModel(this.cm);
6204 this.cm = this.colModel;
6205 this.cm.xmodule = this.xmodule || false;
6208 this.store= Roo.factory(this.store, Roo.data);
6209 this.ds = this.store;
6210 this.ds.xmodule = this.xmodule || false;
6213 if (this.footer && this.store) {
6214 this.footer.dataSource = this.ds;
6215 this.footer = Roo.factory(this.footer);
6222 * Fires when a cell is clicked
6223 * @param {Roo.bootstrap.Table} this
6224 * @param {Roo.Element} el
6225 * @param {Number} rowIndex
6226 * @param {Number} columnIndex
6227 * @param {Roo.EventObject} e
6231 * @event celldblclick
6232 * Fires when a cell is double clicked
6233 * @param {Roo.bootstrap.Table} this
6234 * @param {Roo.Element} el
6235 * @param {Number} rowIndex
6236 * @param {Number} columnIndex
6237 * @param {Roo.EventObject} e
6239 "celldblclick" : true,
6242 * Fires when a row is clicked
6243 * @param {Roo.bootstrap.Table} this
6244 * @param {Roo.Element} el
6245 * @param {Number} rowIndex
6246 * @param {Roo.EventObject} e
6250 * @event rowdblclick
6251 * Fires when a row is double clicked
6252 * @param {Roo.bootstrap.Table} this
6253 * @param {Roo.Element} el
6254 * @param {Number} rowIndex
6255 * @param {Roo.EventObject} e
6257 "rowdblclick" : true,
6260 * Fires when a mouseover occur
6261 * @param {Roo.bootstrap.Table} this
6262 * @param {Roo.Element} el
6263 * @param {Number} rowIndex
6264 * @param {Number} columnIndex
6265 * @param {Roo.EventObject} e
6270 * Fires when a mouseout occur
6271 * @param {Roo.bootstrap.Table} this
6272 * @param {Roo.Element} el
6273 * @param {Number} rowIndex
6274 * @param {Number} columnIndex
6275 * @param {Roo.EventObject} e
6280 * Fires when a row is rendered, so you can change add a style to it.
6281 * @param {Roo.bootstrap.Table} this
6282 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6286 * @event rowsrendered
6287 * Fires when all the rows have been rendered
6288 * @param {Roo.bootstrap.Table} this
6290 'rowsrendered' : true,
6292 * @event contextmenu
6293 * The raw contextmenu event for the entire grid.
6294 * @param {Roo.EventObject} e
6296 "contextmenu" : true,
6298 * @event rowcontextmenu
6299 * Fires when a row is right clicked
6300 * @param {Roo.bootstrap.Table} this
6301 * @param {Number} rowIndex
6302 * @param {Roo.EventObject} e
6304 "rowcontextmenu" : true,
6306 * @event cellcontextmenu
6307 * Fires when a cell is right clicked
6308 * @param {Roo.bootstrap.Table} this
6309 * @param {Number} rowIndex
6310 * @param {Number} cellIndex
6311 * @param {Roo.EventObject} e
6313 "cellcontextmenu" : true,
6315 * @event headercontextmenu
6316 * Fires when a header is right clicked
6317 * @param {Roo.bootstrap.Table} this
6318 * @param {Number} columnIndex
6319 * @param {Roo.EventObject} e
6321 "headercontextmenu" : true
6325 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6351 rowSelection : false,
6352 cellSelection : false,
6355 // Roo.Element - the tbody
6357 // Roo.Element - thead element
6360 container: false, // used by gridpanel...
6366 auto_hide_footer : false,
6368 getAutoCreate : function()
6370 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6377 if (this.scrollBody) {
6378 cfg.cls += ' table-body-fixed';
6381 cfg.cls += ' table-striped';
6385 cfg.cls += ' table-hover';
6387 if (this.bordered) {
6388 cfg.cls += ' table-bordered';
6390 if (this.condensed) {
6391 cfg.cls += ' table-condensed';
6393 if (this.responsive) {
6394 cfg.cls += ' table-responsive';
6398 cfg.cls+= ' ' +this.cls;
6401 // this lot should be simplifed...
6414 ].forEach(function(k) {
6422 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6425 if(this.store || this.cm){
6426 if(this.headerShow){
6427 cfg.cn.push(this.renderHeader());
6430 cfg.cn.push(this.renderBody());
6432 if(this.footerShow){
6433 cfg.cn.push(this.renderFooter());
6435 // where does this come from?
6436 //cfg.cls+= ' TableGrid';
6439 return { cn : [ cfg ] };
6442 initEvents : function()
6444 if(!this.store || !this.cm){
6447 if (this.selModel) {
6448 this.selModel.initEvents();
6452 //Roo.log('initEvents with ds!!!!');
6454 this.mainBody = this.el.select('tbody', true).first();
6455 this.mainHead = this.el.select('thead', true).first();
6456 this.mainFoot = this.el.select('tfoot', true).first();
6462 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6463 e.on('click', _this.sort, _this);
6466 this.mainBody.on("click", this.onClick, this);
6467 this.mainBody.on("dblclick", this.onDblClick, this);
6469 // why is this done????? = it breaks dialogs??
6470 //this.parent().el.setStyle('position', 'relative');
6474 this.footer.parentId = this.id;
6475 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6478 this.el.select('tfoot tr td').first().addClass('hide');
6483 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6486 this.store.on('load', this.onLoad, this);
6487 this.store.on('beforeload', this.onBeforeLoad, this);
6488 this.store.on('update', this.onUpdate, this);
6489 this.store.on('add', this.onAdd, this);
6490 this.store.on("clear", this.clear, this);
6492 this.el.on("contextmenu", this.onContextMenu, this);
6494 this.mainBody.on('scroll', this.onBodyScroll, this);
6496 this.cm.on("headerchange", this.onHeaderChange, this);
6498 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6502 onContextMenu : function(e, t)
6504 this.processEvent("contextmenu", e);
6507 processEvent : function(name, e)
6509 if (name != 'touchstart' ) {
6510 this.fireEvent(name, e);
6513 var t = e.getTarget();
6515 var cell = Roo.get(t);
6521 if(cell.findParent('tfoot', false, true)){
6525 if(cell.findParent('thead', false, true)){
6527 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6528 cell = Roo.get(t).findParent('th', false, true);
6530 Roo.log("failed to find th in thead?");
6531 Roo.log(e.getTarget());
6536 var cellIndex = cell.dom.cellIndex;
6538 var ename = name == 'touchstart' ? 'click' : name;
6539 this.fireEvent("header" + ename, this, cellIndex, e);
6544 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6545 cell = Roo.get(t).findParent('td', false, true);
6547 Roo.log("failed to find th in tbody?");
6548 Roo.log(e.getTarget());
6553 var row = cell.findParent('tr', false, true);
6554 var cellIndex = cell.dom.cellIndex;
6555 var rowIndex = row.dom.rowIndex - 1;
6559 this.fireEvent("row" + name, this, rowIndex, e);
6563 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6569 onMouseover : function(e, el)
6571 var cell = Roo.get(el);
6577 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6578 cell = cell.findParent('td', false, true);
6581 var row = cell.findParent('tr', false, true);
6582 var cellIndex = cell.dom.cellIndex;
6583 var rowIndex = row.dom.rowIndex - 1; // start from 0
6585 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6589 onMouseout : function(e, el)
6591 var cell = Roo.get(el);
6597 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6598 cell = cell.findParent('td', false, true);
6601 var row = cell.findParent('tr', false, true);
6602 var cellIndex = cell.dom.cellIndex;
6603 var rowIndex = row.dom.rowIndex - 1; // start from 0
6605 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6609 onClick : function(e, el)
6611 var cell = Roo.get(el);
6613 if(!cell || (!this.cellSelection && !this.rowSelection)){
6617 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6618 cell = cell.findParent('td', false, true);
6621 if(!cell || typeof(cell) == 'undefined'){
6625 var row = cell.findParent('tr', false, true);
6627 if(!row || typeof(row) == 'undefined'){
6631 var cellIndex = cell.dom.cellIndex;
6632 var rowIndex = this.getRowIndex(row);
6634 // why??? - should these not be based on SelectionModel?
6635 if(this.cellSelection){
6636 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6639 if(this.rowSelection){
6640 this.fireEvent('rowclick', this, row, rowIndex, e);
6646 onDblClick : function(e,el)
6648 var cell = Roo.get(el);
6650 if(!cell || (!this.cellSelection && !this.rowSelection)){
6654 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6655 cell = cell.findParent('td', false, true);
6658 if(!cell || typeof(cell) == 'undefined'){
6662 var row = cell.findParent('tr', false, true);
6664 if(!row || typeof(row) == 'undefined'){
6668 var cellIndex = cell.dom.cellIndex;
6669 var rowIndex = this.getRowIndex(row);
6671 if(this.cellSelection){
6672 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6675 if(this.rowSelection){
6676 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6680 sort : function(e,el)
6682 var col = Roo.get(el);
6684 if(!col.hasClass('sortable')){
6688 var sort = col.attr('sort');
6691 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6695 this.store.sortInfo = {field : sort, direction : dir};
6698 Roo.log("calling footer first");
6699 this.footer.onClick('first');
6702 this.store.load({ params : { start : 0 } });
6706 renderHeader : function()
6714 this.totalWidth = 0;
6716 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6718 var config = cm.config[i];
6722 cls : 'x-hcol-' + i,
6724 html: cm.getColumnHeader(i)
6729 if(typeof(config.sortable) != 'undefined' && config.sortable){
6731 c.html = '<i class="glyphicon"></i>' + c.html;
6734 if(typeof(config.lgHeader) != 'undefined'){
6735 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6738 if(typeof(config.mdHeader) != 'undefined'){
6739 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6742 if(typeof(config.smHeader) != 'undefined'){
6743 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6746 if(typeof(config.xsHeader) != 'undefined'){
6747 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6754 if(typeof(config.tooltip) != 'undefined'){
6755 c.tooltip = config.tooltip;
6758 if(typeof(config.colspan) != 'undefined'){
6759 c.colspan = config.colspan;
6762 if(typeof(config.hidden) != 'undefined' && config.hidden){
6763 c.style += ' display:none;';
6766 if(typeof(config.dataIndex) != 'undefined'){
6767 c.sort = config.dataIndex;
6772 if(typeof(config.align) != 'undefined' && config.align.length){
6773 c.style += ' text-align:' + config.align + ';';
6776 if(typeof(config.width) != 'undefined'){
6777 c.style += ' width:' + config.width + 'px;';
6778 this.totalWidth += config.width;
6780 this.totalWidth += 100; // assume minimum of 100 per column?
6783 if(typeof(config.cls) != 'undefined'){
6784 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6787 ['xs','sm','md','lg'].map(function(size){
6789 if(typeof(config[size]) == 'undefined'){
6793 if (!config[size]) { // 0 = hidden
6794 c.cls += ' hidden-' + size;
6798 c.cls += ' col-' + size + '-' + config[size];
6808 renderBody : function()
6818 colspan : this.cm.getColumnCount()
6828 renderFooter : function()
6838 colspan : this.cm.getColumnCount()
6852 // Roo.log('ds onload');
6857 var ds = this.store;
6859 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6860 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6861 if (_this.store.sortInfo) {
6863 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6864 e.select('i', true).addClass(['glyphicon-arrow-up']);
6867 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6868 e.select('i', true).addClass(['glyphicon-arrow-down']);
6873 var tbody = this.mainBody;
6875 if(ds.getCount() > 0){
6876 ds.data.each(function(d,rowIndex){
6877 var row = this.renderRow(cm, ds, rowIndex);
6879 tbody.createChild(row);
6883 if(row.cellObjects.length){
6884 Roo.each(row.cellObjects, function(r){
6885 _this.renderCellObject(r);
6892 var tfoot = this.el.select('tfoot', true).first();
6894 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6896 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6898 var total = this.ds.getTotalCount();
6900 if(this.footer.pageSize < total){
6901 this.mainFoot.show();
6905 Roo.each(this.el.select('tbody td', true).elements, function(e){
6906 e.on('mouseover', _this.onMouseover, _this);
6909 Roo.each(this.el.select('tbody td', true).elements, function(e){
6910 e.on('mouseout', _this.onMouseout, _this);
6912 this.fireEvent('rowsrendered', this);
6918 onUpdate : function(ds,record)
6920 this.refreshRow(record);
6924 onRemove : function(ds, record, index, isUpdate){
6925 if(isUpdate !== true){
6926 this.fireEvent("beforerowremoved", this, index, record);
6928 var bt = this.mainBody.dom;
6930 var rows = this.el.select('tbody > tr', true).elements;
6932 if(typeof(rows[index]) != 'undefined'){
6933 bt.removeChild(rows[index].dom);
6936 // if(bt.rows[index]){
6937 // bt.removeChild(bt.rows[index]);
6940 if(isUpdate !== true){
6941 //this.stripeRows(index);
6942 //this.syncRowHeights(index, index);
6944 this.fireEvent("rowremoved", this, index, record);
6948 onAdd : function(ds, records, rowIndex)
6950 //Roo.log('on Add called');
6951 // - note this does not handle multiple adding very well..
6952 var bt = this.mainBody.dom;
6953 for (var i =0 ; i < records.length;i++) {
6954 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6955 //Roo.log(records[i]);
6956 //Roo.log(this.store.getAt(rowIndex+i));
6957 this.insertRow(this.store, rowIndex + i, false);
6964 refreshRow : function(record){
6965 var ds = this.store, index;
6966 if(typeof record == 'number'){
6968 record = ds.getAt(index);
6970 index = ds.indexOf(record);
6972 this.insertRow(ds, index, true);
6974 this.onRemove(ds, record, index+1, true);
6976 //this.syncRowHeights(index, index);
6978 this.fireEvent("rowupdated", this, index, record);
6981 insertRow : function(dm, rowIndex, isUpdate){
6984 this.fireEvent("beforerowsinserted", this, rowIndex);
6986 //var s = this.getScrollState();
6987 var row = this.renderRow(this.cm, this.store, rowIndex);
6988 // insert before rowIndex..
6989 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
6993 if(row.cellObjects.length){
6994 Roo.each(row.cellObjects, function(r){
6995 _this.renderCellObject(r);
7000 this.fireEvent("rowsinserted", this, rowIndex);
7001 //this.syncRowHeights(firstRow, lastRow);
7002 //this.stripeRows(firstRow);
7009 getRowDom : function(rowIndex)
7011 var rows = this.el.select('tbody > tr', true).elements;
7013 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7016 // returns the object tree for a tr..
7019 renderRow : function(cm, ds, rowIndex)
7021 var d = ds.getAt(rowIndex);
7025 cls : 'x-row-' + rowIndex,
7029 var cellObjects = [];
7031 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7032 var config = cm.config[i];
7034 var renderer = cm.getRenderer(i);
7038 if(typeof(renderer) !== 'undefined'){
7039 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7041 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7042 // and are rendered into the cells after the row is rendered - using the id for the element.
7044 if(typeof(value) === 'object'){
7054 rowIndex : rowIndex,
7059 this.fireEvent('rowclass', this, rowcfg);
7063 cls : rowcfg.rowClass + ' x-col-' + i,
7065 html: (typeof(value) === 'object') ? '' : value
7072 if(typeof(config.colspan) != 'undefined'){
7073 td.colspan = config.colspan;
7076 if(typeof(config.hidden) != 'undefined' && config.hidden){
7077 td.style += ' display:none;';
7080 if(typeof(config.align) != 'undefined' && config.align.length){
7081 td.style += ' text-align:' + config.align + ';';
7083 if(typeof(config.valign) != 'undefined' && config.valign.length){
7084 td.style += ' vertical-align:' + config.valign + ';';
7087 if(typeof(config.width) != 'undefined'){
7088 td.style += ' width:' + config.width + 'px;';
7091 if(typeof(config.cursor) != 'undefined'){
7092 td.style += ' cursor:' + config.cursor + ';';
7095 if(typeof(config.cls) != 'undefined'){
7096 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7099 ['xs','sm','md','lg'].map(function(size){
7101 if(typeof(config[size]) == 'undefined'){
7105 if (!config[size]) { // 0 = hidden
7106 td.cls += ' hidden-' + size;
7110 td.cls += ' col-' + size + '-' + config[size];
7118 row.cellObjects = cellObjects;
7126 onBeforeLoad : function()
7135 this.el.select('tbody', true).first().dom.innerHTML = '';
7138 * Show or hide a row.
7139 * @param {Number} rowIndex to show or hide
7140 * @param {Boolean} state hide
7142 setRowVisibility : function(rowIndex, state)
7144 var bt = this.mainBody.dom;
7146 var rows = this.el.select('tbody > tr', true).elements;
7148 if(typeof(rows[rowIndex]) == 'undefined'){
7151 rows[rowIndex].dom.style.display = state ? '' : 'none';
7155 getSelectionModel : function(){
7157 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7159 return this.selModel;
7162 * Render the Roo.bootstrap object from renderder
7164 renderCellObject : function(r)
7168 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7170 var t = r.cfg.render(r.container);
7173 Roo.each(r.cfg.cn, function(c){
7175 container: t.getChildContainer(),
7178 _this.renderCellObject(child);
7183 getRowIndex : function(row)
7187 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7198 * Returns the grid's underlying element = used by panel.Grid
7199 * @return {Element} The element
7201 getGridEl : function(){
7205 * Forces a resize - used by panel.Grid
7206 * @return {Element} The element
7208 autoSize : function()
7210 //var ctr = Roo.get(this.container.dom.parentElement);
7211 var ctr = Roo.get(this.el.dom);
7213 var thd = this.getGridEl().select('thead',true).first();
7214 var tbd = this.getGridEl().select('tbody', true).first();
7215 var tfd = this.getGridEl().select('tfoot', true).first();
7217 var cw = ctr.getWidth();
7221 tbd.setSize(ctr.getWidth(),
7222 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7224 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7227 cw = Math.max(cw, this.totalWidth);
7228 this.getGridEl().select('tr',true).setWidth(cw);
7229 // resize 'expandable coloumn?
7231 return; // we doe not have a view in this design..
7234 onBodyScroll: function()
7236 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7238 this.mainHead.setStyle({
7239 'position' : 'relative',
7240 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7246 var scrollHeight = this.mainBody.dom.scrollHeight;
7248 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7250 var height = this.mainBody.getHeight();
7252 if(scrollHeight - height == scrollTop) {
7254 var total = this.ds.getTotalCount();
7256 if(this.footer.cursor + this.footer.pageSize < total){
7258 this.footer.ds.load({
7260 start : this.footer.cursor + this.footer.pageSize,
7261 limit : this.footer.pageSize
7271 onHeaderChange : function()
7273 var header = this.renderHeader();
7274 var table = this.el.select('table', true).first();
7276 this.mainHead.remove();
7277 this.mainHead = table.createChild(header, this.mainBody, false);
7280 onHiddenChange : function(colModel, colIndex, hidden)
7282 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7283 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7285 this.CSS.updateRule(thSelector, "display", "");
7286 this.CSS.updateRule(tdSelector, "display", "");
7289 this.CSS.updateRule(thSelector, "display", "none");
7290 this.CSS.updateRule(tdSelector, "display", "none");
7293 this.onHeaderChange();
7297 setColumnWidth: function(col_index, width)
7299 // width = "md-2 xs-2..."
7300 if(!this.colModel.config[col_index]) {
7304 var w = width.split(" ");
7306 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7308 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7311 for(var j = 0; j < w.length; j++) {
7317 var size_cls = w[j].split("-");
7319 if(!Number.isInteger(size_cls[1] * 1)) {
7323 if(!this.colModel.config[col_index][size_cls[0]]) {
7327 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7331 h_row[0].classList.replace(
7332 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7333 "col-"+size_cls[0]+"-"+size_cls[1]
7336 for(var i = 0; i < rows.length; i++) {
7338 var size_cls = w[j].split("-");
7340 if(!Number.isInteger(size_cls[1] * 1)) {
7344 if(!this.colModel.config[col_index][size_cls[0]]) {
7348 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7352 rows[i].classList.replace(
7353 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7354 "col-"+size_cls[0]+"-"+size_cls[1]
7358 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7373 * @class Roo.bootstrap.TableCell
7374 * @extends Roo.bootstrap.Component
7375 * Bootstrap TableCell class
7376 * @cfg {String} html cell contain text
7377 * @cfg {String} cls cell class
7378 * @cfg {String} tag cell tag (td|th) default td
7379 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7380 * @cfg {String} align Aligns the content in a cell
7381 * @cfg {String} axis Categorizes cells
7382 * @cfg {String} bgcolor Specifies the background color of a cell
7383 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7384 * @cfg {Number} colspan Specifies the number of columns a cell should span
7385 * @cfg {String} headers Specifies one or more header cells a cell is related to
7386 * @cfg {Number} height Sets the height of a cell
7387 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7388 * @cfg {Number} rowspan Sets the number of rows a cell should span
7389 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7390 * @cfg {String} valign Vertical aligns the content in a cell
7391 * @cfg {Number} width Specifies the width of a cell
7394 * Create a new TableCell
7395 * @param {Object} config The config object
7398 Roo.bootstrap.TableCell = function(config){
7399 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7402 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7422 getAutoCreate : function(){
7423 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7443 cfg.align=this.align
7449 cfg.bgcolor=this.bgcolor
7452 cfg.charoff=this.charoff
7455 cfg.colspan=this.colspan
7458 cfg.headers=this.headers
7461 cfg.height=this.height
7464 cfg.nowrap=this.nowrap
7467 cfg.rowspan=this.rowspan
7470 cfg.scope=this.scope
7473 cfg.valign=this.valign
7476 cfg.width=this.width
7495 * @class Roo.bootstrap.TableRow
7496 * @extends Roo.bootstrap.Component
7497 * Bootstrap TableRow class
7498 * @cfg {String} cls row class
7499 * @cfg {String} align Aligns the content in a table row
7500 * @cfg {String} bgcolor Specifies a background color for a table row
7501 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7502 * @cfg {String} valign Vertical aligns the content in a table row
7505 * Create a new TableRow
7506 * @param {Object} config The config object
7509 Roo.bootstrap.TableRow = function(config){
7510 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7513 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7521 getAutoCreate : function(){
7522 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7532 cfg.align = this.align;
7535 cfg.bgcolor = this.bgcolor;
7538 cfg.charoff = this.charoff;
7541 cfg.valign = this.valign;
7559 * @class Roo.bootstrap.TableBody
7560 * @extends Roo.bootstrap.Component
7561 * Bootstrap TableBody class
7562 * @cfg {String} cls element class
7563 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7564 * @cfg {String} align Aligns the content inside the element
7565 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7566 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7569 * Create a new TableBody
7570 * @param {Object} config The config object
7573 Roo.bootstrap.TableBody = function(config){
7574 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7577 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7585 getAutoCreate : function(){
7586 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7600 cfg.align = this.align;
7603 cfg.charoff = this.charoff;
7606 cfg.valign = this.valign;
7613 // initEvents : function()
7620 // this.store = Roo.factory(this.store, Roo.data);
7621 // this.store.on('load', this.onLoad, this);
7623 // this.store.load();
7627 // onLoad: function ()
7629 // this.fireEvent('load', this);
7639 * Ext JS Library 1.1.1
7640 * Copyright(c) 2006-2007, Ext JS, LLC.
7642 * Originally Released Under LGPL - original licence link has changed is not relivant.
7645 * <script type="text/javascript">
7648 // as we use this in bootstrap.
7649 Roo.namespace('Roo.form');
7651 * @class Roo.form.Action
7652 * Internal Class used to handle form actions
7654 * @param {Roo.form.BasicForm} el The form element or its id
7655 * @param {Object} config Configuration options
7660 // define the action interface
7661 Roo.form.Action = function(form, options){
7663 this.options = options || {};
7666 * Client Validation Failed
7669 Roo.form.Action.CLIENT_INVALID = 'client';
7671 * Server Validation Failed
7674 Roo.form.Action.SERVER_INVALID = 'server';
7676 * Connect to Server Failed
7679 Roo.form.Action.CONNECT_FAILURE = 'connect';
7681 * Reading Data from Server Failed
7684 Roo.form.Action.LOAD_FAILURE = 'load';
7686 Roo.form.Action.prototype = {
7688 failureType : undefined,
7689 response : undefined,
7693 run : function(options){
7698 success : function(response){
7703 handleResponse : function(response){
7707 // default connection failure
7708 failure : function(response){
7710 this.response = response;
7711 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7712 this.form.afterAction(this, false);
7715 processResponse : function(response){
7716 this.response = response;
7717 if(!response.responseText){
7720 this.result = this.handleResponse(response);
7724 // utility functions used internally
7725 getUrl : function(appendParams){
7726 var url = this.options.url || this.form.url || this.form.el.dom.action;
7728 var p = this.getParams();
7730 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7736 getMethod : function(){
7737 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7740 getParams : function(){
7741 var bp = this.form.baseParams;
7742 var p = this.options.params;
7744 if(typeof p == "object"){
7745 p = Roo.urlEncode(Roo.applyIf(p, bp));
7746 }else if(typeof p == 'string' && bp){
7747 p += '&' + Roo.urlEncode(bp);
7750 p = Roo.urlEncode(bp);
7755 createCallback : function(){
7757 success: this.success,
7758 failure: this.failure,
7760 timeout: (this.form.timeout*1000),
7761 upload: this.form.fileUpload ? this.success : undefined
7766 Roo.form.Action.Submit = function(form, options){
7767 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7770 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7773 haveProgress : false,
7774 uploadComplete : false,
7776 // uploadProgress indicator.
7777 uploadProgress : function()
7779 if (!this.form.progressUrl) {
7783 if (!this.haveProgress) {
7784 Roo.MessageBox.progress("Uploading", "Uploading");
7786 if (this.uploadComplete) {
7787 Roo.MessageBox.hide();
7791 this.haveProgress = true;
7793 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7795 var c = new Roo.data.Connection();
7797 url : this.form.progressUrl,
7802 success : function(req){
7803 //console.log(data);
7807 rdata = Roo.decode(req.responseText)
7809 Roo.log("Invalid data from server..");
7813 if (!rdata || !rdata.success) {
7815 Roo.MessageBox.alert(Roo.encode(rdata));
7818 var data = rdata.data;
7820 if (this.uploadComplete) {
7821 Roo.MessageBox.hide();
7826 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7827 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7830 this.uploadProgress.defer(2000,this);
7833 failure: function(data) {
7834 Roo.log('progress url failed ');
7845 // run get Values on the form, so it syncs any secondary forms.
7846 this.form.getValues();
7848 var o = this.options;
7849 var method = this.getMethod();
7850 var isPost = method == 'POST';
7851 if(o.clientValidation === false || this.form.isValid()){
7853 if (this.form.progressUrl) {
7854 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7855 (new Date() * 1) + '' + Math.random());
7860 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7861 form:this.form.el.dom,
7862 url:this.getUrl(!isPost),
7864 params:isPost ? this.getParams() : null,
7865 isUpload: this.form.fileUpload
7868 this.uploadProgress();
7870 }else if (o.clientValidation !== false){ // client validation failed
7871 this.failureType = Roo.form.Action.CLIENT_INVALID;
7872 this.form.afterAction(this, false);
7876 success : function(response)
7878 this.uploadComplete= true;
7879 if (this.haveProgress) {
7880 Roo.MessageBox.hide();
7884 var result = this.processResponse(response);
7885 if(result === true || result.success){
7886 this.form.afterAction(this, true);
7890 this.form.markInvalid(result.errors);
7891 this.failureType = Roo.form.Action.SERVER_INVALID;
7893 this.form.afterAction(this, false);
7895 failure : function(response)
7897 this.uploadComplete= true;
7898 if (this.haveProgress) {
7899 Roo.MessageBox.hide();
7902 this.response = response;
7903 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7904 this.form.afterAction(this, false);
7907 handleResponse : function(response){
7908 if(this.form.errorReader){
7909 var rs = this.form.errorReader.read(response);
7912 for(var i = 0, len = rs.records.length; i < len; i++) {
7913 var r = rs.records[i];
7917 if(errors.length < 1){
7921 success : rs.success,
7927 ret = Roo.decode(response.responseText);
7931 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7941 Roo.form.Action.Load = function(form, options){
7942 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7943 this.reader = this.form.reader;
7946 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7951 Roo.Ajax.request(Roo.apply(
7952 this.createCallback(), {
7953 method:this.getMethod(),
7954 url:this.getUrl(false),
7955 params:this.getParams()
7959 success : function(response){
7961 var result = this.processResponse(response);
7962 if(result === true || !result.success || !result.data){
7963 this.failureType = Roo.form.Action.LOAD_FAILURE;
7964 this.form.afterAction(this, false);
7967 this.form.clearInvalid();
7968 this.form.setValues(result.data);
7969 this.form.afterAction(this, true);
7972 handleResponse : function(response){
7973 if(this.form.reader){
7974 var rs = this.form.reader.read(response);
7975 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
7977 success : rs.success,
7981 return Roo.decode(response.responseText);
7985 Roo.form.Action.ACTION_TYPES = {
7986 'load' : Roo.form.Action.Load,
7987 'submit' : Roo.form.Action.Submit
7996 * @class Roo.bootstrap.Form
7997 * @extends Roo.bootstrap.Component
7998 * Bootstrap Form class
7999 * @cfg {String} method GET | POST (default POST)
8000 * @cfg {String} labelAlign top | left (default top)
8001 * @cfg {String} align left | right - for navbars
8002 * @cfg {Boolean} loadMask load mask when submit (default true)
8007 * @param {Object} config The config object
8011 Roo.bootstrap.Form = function(config){
8013 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8015 Roo.bootstrap.Form.popover.apply();
8019 * @event clientvalidation
8020 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8021 * @param {Form} this
8022 * @param {Boolean} valid true if the form has passed client-side validation
8024 clientvalidation: true,
8026 * @event beforeaction
8027 * Fires before any action is performed. Return false to cancel the action.
8028 * @param {Form} this
8029 * @param {Action} action The action to be performed
8033 * @event actionfailed
8034 * Fires when an action fails.
8035 * @param {Form} this
8036 * @param {Action} action The action that failed
8038 actionfailed : true,
8040 * @event actioncomplete
8041 * Fires when an action is completed.
8042 * @param {Form} this
8043 * @param {Action} action The action that completed
8045 actioncomplete : true
8049 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8052 * @cfg {String} method
8053 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8058 * The URL to use for form actions if one isn't supplied in the action options.
8061 * @cfg {Boolean} fileUpload
8062 * Set to true if this form is a file upload.
8066 * @cfg {Object} baseParams
8067 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8071 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8075 * @cfg {Sting} align (left|right) for navbar forms
8080 activeAction : null,
8083 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8084 * element by passing it or its id or mask the form itself by passing in true.
8087 waitMsgTarget : false,
8092 * @cfg {Boolean} errorMask (true|false) default false
8097 * @cfg {Number} maskOffset Default 100
8102 * @cfg {Boolean} maskBody
8106 getAutoCreate : function(){
8110 method : this.method || 'POST',
8111 id : this.id || Roo.id(),
8114 if (this.parent().xtype.match(/^Nav/)) {
8115 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8119 if (this.labelAlign == 'left' ) {
8120 cfg.cls += ' form-horizontal';
8126 initEvents : function()
8128 this.el.on('submit', this.onSubmit, this);
8129 // this was added as random key presses on the form where triggering form submit.
8130 this.el.on('keypress', function(e) {
8131 if (e.getCharCode() != 13) {
8134 // we might need to allow it for textareas.. and some other items.
8135 // check e.getTarget().
8137 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8141 Roo.log("keypress blocked");
8149 onSubmit : function(e){
8154 * Returns true if client-side validation on the form is successful.
8157 isValid : function(){
8158 var items = this.getItems();
8162 items.each(function(f){
8168 Roo.log('invalid field: ' + f.name);
8172 if(!target && f.el.isVisible(true)){
8178 if(this.errorMask && !valid){
8179 Roo.bootstrap.Form.popover.mask(this, target);
8186 * Returns true if any fields in this form have changed since their original load.
8189 isDirty : function(){
8191 var items = this.getItems();
8192 items.each(function(f){
8202 * Performs a predefined action (submit or load) or custom actions you define on this form.
8203 * @param {String} actionName The name of the action type
8204 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8205 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8206 * accept other config options):
8208 Property Type Description
8209 ---------------- --------------- ----------------------------------------------------------------------------------
8210 url String The url for the action (defaults to the form's url)
8211 method String The form method to use (defaults to the form's method, or POST if not defined)
8212 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8213 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8214 validate the form on the client (defaults to false)
8216 * @return {BasicForm} this
8218 doAction : function(action, options){
8219 if(typeof action == 'string'){
8220 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8222 if(this.fireEvent('beforeaction', this, action) !== false){
8223 this.beforeAction(action);
8224 action.run.defer(100, action);
8230 beforeAction : function(action){
8231 var o = action.options;
8236 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8238 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8241 // not really supported yet.. ??
8243 //if(this.waitMsgTarget === true){
8244 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8245 //}else if(this.waitMsgTarget){
8246 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8247 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8249 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8255 afterAction : function(action, success){
8256 this.activeAction = null;
8257 var o = action.options;
8262 Roo.get(document.body).unmask();
8268 //if(this.waitMsgTarget === true){
8269 // this.el.unmask();
8270 //}else if(this.waitMsgTarget){
8271 // this.waitMsgTarget.unmask();
8273 // Roo.MessageBox.updateProgress(1);
8274 // Roo.MessageBox.hide();
8281 Roo.callback(o.success, o.scope, [this, action]);
8282 this.fireEvent('actioncomplete', this, action);
8286 // failure condition..
8287 // we have a scenario where updates need confirming.
8288 // eg. if a locking scenario exists..
8289 // we look for { errors : { needs_confirm : true }} in the response.
8291 (typeof(action.result) != 'undefined') &&
8292 (typeof(action.result.errors) != 'undefined') &&
8293 (typeof(action.result.errors.needs_confirm) != 'undefined')
8296 Roo.log("not supported yet");
8299 Roo.MessageBox.confirm(
8300 "Change requires confirmation",
8301 action.result.errorMsg,
8306 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8316 Roo.callback(o.failure, o.scope, [this, action]);
8317 // show an error message if no failed handler is set..
8318 if (!this.hasListener('actionfailed')) {
8319 Roo.log("need to add dialog support");
8321 Roo.MessageBox.alert("Error",
8322 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8323 action.result.errorMsg :
8324 "Saving Failed, please check your entries or try again"
8329 this.fireEvent('actionfailed', this, action);
8334 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8335 * @param {String} id The value to search for
8338 findField : function(id){
8339 var items = this.getItems();
8340 var field = items.get(id);
8342 items.each(function(f){
8343 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8350 return field || null;
8353 * Mark fields in this form invalid in bulk.
8354 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8355 * @return {BasicForm} this
8357 markInvalid : function(errors){
8358 if(errors instanceof Array){
8359 for(var i = 0, len = errors.length; i < len; i++){
8360 var fieldError = errors[i];
8361 var f = this.findField(fieldError.id);
8363 f.markInvalid(fieldError.msg);
8369 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8370 field.markInvalid(errors[id]);
8374 //Roo.each(this.childForms || [], function (f) {
8375 // f.markInvalid(errors);
8382 * Set values for fields in this form in bulk.
8383 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8384 * @return {BasicForm} this
8386 setValues : function(values){
8387 if(values instanceof Array){ // array of objects
8388 for(var i = 0, len = values.length; i < len; i++){
8390 var f = this.findField(v.id);
8392 f.setValue(v.value);
8393 if(this.trackResetOnLoad){
8394 f.originalValue = f.getValue();
8398 }else{ // object hash
8401 if(typeof values[id] != 'function' && (field = this.findField(id))){
8403 if (field.setFromData &&
8405 field.displayField &&
8406 // combos' with local stores can
8407 // be queried via setValue()
8408 // to set their value..
8409 (field.store && !field.store.isLocal)
8413 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8414 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8415 field.setFromData(sd);
8417 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8419 field.setFromData(values);
8422 field.setValue(values[id]);
8426 if(this.trackResetOnLoad){
8427 field.originalValue = field.getValue();
8433 //Roo.each(this.childForms || [], function (f) {
8434 // f.setValues(values);
8441 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8442 * they are returned as an array.
8443 * @param {Boolean} asString
8446 getValues : function(asString){
8447 //if (this.childForms) {
8448 // copy values from the child forms
8449 // Roo.each(this.childForms, function (f) {
8450 // this.setValues(f.getValues());
8456 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8457 if(asString === true){
8460 return Roo.urlDecode(fs);
8464 * Returns the fields in this form as an object with key/value pairs.
8465 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8468 getFieldValues : function(with_hidden)
8470 var items = this.getItems();
8472 items.each(function(f){
8478 var v = f.getValue();
8480 if (f.inputType =='radio') {
8481 if (typeof(ret[f.getName()]) == 'undefined') {
8482 ret[f.getName()] = ''; // empty..
8485 if (!f.el.dom.checked) {
8493 if(f.xtype == 'MoneyField'){
8494 ret[f.currencyName] = f.getCurrency();
8497 // not sure if this supported any more..
8498 if ((typeof(v) == 'object') && f.getRawValue) {
8499 v = f.getRawValue() ; // dates..
8501 // combo boxes where name != hiddenName...
8502 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8503 ret[f.name] = f.getRawValue();
8505 ret[f.getName()] = v;
8512 * Clears all invalid messages in this form.
8513 * @return {BasicForm} this
8515 clearInvalid : function(){
8516 var items = this.getItems();
8518 items.each(function(f){
8527 * @return {BasicForm} this
8530 var items = this.getItems();
8531 items.each(function(f){
8535 Roo.each(this.childForms || [], function (f) {
8543 getItems : function()
8545 var r=new Roo.util.MixedCollection(false, function(o){
8546 return o.id || (o.id = Roo.id());
8548 var iter = function(el) {
8555 Roo.each(el.items,function(e) {
8564 hideFields : function(items)
8566 Roo.each(items, function(i){
8568 var f = this.findField(i);
8579 showFields : function(items)
8581 Roo.each(items, function(i){
8583 var f = this.findField(i);
8596 Roo.apply(Roo.bootstrap.Form, {
8623 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8624 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8625 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8626 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8629 this.maskEl.top.enableDisplayMode("block");
8630 this.maskEl.left.enableDisplayMode("block");
8631 this.maskEl.bottom.enableDisplayMode("block");
8632 this.maskEl.right.enableDisplayMode("block");
8634 this.toolTip = new Roo.bootstrap.Tooltip({
8635 cls : 'roo-form-error-popover',
8637 'left' : ['r-l', [-2,0], 'right'],
8638 'right' : ['l-r', [2,0], 'left'],
8639 'bottom' : ['tl-bl', [0,2], 'top'],
8640 'top' : [ 'bl-tl', [0,-2], 'bottom']
8644 this.toolTip.render(Roo.get(document.body));
8646 this.toolTip.el.enableDisplayMode("block");
8648 Roo.get(document.body).on('click', function(){
8652 Roo.get(document.body).on('touchstart', function(){
8656 this.isApplied = true
8659 mask : function(form, target)
8663 this.target = target;
8665 if(!this.form.errorMask || !target.el){
8669 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8671 Roo.log(scrollable);
8673 var ot = this.target.el.calcOffsetsTo(scrollable);
8675 var scrollTo = ot[1] - this.form.maskOffset;
8677 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8679 scrollable.scrollTo('top', scrollTo);
8681 var box = this.target.el.getBox();
8683 var zIndex = Roo.bootstrap.Modal.zIndex++;
8686 this.maskEl.top.setStyle('position', 'absolute');
8687 this.maskEl.top.setStyle('z-index', zIndex);
8688 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8689 this.maskEl.top.setLeft(0);
8690 this.maskEl.top.setTop(0);
8691 this.maskEl.top.show();
8693 this.maskEl.left.setStyle('position', 'absolute');
8694 this.maskEl.left.setStyle('z-index', zIndex);
8695 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8696 this.maskEl.left.setLeft(0);
8697 this.maskEl.left.setTop(box.y - this.padding);
8698 this.maskEl.left.show();
8700 this.maskEl.bottom.setStyle('position', 'absolute');
8701 this.maskEl.bottom.setStyle('z-index', zIndex);
8702 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8703 this.maskEl.bottom.setLeft(0);
8704 this.maskEl.bottom.setTop(box.bottom + this.padding);
8705 this.maskEl.bottom.show();
8707 this.maskEl.right.setStyle('position', 'absolute');
8708 this.maskEl.right.setStyle('z-index', zIndex);
8709 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8710 this.maskEl.right.setLeft(box.right + this.padding);
8711 this.maskEl.right.setTop(box.y - this.padding);
8712 this.maskEl.right.show();
8714 this.toolTip.bindEl = this.target.el;
8716 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8718 var tip = this.target.blankText;
8720 if(this.target.getValue() !== '' ) {
8722 if (this.target.invalidText.length) {
8723 tip = this.target.invalidText;
8724 } else if (this.target.regexText.length){
8725 tip = this.target.regexText;
8729 this.toolTip.show(tip);
8731 this.intervalID = window.setInterval(function() {
8732 Roo.bootstrap.Form.popover.unmask();
8735 window.onwheel = function(){ return false;};
8737 (function(){ this.isMasked = true; }).defer(500, this);
8743 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8747 this.maskEl.top.setStyle('position', 'absolute');
8748 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8749 this.maskEl.top.hide();
8751 this.maskEl.left.setStyle('position', 'absolute');
8752 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8753 this.maskEl.left.hide();
8755 this.maskEl.bottom.setStyle('position', 'absolute');
8756 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8757 this.maskEl.bottom.hide();
8759 this.maskEl.right.setStyle('position', 'absolute');
8760 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8761 this.maskEl.right.hide();
8763 this.toolTip.hide();
8765 this.toolTip.el.hide();
8767 window.onwheel = function(){ return true;};
8769 if(this.intervalID){
8770 window.clearInterval(this.intervalID);
8771 this.intervalID = false;
8774 this.isMasked = false;
8784 * Ext JS Library 1.1.1
8785 * Copyright(c) 2006-2007, Ext JS, LLC.
8787 * Originally Released Under LGPL - original licence link has changed is not relivant.
8790 * <script type="text/javascript">
8793 * @class Roo.form.VTypes
8794 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8797 Roo.form.VTypes = function(){
8798 // closure these in so they are only created once.
8799 var alpha = /^[a-zA-Z_]+$/;
8800 var alphanum = /^[a-zA-Z0-9_]+$/;
8801 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8802 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8804 // All these messages and functions are configurable
8807 * The function used to validate email addresses
8808 * @param {String} value The email address
8810 'email' : function(v){
8811 return email.test(v);
8814 * The error text to display when the email validation function returns false
8817 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8819 * The keystroke filter mask to be applied on email input
8822 'emailMask' : /[a-z0-9_\.\-@]/i,
8825 * The function used to validate URLs
8826 * @param {String} value The URL
8828 'url' : function(v){
8832 * The error text to display when the url validation function returns false
8835 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8838 * The function used to validate alpha values
8839 * @param {String} value The value
8841 'alpha' : function(v){
8842 return alpha.test(v);
8845 * The error text to display when the alpha validation function returns false
8848 'alphaText' : 'This field should only contain letters and _',
8850 * The keystroke filter mask to be applied on alpha input
8853 'alphaMask' : /[a-z_]/i,
8856 * The function used to validate alphanumeric values
8857 * @param {String} value The value
8859 'alphanum' : function(v){
8860 return alphanum.test(v);
8863 * The error text to display when the alphanumeric validation function returns false
8866 'alphanumText' : 'This field should only contain letters, numbers and _',
8868 * The keystroke filter mask to be applied on alphanumeric input
8871 'alphanumMask' : /[a-z0-9_]/i
8881 * @class Roo.bootstrap.Input
8882 * @extends Roo.bootstrap.Component
8883 * Bootstrap Input class
8884 * @cfg {Boolean} disabled is it disabled
8885 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8886 * @cfg {String} name name of the input
8887 * @cfg {string} fieldLabel - the label associated
8888 * @cfg {string} placeholder - placeholder to put in text.
8889 * @cfg {string} before - input group add on before
8890 * @cfg {string} after - input group add on after
8891 * @cfg {string} size - (lg|sm) or leave empty..
8892 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8893 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8894 * @cfg {Number} md colspan out of 12 for computer-sized screens
8895 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8896 * @cfg {string} value default value of the input
8897 * @cfg {Number} labelWidth set the width of label
8898 * @cfg {Number} labellg set the width of label (1-12)
8899 * @cfg {Number} labelmd set the width of label (1-12)
8900 * @cfg {Number} labelsm set the width of label (1-12)
8901 * @cfg {Number} labelxs set the width of label (1-12)
8902 * @cfg {String} labelAlign (top|left)
8903 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8904 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8905 * @cfg {String} indicatorpos (left|right) default left
8906 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8907 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8909 * @cfg {String} align (left|center|right) Default left
8910 * @cfg {Boolean} forceFeedback (true|false) Default false
8913 * Create a new Input
8914 * @param {Object} config The config object
8917 Roo.bootstrap.Input = function(config){
8919 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8924 * Fires when this field receives input focus.
8925 * @param {Roo.form.Field} this
8930 * Fires when this field loses input focus.
8931 * @param {Roo.form.Field} this
8936 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8937 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8938 * @param {Roo.form.Field} this
8939 * @param {Roo.EventObject} e The event object
8944 * Fires just before the field blurs if the field value has changed.
8945 * @param {Roo.form.Field} this
8946 * @param {Mixed} newValue The new value
8947 * @param {Mixed} oldValue The original value
8952 * Fires after the field has been marked as invalid.
8953 * @param {Roo.form.Field} this
8954 * @param {String} msg The validation message
8959 * Fires after the field has been validated with no errors.
8960 * @param {Roo.form.Field} this
8965 * Fires after the key up
8966 * @param {Roo.form.Field} this
8967 * @param {Roo.EventObject} e The event Object
8973 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
8975 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
8976 automatic validation (defaults to "keyup").
8978 validationEvent : "keyup",
8980 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
8982 validateOnBlur : true,
8984 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
8986 validationDelay : 250,
8988 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
8990 focusClass : "x-form-focus", // not needed???
8994 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
8996 invalidClass : "has-warning",
8999 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
9001 validClass : "has-success",
9004 * @cfg {Boolean} hasFeedback (true|false) default true
9009 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9011 invalidFeedbackClass : "glyphicon-warning-sign",
9014 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9016 validFeedbackClass : "glyphicon-ok",
9019 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9021 selectOnFocus : false,
9024 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9028 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9033 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9035 disableKeyFilter : false,
9038 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9042 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9046 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9048 blankText : "Please complete this mandatory field",
9051 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9055 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9057 maxLength : Number.MAX_VALUE,
9059 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9061 minLengthText : "The minimum length for this field is {0}",
9063 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9065 maxLengthText : "The maximum length for this field is {0}",
9069 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9070 * If available, this function will be called only after the basic validators all return true, and will be passed the
9071 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9075 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9076 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9077 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9081 * @cfg {String} regexText -- Depricated - use Invalid Text
9086 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9092 autocomplete: false,
9111 formatedValue : false,
9112 forceFeedback : false,
9114 indicatorpos : 'left',
9124 parentLabelAlign : function()
9127 while (parent.parent()) {
9128 parent = parent.parent();
9129 if (typeof(parent.labelAlign) !='undefined') {
9130 return parent.labelAlign;
9137 getAutoCreate : function()
9139 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9145 if(this.inputType != 'hidden'){
9146 cfg.cls = 'form-group' //input-group
9152 type : this.inputType,
9154 cls : 'form-control',
9155 placeholder : this.placeholder || '',
9156 autocomplete : this.autocomplete || 'new-password'
9159 if(this.capture.length){
9160 input.capture = this.capture;
9163 if(this.accept.length){
9164 input.accept = this.accept + "/*";
9168 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9171 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9172 input.maxLength = this.maxLength;
9175 if (this.disabled) {
9176 input.disabled=true;
9179 if (this.readOnly) {
9180 input.readonly=true;
9184 input.name = this.name;
9188 input.cls += ' input-' + this.size;
9192 ['xs','sm','md','lg'].map(function(size){
9193 if (settings[size]) {
9194 cfg.cls += ' col-' + size + '-' + settings[size];
9198 var inputblock = input;
9202 cls: 'glyphicon form-control-feedback'
9205 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9208 cls : 'has-feedback',
9216 if (this.before || this.after) {
9219 cls : 'input-group',
9223 if (this.before && typeof(this.before) == 'string') {
9225 inputblock.cn.push({
9227 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9231 if (this.before && typeof(this.before) == 'object') {
9232 this.before = Roo.factory(this.before);
9234 inputblock.cn.push({
9236 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9237 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9241 inputblock.cn.push(input);
9243 if (this.after && typeof(this.after) == 'string') {
9244 inputblock.cn.push({
9246 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9250 if (this.after && typeof(this.after) == 'object') {
9251 this.after = Roo.factory(this.after);
9253 inputblock.cn.push({
9255 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9256 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9260 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9261 inputblock.cls += ' has-feedback';
9262 inputblock.cn.push(feedback);
9267 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9268 tooltip : 'This field is required'
9270 if (Roo.bootstrap.version == 4) {
9273 style : 'display-none'
9276 if (align ==='left' && this.fieldLabel.length) {
9278 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9285 cls : 'control-label col-form-label',
9286 html : this.fieldLabel
9297 var labelCfg = cfg.cn[1];
9298 var contentCfg = cfg.cn[2];
9300 if(this.indicatorpos == 'right'){
9305 cls : 'control-label col-form-label',
9309 html : this.fieldLabel
9323 labelCfg = cfg.cn[0];
9324 contentCfg = cfg.cn[1];
9328 if(this.labelWidth > 12){
9329 labelCfg.style = "width: " + this.labelWidth + 'px';
9332 if(this.labelWidth < 13 && this.labelmd == 0){
9333 this.labelmd = this.labelWidth;
9336 if(this.labellg > 0){
9337 labelCfg.cls += ' col-lg-' + this.labellg;
9338 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9341 if(this.labelmd > 0){
9342 labelCfg.cls += ' col-md-' + this.labelmd;
9343 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9346 if(this.labelsm > 0){
9347 labelCfg.cls += ' col-sm-' + this.labelsm;
9348 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9351 if(this.labelxs > 0){
9352 labelCfg.cls += ' col-xs-' + this.labelxs;
9353 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9357 } else if ( this.fieldLabel.length) {
9362 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9363 tooltip : 'This field is required'
9367 //cls : 'input-group-addon',
9368 html : this.fieldLabel
9376 if(this.indicatorpos == 'right'){
9381 //cls : 'input-group-addon',
9382 html : this.fieldLabel
9387 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9388 tooltip : 'This field is required'
9408 if (this.parentType === 'Navbar' && this.parent().bar) {
9409 cfg.cls += ' navbar-form';
9412 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9413 // on BS4 we do this only if not form
9414 cfg.cls += ' navbar-form';
9422 * return the real input element.
9424 inputEl: function ()
9426 return this.el.select('input.form-control',true).first();
9429 tooltipEl : function()
9431 return this.inputEl();
9434 indicatorEl : function()
9436 if (Roo.bootstrap.version == 4) {
9437 return false; // not enabled in v4 yet.
9440 var indicator = this.el.select('i.roo-required-indicator',true).first();
9450 setDisabled : function(v)
9452 var i = this.inputEl().dom;
9454 i.removeAttribute('disabled');
9458 i.setAttribute('disabled','true');
9460 initEvents : function()
9463 this.inputEl().on("keydown" , this.fireKey, this);
9464 this.inputEl().on("focus", this.onFocus, this);
9465 this.inputEl().on("blur", this.onBlur, this);
9467 this.inputEl().relayEvent('keyup', this);
9469 this.indicator = this.indicatorEl();
9472 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9475 // reference to original value for reset
9476 this.originalValue = this.getValue();
9477 //Roo.form.TextField.superclass.initEvents.call(this);
9478 if(this.validationEvent == 'keyup'){
9479 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9480 this.inputEl().on('keyup', this.filterValidation, this);
9482 else if(this.validationEvent !== false){
9483 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9486 if(this.selectOnFocus){
9487 this.on("focus", this.preFocus, this);
9490 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9491 this.inputEl().on("keypress", this.filterKeys, this);
9493 this.inputEl().relayEvent('keypress', this);
9496 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9497 this.el.on("click", this.autoSize, this);
9500 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9501 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9504 if (typeof(this.before) == 'object') {
9505 this.before.render(this.el.select('.roo-input-before',true).first());
9507 if (typeof(this.after) == 'object') {
9508 this.after.render(this.el.select('.roo-input-after',true).first());
9511 this.inputEl().on('change', this.onChange, this);
9514 filterValidation : function(e){
9515 if(!e.isNavKeyPress()){
9516 this.validationTask.delay(this.validationDelay);
9520 * Validates the field value
9521 * @return {Boolean} True if the value is valid, else false
9523 validate : function(){
9524 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9525 if(this.disabled || this.validateValue(this.getRawValue())){
9536 * Validates a value according to the field's validation rules and marks the field as invalid
9537 * if the validation fails
9538 * @param {Mixed} value The value to validate
9539 * @return {Boolean} True if the value is valid, else false
9541 validateValue : function(value)
9543 if(this.getVisibilityEl().hasClass('hidden')){
9547 if(value.length < 1) { // if it's blank
9548 if(this.allowBlank){
9554 if(value.length < this.minLength){
9555 this.invalidText = String.format(this.minLengthText, this.minLength);
9558 if(value.length > this.maxLength){
9559 this.invalidText = String.format(this.maxLengthText, this.maxLength);
9563 var vt = Roo.form.VTypes;
9564 if(!vt[this.vtype](value, this)){
9568 if(typeof this.validator == "function"){
9569 var msg = this.validator(value);
9573 if (typeof(msg) == 'string') {
9574 this.invalidText = msg;
9578 if(this.regex && !this.regex.test(value)){
9586 fireKey : function(e){
9587 //Roo.log('field ' + e.getKey());
9588 if(e.isNavKeyPress()){
9589 this.fireEvent("specialkey", this, e);
9592 focus : function (selectText){
9594 this.inputEl().focus();
9595 if(selectText === true){
9596 this.inputEl().dom.select();
9602 onFocus : function(){
9603 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9604 // this.el.addClass(this.focusClass);
9607 this.hasFocus = true;
9608 this.startValue = this.getValue();
9609 this.fireEvent("focus", this);
9613 beforeBlur : Roo.emptyFn,
9617 onBlur : function(){
9619 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9620 //this.el.removeClass(this.focusClass);
9622 this.hasFocus = false;
9623 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9626 var v = this.getValue();
9627 if(String(v) !== String(this.startValue)){
9628 this.fireEvent('change', this, v, this.startValue);
9630 this.fireEvent("blur", this);
9633 onChange : function(e)
9635 var v = this.getValue();
9636 if(String(v) !== String(this.startValue)){
9637 this.fireEvent('change', this, v, this.startValue);
9643 * Resets the current field value to the originally loaded value and clears any validation messages
9646 this.setValue(this.originalValue);
9650 * Returns the name of the field
9651 * @return {Mixed} name The name field
9653 getName: function(){
9657 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9658 * @return {Mixed} value The field value
9660 getValue : function(){
9662 var v = this.inputEl().getValue();
9667 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9668 * @return {Mixed} value The field value
9670 getRawValue : function(){
9671 var v = this.inputEl().getValue();
9677 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9678 * @param {Mixed} value The value to set
9680 setRawValue : function(v){
9681 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9684 selectText : function(start, end){
9685 var v = this.getRawValue();
9687 start = start === undefined ? 0 : start;
9688 end = end === undefined ? v.length : end;
9689 var d = this.inputEl().dom;
9690 if(d.setSelectionRange){
9691 d.setSelectionRange(start, end);
9692 }else if(d.createTextRange){
9693 var range = d.createTextRange();
9694 range.moveStart("character", start);
9695 range.moveEnd("character", v.length-end);
9702 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9703 * @param {Mixed} value The value to set
9705 setValue : function(v){
9708 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9714 processValue : function(value){
9715 if(this.stripCharsRe){
9716 var newValue = value.replace(this.stripCharsRe, '');
9717 if(newValue !== value){
9718 this.setRawValue(newValue);
9725 preFocus : function(){
9727 if(this.selectOnFocus){
9728 this.inputEl().dom.select();
9731 filterKeys : function(e){
9733 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9736 var c = e.getCharCode(), cc = String.fromCharCode(c);
9737 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9740 if(!this.maskRe.test(cc)){
9745 * Clear any invalid styles/messages for this field
9747 clearInvalid : function(){
9749 if(!this.el || this.preventMark){ // not rendered
9754 this.el.removeClass(this.invalidClass);
9756 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9758 var feedback = this.el.select('.form-control-feedback', true).first();
9761 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9767 this.indicator.removeClass('visible');
9768 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9771 this.fireEvent('valid', this);
9775 * Mark this field as valid
9777 markValid : function()
9779 if(!this.el || this.preventMark){ // not rendered...
9783 this.el.removeClass([this.invalidClass, this.validClass]);
9785 var feedback = this.el.select('.form-control-feedback', true).first();
9788 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9792 this.indicator.removeClass('visible');
9793 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9800 if(this.allowBlank && !this.getRawValue().length){
9804 this.el.addClass(this.validClass);
9806 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9808 var feedback = this.el.select('.form-control-feedback', true).first();
9811 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9812 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9817 this.fireEvent('valid', this);
9821 * Mark this field as invalid
9822 * @param {String} msg The validation message
9824 markInvalid : function(msg)
9826 if(!this.el || this.preventMark){ // not rendered
9830 this.el.removeClass([this.invalidClass, this.validClass]);
9832 var feedback = this.el.select('.form-control-feedback', true).first();
9835 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9842 if(this.allowBlank && !this.getRawValue().length){
9847 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9848 this.indicator.addClass('visible');
9851 this.el.addClass(this.invalidClass);
9853 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9855 var feedback = this.el.select('.form-control-feedback', true).first();
9858 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9860 if(this.getValue().length || this.forceFeedback){
9861 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9868 this.fireEvent('invalid', this, msg);
9871 SafariOnKeyDown : function(event)
9873 // this is a workaround for a password hang bug on chrome/ webkit.
9874 if (this.inputEl().dom.type != 'password') {
9878 var isSelectAll = false;
9880 if(this.inputEl().dom.selectionEnd > 0){
9881 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9883 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9884 event.preventDefault();
9889 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9891 event.preventDefault();
9892 // this is very hacky as keydown always get's upper case.
9894 var cc = String.fromCharCode(event.getCharCode());
9895 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9899 adjustWidth : function(tag, w){
9900 tag = tag.toLowerCase();
9901 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9902 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9906 if(tag == 'textarea'){
9909 }else if(Roo.isOpera){
9913 if(tag == 'textarea'){
9921 setFieldLabel : function(v)
9927 if(this.indicatorEl()){
9928 var ar = this.el.select('label > span',true);
9930 if (ar.elements.length) {
9931 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9932 this.fieldLabel = v;
9936 var br = this.el.select('label',true);
9938 if(br.elements.length) {
9939 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9940 this.fieldLabel = v;
9944 Roo.log('Cannot Found any of label > span || label in input');
9948 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9949 this.fieldLabel = v;
9964 * @class Roo.bootstrap.TextArea
9965 * @extends Roo.bootstrap.Input
9966 * Bootstrap TextArea class
9967 * @cfg {Number} cols Specifies the visible width of a text area
9968 * @cfg {Number} rows Specifies the visible number of lines in a text area
9969 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9970 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9971 * @cfg {string} html text
9974 * Create a new TextArea
9975 * @param {Object} config The config object
9978 Roo.bootstrap.TextArea = function(config){
9979 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9983 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9993 getAutoCreate : function(){
9995 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10001 if(this.inputType != 'hidden'){
10002 cfg.cls = 'form-group' //input-group
10010 value : this.value || '',
10011 html: this.html || '',
10012 cls : 'form-control',
10013 placeholder : this.placeholder || ''
10017 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10018 input.maxLength = this.maxLength;
10022 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10026 input.cols = this.cols;
10029 if (this.readOnly) {
10030 input.readonly = true;
10034 input.name = this.name;
10038 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10042 ['xs','sm','md','lg'].map(function(size){
10043 if (settings[size]) {
10044 cfg.cls += ' col-' + size + '-' + settings[size];
10048 var inputblock = input;
10050 if(this.hasFeedback && !this.allowBlank){
10054 cls: 'glyphicon form-control-feedback'
10058 cls : 'has-feedback',
10067 if (this.before || this.after) {
10070 cls : 'input-group',
10074 inputblock.cn.push({
10076 cls : 'input-group-addon',
10081 inputblock.cn.push(input);
10083 if(this.hasFeedback && !this.allowBlank){
10084 inputblock.cls += ' has-feedback';
10085 inputblock.cn.push(feedback);
10089 inputblock.cn.push({
10091 cls : 'input-group-addon',
10098 if (align ==='left' && this.fieldLabel.length) {
10103 cls : 'control-label',
10104 html : this.fieldLabel
10115 if(this.labelWidth > 12){
10116 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10119 if(this.labelWidth < 13 && this.labelmd == 0){
10120 this.labelmd = this.labelWidth;
10123 if(this.labellg > 0){
10124 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10125 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10128 if(this.labelmd > 0){
10129 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10130 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10133 if(this.labelsm > 0){
10134 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10135 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10138 if(this.labelxs > 0){
10139 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10140 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10143 } else if ( this.fieldLabel.length) {
10148 //cls : 'input-group-addon',
10149 html : this.fieldLabel
10167 if (this.disabled) {
10168 input.disabled=true;
10175 * return the real textarea element.
10177 inputEl: function ()
10179 return this.el.select('textarea.form-control',true).first();
10183 * Clear any invalid styles/messages for this field
10185 clearInvalid : function()
10188 if(!this.el || this.preventMark){ // not rendered
10192 var label = this.el.select('label', true).first();
10193 var icon = this.el.select('i.fa-star', true).first();
10199 this.el.removeClass(this.invalidClass);
10201 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10203 var feedback = this.el.select('.form-control-feedback', true).first();
10206 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10211 this.fireEvent('valid', this);
10215 * Mark this field as valid
10217 markValid : function()
10219 if(!this.el || this.preventMark){ // not rendered
10223 this.el.removeClass([this.invalidClass, this.validClass]);
10225 var feedback = this.el.select('.form-control-feedback', true).first();
10228 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10231 if(this.disabled || this.allowBlank){
10235 var label = this.el.select('label', true).first();
10236 var icon = this.el.select('i.fa-star', true).first();
10242 this.el.addClass(this.validClass);
10244 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10246 var feedback = this.el.select('.form-control-feedback', true).first();
10249 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10250 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10255 this.fireEvent('valid', this);
10259 * Mark this field as invalid
10260 * @param {String} msg The validation message
10262 markInvalid : function(msg)
10264 if(!this.el || this.preventMark){ // not rendered
10268 this.el.removeClass([this.invalidClass, this.validClass]);
10270 var feedback = this.el.select('.form-control-feedback', true).first();
10273 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10276 if(this.disabled || this.allowBlank){
10280 var label = this.el.select('label', true).first();
10281 var icon = this.el.select('i.fa-star', true).first();
10283 if(!this.getValue().length && label && !icon){
10284 this.el.createChild({
10286 cls : 'text-danger fa fa-lg fa-star',
10287 tooltip : 'This field is required',
10288 style : 'margin-right:5px;'
10292 this.el.addClass(this.invalidClass);
10294 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10296 var feedback = this.el.select('.form-control-feedback', true).first();
10299 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10301 if(this.getValue().length || this.forceFeedback){
10302 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10309 this.fireEvent('invalid', this, msg);
10317 * trigger field - base class for combo..
10322 * @class Roo.bootstrap.TriggerField
10323 * @extends Roo.bootstrap.Input
10324 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10325 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10326 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10327 * for which you can provide a custom implementation. For example:
10329 var trigger = new Roo.bootstrap.TriggerField();
10330 trigger.onTriggerClick = myTriggerFn;
10331 trigger.applyTo('my-field');
10334 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10335 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10336 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10337 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10338 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10341 * Create a new TriggerField.
10342 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10343 * to the base TextField)
10345 Roo.bootstrap.TriggerField = function(config){
10346 this.mimicing = false;
10347 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10350 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10352 * @cfg {String} triggerClass A CSS class to apply to the trigger
10355 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10360 * @cfg {Boolean} removable (true|false) special filter default false
10364 /** @cfg {Boolean} grow @hide */
10365 /** @cfg {Number} growMin @hide */
10366 /** @cfg {Number} growMax @hide */
10372 autoSize: Roo.emptyFn,
10376 deferHeight : true,
10379 actionMode : 'wrap',
10384 getAutoCreate : function(){
10386 var align = this.labelAlign || this.parentLabelAlign();
10391 cls: 'form-group' //input-group
10398 type : this.inputType,
10399 cls : 'form-control',
10400 autocomplete: 'new-password',
10401 placeholder : this.placeholder || ''
10405 input.name = this.name;
10408 input.cls += ' input-' + this.size;
10411 if (this.disabled) {
10412 input.disabled=true;
10415 var inputblock = input;
10417 if(this.hasFeedback && !this.allowBlank){
10421 cls: 'glyphicon form-control-feedback'
10424 if(this.removable && !this.editable && !this.tickable){
10426 cls : 'has-feedback',
10432 cls : 'roo-combo-removable-btn close'
10439 cls : 'has-feedback',
10448 if(this.removable && !this.editable && !this.tickable){
10450 cls : 'roo-removable',
10456 cls : 'roo-combo-removable-btn close'
10463 if (this.before || this.after) {
10466 cls : 'input-group',
10470 inputblock.cn.push({
10472 cls : 'input-group-addon input-group-prepend input-group-text',
10477 inputblock.cn.push(input);
10479 if(this.hasFeedback && !this.allowBlank){
10480 inputblock.cls += ' has-feedback';
10481 inputblock.cn.push(feedback);
10485 inputblock.cn.push({
10487 cls : 'input-group-addon input-group-append input-group-text',
10496 var ibwrap = inputblock;
10501 cls: 'roo-select2-choices',
10505 cls: 'roo-select2-search-field',
10517 cls: 'roo-select2-container input-group',
10522 cls: 'form-hidden-field'
10528 if(!this.multiple && this.showToggleBtn){
10534 if (this.caret != false) {
10537 cls: 'fa fa-' + this.caret
10544 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10549 cls: 'combobox-clear',
10563 combobox.cls += ' roo-select2-container-multi';
10567 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10568 tooltip : 'This field is required'
10570 if (Roo.bootstrap.version == 4) {
10573 style : 'display:none'
10578 if (align ==='left' && this.fieldLabel.length) {
10580 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10587 cls : 'control-label',
10588 html : this.fieldLabel
10600 var labelCfg = cfg.cn[1];
10601 var contentCfg = cfg.cn[2];
10603 if(this.indicatorpos == 'right'){
10608 cls : 'control-label',
10612 html : this.fieldLabel
10626 labelCfg = cfg.cn[0];
10627 contentCfg = cfg.cn[1];
10630 if(this.labelWidth > 12){
10631 labelCfg.style = "width: " + this.labelWidth + 'px';
10634 if(this.labelWidth < 13 && this.labelmd == 0){
10635 this.labelmd = this.labelWidth;
10638 if(this.labellg > 0){
10639 labelCfg.cls += ' col-lg-' + this.labellg;
10640 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10643 if(this.labelmd > 0){
10644 labelCfg.cls += ' col-md-' + this.labelmd;
10645 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10648 if(this.labelsm > 0){
10649 labelCfg.cls += ' col-sm-' + this.labelsm;
10650 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10653 if(this.labelxs > 0){
10654 labelCfg.cls += ' col-xs-' + this.labelxs;
10655 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10658 } else if ( this.fieldLabel.length) {
10659 // Roo.log(" label");
10664 //cls : 'input-group-addon',
10665 html : this.fieldLabel
10673 if(this.indicatorpos == 'right'){
10681 html : this.fieldLabel
10695 // Roo.log(" no label && no align");
10702 ['xs','sm','md','lg'].map(function(size){
10703 if (settings[size]) {
10704 cfg.cls += ' col-' + size + '-' + settings[size];
10715 onResize : function(w, h){
10716 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10717 // if(typeof w == 'number'){
10718 // var x = w - this.trigger.getWidth();
10719 // this.inputEl().setWidth(this.adjustWidth('input', x));
10720 // this.trigger.setStyle('left', x+'px');
10725 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10728 getResizeEl : function(){
10729 return this.inputEl();
10733 getPositionEl : function(){
10734 return this.inputEl();
10738 alignErrorIcon : function(){
10739 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10743 initEvents : function(){
10747 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10748 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10749 if(!this.multiple && this.showToggleBtn){
10750 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10751 if(this.hideTrigger){
10752 this.trigger.setDisplayed(false);
10754 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10758 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10761 if(this.removable && !this.editable && !this.tickable){
10762 var close = this.closeTriggerEl();
10765 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10766 close.on('click', this.removeBtnClick, this, close);
10770 //this.trigger.addClassOnOver('x-form-trigger-over');
10771 //this.trigger.addClassOnClick('x-form-trigger-click');
10774 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10778 closeTriggerEl : function()
10780 var close = this.el.select('.roo-combo-removable-btn', true).first();
10781 return close ? close : false;
10784 removeBtnClick : function(e, h, el)
10786 e.preventDefault();
10788 if(this.fireEvent("remove", this) !== false){
10790 this.fireEvent("afterremove", this)
10794 createList : function()
10796 this.list = Roo.get(document.body).createChild({
10797 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10798 cls: 'typeahead typeahead-long dropdown-menu',
10799 style: 'display:none'
10802 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10807 initTrigger : function(){
10812 onDestroy : function(){
10814 this.trigger.removeAllListeners();
10815 // this.trigger.remove();
10818 // this.wrap.remove();
10820 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10824 onFocus : function(){
10825 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10827 if(!this.mimicing){
10828 this.wrap.addClass('x-trigger-wrap-focus');
10829 this.mimicing = true;
10830 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10831 if(this.monitorTab){
10832 this.el.on("keydown", this.checkTab, this);
10839 checkTab : function(e){
10840 if(e.getKey() == e.TAB){
10841 this.triggerBlur();
10846 onBlur : function(){
10851 mimicBlur : function(e, t){
10853 if(!this.wrap.contains(t) && this.validateBlur()){
10854 this.triggerBlur();
10860 triggerBlur : function(){
10861 this.mimicing = false;
10862 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10863 if(this.monitorTab){
10864 this.el.un("keydown", this.checkTab, this);
10866 //this.wrap.removeClass('x-trigger-wrap-focus');
10867 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10871 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10872 validateBlur : function(e, t){
10877 onDisable : function(){
10878 this.inputEl().dom.disabled = true;
10879 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10881 // this.wrap.addClass('x-item-disabled');
10886 onEnable : function(){
10887 this.inputEl().dom.disabled = false;
10888 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10890 // this.el.removeClass('x-item-disabled');
10895 onShow : function(){
10896 var ae = this.getActionEl();
10899 ae.dom.style.display = '';
10900 ae.dom.style.visibility = 'visible';
10906 onHide : function(){
10907 var ae = this.getActionEl();
10908 ae.dom.style.display = 'none';
10912 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10913 * by an implementing function.
10915 * @param {EventObject} e
10917 onTriggerClick : Roo.emptyFn
10921 * Ext JS Library 1.1.1
10922 * Copyright(c) 2006-2007, Ext JS, LLC.
10924 * Originally Released Under LGPL - original licence link has changed is not relivant.
10927 * <script type="text/javascript">
10932 * @class Roo.data.SortTypes
10934 * Defines the default sorting (casting?) comparison functions used when sorting data.
10936 Roo.data.SortTypes = {
10938 * Default sort that does nothing
10939 * @param {Mixed} s The value being converted
10940 * @return {Mixed} The comparison value
10942 none : function(s){
10947 * The regular expression used to strip tags
10951 stripTagsRE : /<\/?[^>]+>/gi,
10954 * Strips all HTML tags to sort on text only
10955 * @param {Mixed} s The value being converted
10956 * @return {String} The comparison value
10958 asText : function(s){
10959 return String(s).replace(this.stripTagsRE, "");
10963 * Strips all HTML tags to sort on text only - Case insensitive
10964 * @param {Mixed} s The value being converted
10965 * @return {String} The comparison value
10967 asUCText : function(s){
10968 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10972 * Case insensitive string
10973 * @param {Mixed} s The value being converted
10974 * @return {String} The comparison value
10976 asUCString : function(s) {
10977 return String(s).toUpperCase();
10982 * @param {Mixed} s The value being converted
10983 * @return {Number} The comparison value
10985 asDate : function(s) {
10989 if(s instanceof Date){
10990 return s.getTime();
10992 return Date.parse(String(s));
10997 * @param {Mixed} s The value being converted
10998 * @return {Float} The comparison value
11000 asFloat : function(s) {
11001 var val = parseFloat(String(s).replace(/,/g, ""));
11010 * @param {Mixed} s The value being converted
11011 * @return {Number} The comparison value
11013 asInt : function(s) {
11014 var val = parseInt(String(s).replace(/,/g, ""));
11022 * Ext JS Library 1.1.1
11023 * Copyright(c) 2006-2007, Ext JS, LLC.
11025 * Originally Released Under LGPL - original licence link has changed is not relivant.
11028 * <script type="text/javascript">
11032 * @class Roo.data.Record
11033 * Instances of this class encapsulate both record <em>definition</em> information, and record
11034 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11035 * to access Records cached in an {@link Roo.data.Store} object.<br>
11037 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11038 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11041 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11043 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11044 * {@link #create}. The parameters are the same.
11045 * @param {Array} data An associative Array of data values keyed by the field name.
11046 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11047 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11048 * not specified an integer id is generated.
11050 Roo.data.Record = function(data, id){
11051 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11056 * Generate a constructor for a specific record layout.
11057 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11058 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11059 * Each field definition object may contain the following properties: <ul>
11060 * <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,
11061 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11062 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11063 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11064 * is being used, then this is a string containing the javascript expression to reference the data relative to
11065 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11066 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11067 * this may be omitted.</p></li>
11068 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11069 * <ul><li>auto (Default, implies no conversion)</li>
11074 * <li>date</li></ul></p></li>
11075 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11076 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11077 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11078 * by the Reader into an object that will be stored in the Record. It is passed the
11079 * following parameters:<ul>
11080 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11082 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11084 * <br>usage:<br><pre><code>
11085 var TopicRecord = Roo.data.Record.create(
11086 {name: 'title', mapping: 'topic_title'},
11087 {name: 'author', mapping: 'username'},
11088 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11089 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11090 {name: 'lastPoster', mapping: 'user2'},
11091 {name: 'excerpt', mapping: 'post_text'}
11094 var myNewRecord = new TopicRecord({
11095 title: 'Do my job please',
11098 lastPost: new Date(),
11099 lastPoster: 'Animal',
11100 excerpt: 'No way dude!'
11102 myStore.add(myNewRecord);
11107 Roo.data.Record.create = function(o){
11108 var f = function(){
11109 f.superclass.constructor.apply(this, arguments);
11111 Roo.extend(f, Roo.data.Record);
11112 var p = f.prototype;
11113 p.fields = new Roo.util.MixedCollection(false, function(field){
11116 for(var i = 0, len = o.length; i < len; i++){
11117 p.fields.add(new Roo.data.Field(o[i]));
11119 f.getField = function(name){
11120 return p.fields.get(name);
11125 Roo.data.Record.AUTO_ID = 1000;
11126 Roo.data.Record.EDIT = 'edit';
11127 Roo.data.Record.REJECT = 'reject';
11128 Roo.data.Record.COMMIT = 'commit';
11130 Roo.data.Record.prototype = {
11132 * Readonly flag - true if this record has been modified.
11141 join : function(store){
11142 this.store = store;
11146 * Set the named field to the specified value.
11147 * @param {String} name The name of the field to set.
11148 * @param {Object} value The value to set the field to.
11150 set : function(name, value){
11151 if(this.data[name] == value){
11155 if(!this.modified){
11156 this.modified = {};
11158 if(typeof this.modified[name] == 'undefined'){
11159 this.modified[name] = this.data[name];
11161 this.data[name] = value;
11162 if(!this.editing && this.store){
11163 this.store.afterEdit(this);
11168 * Get the value of the named field.
11169 * @param {String} name The name of the field to get the value of.
11170 * @return {Object} The value of the field.
11172 get : function(name){
11173 return this.data[name];
11177 beginEdit : function(){
11178 this.editing = true;
11179 this.modified = {};
11183 cancelEdit : function(){
11184 this.editing = false;
11185 delete this.modified;
11189 endEdit : function(){
11190 this.editing = false;
11191 if(this.dirty && this.store){
11192 this.store.afterEdit(this);
11197 * Usually called by the {@link Roo.data.Store} which owns the Record.
11198 * Rejects all changes made to the Record since either creation, or the last commit operation.
11199 * Modified fields are reverted to their original values.
11201 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11202 * of reject operations.
11204 reject : function(){
11205 var m = this.modified;
11207 if(typeof m[n] != "function"){
11208 this.data[n] = m[n];
11211 this.dirty = false;
11212 delete this.modified;
11213 this.editing = false;
11215 this.store.afterReject(this);
11220 * Usually called by the {@link Roo.data.Store} which owns the Record.
11221 * Commits all changes made to the Record since either creation, or the last commit operation.
11223 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11224 * of commit operations.
11226 commit : function(){
11227 this.dirty = false;
11228 delete this.modified;
11229 this.editing = false;
11231 this.store.afterCommit(this);
11236 hasError : function(){
11237 return this.error != null;
11241 clearError : function(){
11246 * Creates a copy of this record.
11247 * @param {String} id (optional) A new record id if you don't want to use this record's id
11250 copy : function(newId) {
11251 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11255 * Ext JS Library 1.1.1
11256 * Copyright(c) 2006-2007, Ext JS, LLC.
11258 * Originally Released Under LGPL - original licence link has changed is not relivant.
11261 * <script type="text/javascript">
11267 * @class Roo.data.Store
11268 * @extends Roo.util.Observable
11269 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11270 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11272 * 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
11273 * has no knowledge of the format of the data returned by the Proxy.<br>
11275 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11276 * instances from the data object. These records are cached and made available through accessor functions.
11278 * Creates a new Store.
11279 * @param {Object} config A config object containing the objects needed for the Store to access data,
11280 * and read the data into Records.
11282 Roo.data.Store = function(config){
11283 this.data = new Roo.util.MixedCollection(false);
11284 this.data.getKey = function(o){
11287 this.baseParams = {};
11289 this.paramNames = {
11294 "multisort" : "_multisort"
11297 if(config && config.data){
11298 this.inlineData = config.data;
11299 delete config.data;
11302 Roo.apply(this, config);
11304 if(this.reader){ // reader passed
11305 this.reader = Roo.factory(this.reader, Roo.data);
11306 this.reader.xmodule = this.xmodule || false;
11307 if(!this.recordType){
11308 this.recordType = this.reader.recordType;
11310 if(this.reader.onMetaChange){
11311 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11315 if(this.recordType){
11316 this.fields = this.recordType.prototype.fields;
11318 this.modified = [];
11322 * @event datachanged
11323 * Fires when the data cache has changed, and a widget which is using this Store
11324 * as a Record cache should refresh its view.
11325 * @param {Store} this
11327 datachanged : true,
11329 * @event metachange
11330 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11331 * @param {Store} this
11332 * @param {Object} meta The JSON metadata
11337 * Fires when Records have been added to the Store
11338 * @param {Store} this
11339 * @param {Roo.data.Record[]} records The array of Records added
11340 * @param {Number} index The index at which the record(s) were added
11345 * Fires when a Record has been removed from the Store
11346 * @param {Store} this
11347 * @param {Roo.data.Record} record The Record that was removed
11348 * @param {Number} index The index at which the record was removed
11353 * Fires when a Record has been updated
11354 * @param {Store} this
11355 * @param {Roo.data.Record} record The Record that was updated
11356 * @param {String} operation The update operation being performed. Value may be one of:
11358 Roo.data.Record.EDIT
11359 Roo.data.Record.REJECT
11360 Roo.data.Record.COMMIT
11366 * Fires when the data cache has been cleared.
11367 * @param {Store} this
11371 * @event beforeload
11372 * Fires before a request is made for a new data object. If the beforeload handler returns false
11373 * the load action will be canceled.
11374 * @param {Store} this
11375 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11379 * @event beforeloadadd
11380 * Fires after a new set of Records has been loaded.
11381 * @param {Store} this
11382 * @param {Roo.data.Record[]} records The Records that were loaded
11383 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11385 beforeloadadd : true,
11388 * Fires after a new set of Records has been loaded, before they are added to the store.
11389 * @param {Store} this
11390 * @param {Roo.data.Record[]} records The Records that were loaded
11391 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11392 * @params {Object} return from reader
11396 * @event loadexception
11397 * Fires if an exception occurs in the Proxy during loading.
11398 * Called with the signature of the Proxy's "loadexception" event.
11399 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11402 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11403 * @param {Object} load options
11404 * @param {Object} jsonData from your request (normally this contains the Exception)
11406 loadexception : true
11410 this.proxy = Roo.factory(this.proxy, Roo.data);
11411 this.proxy.xmodule = this.xmodule || false;
11412 this.relayEvents(this.proxy, ["loadexception"]);
11414 this.sortToggle = {};
11415 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11417 Roo.data.Store.superclass.constructor.call(this);
11419 if(this.inlineData){
11420 this.loadData(this.inlineData);
11421 delete this.inlineData;
11425 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11427 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11428 * without a remote query - used by combo/forms at present.
11432 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11435 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11438 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11439 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11442 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11443 * on any HTTP request
11446 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11449 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11453 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11454 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11456 remoteSort : false,
11459 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11460 * loaded or when a record is removed. (defaults to false).
11462 pruneModifiedRecords : false,
11465 lastOptions : null,
11468 * Add Records to the Store and fires the add event.
11469 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11471 add : function(records){
11472 records = [].concat(records);
11473 for(var i = 0, len = records.length; i < len; i++){
11474 records[i].join(this);
11476 var index = this.data.length;
11477 this.data.addAll(records);
11478 this.fireEvent("add", this, records, index);
11482 * Remove a Record from the Store and fires the remove event.
11483 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11485 remove : function(record){
11486 var index = this.data.indexOf(record);
11487 this.data.removeAt(index);
11489 if(this.pruneModifiedRecords){
11490 this.modified.remove(record);
11492 this.fireEvent("remove", this, record, index);
11496 * Remove all Records from the Store and fires the clear event.
11498 removeAll : function(){
11500 if(this.pruneModifiedRecords){
11501 this.modified = [];
11503 this.fireEvent("clear", this);
11507 * Inserts Records to the Store at the given index and fires the add event.
11508 * @param {Number} index The start index at which to insert the passed Records.
11509 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11511 insert : function(index, records){
11512 records = [].concat(records);
11513 for(var i = 0, len = records.length; i < len; i++){
11514 this.data.insert(index, records[i]);
11515 records[i].join(this);
11517 this.fireEvent("add", this, records, index);
11521 * Get the index within the cache of the passed Record.
11522 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11523 * @return {Number} The index of the passed Record. Returns -1 if not found.
11525 indexOf : function(record){
11526 return this.data.indexOf(record);
11530 * Get the index within the cache of the Record with the passed id.
11531 * @param {String} id The id of the Record to find.
11532 * @return {Number} The index of the Record. Returns -1 if not found.
11534 indexOfId : function(id){
11535 return this.data.indexOfKey(id);
11539 * Get the Record with the specified id.
11540 * @param {String} id The id of the Record to find.
11541 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11543 getById : function(id){
11544 return this.data.key(id);
11548 * Get the Record at the specified index.
11549 * @param {Number} index The index of the Record to find.
11550 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11552 getAt : function(index){
11553 return this.data.itemAt(index);
11557 * Returns a range of Records between specified indices.
11558 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11559 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11560 * @return {Roo.data.Record[]} An array of Records
11562 getRange : function(start, end){
11563 return this.data.getRange(start, end);
11567 storeOptions : function(o){
11568 o = Roo.apply({}, o);
11571 this.lastOptions = o;
11575 * Loads the Record cache from the configured Proxy using the configured Reader.
11577 * If using remote paging, then the first load call must specify the <em>start</em>
11578 * and <em>limit</em> properties in the options.params property to establish the initial
11579 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11581 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11582 * and this call will return before the new data has been loaded. Perform any post-processing
11583 * in a callback function, or in a "load" event handler.</strong>
11585 * @param {Object} options An object containing properties which control loading options:<ul>
11586 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11587 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11588 * passed the following arguments:<ul>
11589 * <li>r : Roo.data.Record[]</li>
11590 * <li>options: Options object from the load call</li>
11591 * <li>success: Boolean success indicator</li></ul></li>
11592 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11593 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11596 load : function(options){
11597 options = options || {};
11598 if(this.fireEvent("beforeload", this, options) !== false){
11599 this.storeOptions(options);
11600 var p = Roo.apply(options.params || {}, this.baseParams);
11601 // if meta was not loaded from remote source.. try requesting it.
11602 if (!this.reader.metaFromRemote) {
11603 p._requestMeta = 1;
11605 if(this.sortInfo && this.remoteSort){
11606 var pn = this.paramNames;
11607 p[pn["sort"]] = this.sortInfo.field;
11608 p[pn["dir"]] = this.sortInfo.direction;
11610 if (this.multiSort) {
11611 var pn = this.paramNames;
11612 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11615 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11620 * Reloads the Record cache from the configured Proxy using the configured Reader and
11621 * the options from the last load operation performed.
11622 * @param {Object} options (optional) An object containing properties which may override the options
11623 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11624 * the most recently used options are reused).
11626 reload : function(options){
11627 this.load(Roo.applyIf(options||{}, this.lastOptions));
11631 // Called as a callback by the Reader during a load operation.
11632 loadRecords : function(o, options, success){
11633 if(!o || success === false){
11634 if(success !== false){
11635 this.fireEvent("load", this, [], options, o);
11637 if(options.callback){
11638 options.callback.call(options.scope || this, [], options, false);
11642 // if data returned failure - throw an exception.
11643 if (o.success === false) {
11644 // show a message if no listener is registered.
11645 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11646 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11648 // loadmask wil be hooked into this..
11649 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11652 var r = o.records, t = o.totalRecords || r.length;
11654 this.fireEvent("beforeloadadd", this, r, options, o);
11656 if(!options || options.add !== true){
11657 if(this.pruneModifiedRecords){
11658 this.modified = [];
11660 for(var i = 0, len = r.length; i < len; i++){
11664 this.data = this.snapshot;
11665 delete this.snapshot;
11668 this.data.addAll(r);
11669 this.totalLength = t;
11671 this.fireEvent("datachanged", this);
11673 this.totalLength = Math.max(t, this.data.length+r.length);
11677 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11679 var e = new Roo.data.Record({});
11681 e.set(this.parent.displayField, this.parent.emptyTitle);
11682 e.set(this.parent.valueField, '');
11687 this.fireEvent("load", this, r, options, o);
11688 if(options.callback){
11689 options.callback.call(options.scope || this, r, options, true);
11695 * Loads data from a passed data block. A Reader which understands the format of the data
11696 * must have been configured in the constructor.
11697 * @param {Object} data The data block from which to read the Records. The format of the data expected
11698 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11699 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11701 loadData : function(o, append){
11702 var r = this.reader.readRecords(o);
11703 this.loadRecords(r, {add: append}, true);
11707 * Gets the number of cached records.
11709 * <em>If using paging, this may not be the total size of the dataset. If the data object
11710 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11711 * the data set size</em>
11713 getCount : function(){
11714 return this.data.length || 0;
11718 * Gets the total number of records in the dataset as returned by the server.
11720 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11721 * the dataset size</em>
11723 getTotalCount : function(){
11724 return this.totalLength || 0;
11728 * Returns the sort state of the Store as an object with two properties:
11730 field {String} The name of the field by which the Records are sorted
11731 direction {String} The sort order, "ASC" or "DESC"
11734 getSortState : function(){
11735 return this.sortInfo;
11739 applySort : function(){
11740 if(this.sortInfo && !this.remoteSort){
11741 var s = this.sortInfo, f = s.field;
11742 var st = this.fields.get(f).sortType;
11743 var fn = function(r1, r2){
11744 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11745 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11747 this.data.sort(s.direction, fn);
11748 if(this.snapshot && this.snapshot != this.data){
11749 this.snapshot.sort(s.direction, fn);
11755 * Sets the default sort column and order to be used by the next load operation.
11756 * @param {String} fieldName The name of the field to sort by.
11757 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11759 setDefaultSort : function(field, dir){
11760 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11764 * Sort the Records.
11765 * If remote sorting is used, the sort is performed on the server, and the cache is
11766 * reloaded. If local sorting is used, the cache is sorted internally.
11767 * @param {String} fieldName The name of the field to sort by.
11768 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11770 sort : function(fieldName, dir){
11771 var f = this.fields.get(fieldName);
11773 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11775 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11776 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11781 this.sortToggle[f.name] = dir;
11782 this.sortInfo = {field: f.name, direction: dir};
11783 if(!this.remoteSort){
11785 this.fireEvent("datachanged", this);
11787 this.load(this.lastOptions);
11792 * Calls the specified function for each of the Records in the cache.
11793 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11794 * Returning <em>false</em> aborts and exits the iteration.
11795 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11797 each : function(fn, scope){
11798 this.data.each(fn, scope);
11802 * Gets all records modified since the last commit. Modified records are persisted across load operations
11803 * (e.g., during paging).
11804 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11806 getModifiedRecords : function(){
11807 return this.modified;
11811 createFilterFn : function(property, value, anyMatch){
11812 if(!value.exec){ // not a regex
11813 value = String(value);
11814 if(value.length == 0){
11817 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11819 return function(r){
11820 return value.test(r.data[property]);
11825 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11826 * @param {String} property A field on your records
11827 * @param {Number} start The record index to start at (defaults to 0)
11828 * @param {Number} end The last record index to include (defaults to length - 1)
11829 * @return {Number} The sum
11831 sum : function(property, start, end){
11832 var rs = this.data.items, v = 0;
11833 start = start || 0;
11834 end = (end || end === 0) ? end : rs.length-1;
11836 for(var i = start; i <= end; i++){
11837 v += (rs[i].data[property] || 0);
11843 * Filter the records by a specified property.
11844 * @param {String} field A field on your records
11845 * @param {String/RegExp} value Either a string that the field
11846 * should start with or a RegExp to test against the field
11847 * @param {Boolean} anyMatch True to match any part not just the beginning
11849 filter : function(property, value, anyMatch){
11850 var fn = this.createFilterFn(property, value, anyMatch);
11851 return fn ? this.filterBy(fn) : this.clearFilter();
11855 * Filter by a function. The specified function will be called with each
11856 * record in this data source. If the function returns true the record is included,
11857 * otherwise it is filtered.
11858 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11859 * @param {Object} scope (optional) The scope of the function (defaults to this)
11861 filterBy : function(fn, scope){
11862 this.snapshot = this.snapshot || this.data;
11863 this.data = this.queryBy(fn, scope||this);
11864 this.fireEvent("datachanged", this);
11868 * Query the records by a specified property.
11869 * @param {String} field A field on your records
11870 * @param {String/RegExp} value Either a string that the field
11871 * should start with or a RegExp to test against the field
11872 * @param {Boolean} anyMatch True to match any part not just the beginning
11873 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11875 query : function(property, value, anyMatch){
11876 var fn = this.createFilterFn(property, value, anyMatch);
11877 return fn ? this.queryBy(fn) : this.data.clone();
11881 * Query by a function. The specified function will be called with each
11882 * record in this data source. If the function returns true the record is included
11884 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11885 * @param {Object} scope (optional) The scope of the function (defaults to this)
11886 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11888 queryBy : function(fn, scope){
11889 var data = this.snapshot || this.data;
11890 return data.filterBy(fn, scope||this);
11894 * Collects unique values for a particular dataIndex from this store.
11895 * @param {String} dataIndex The property to collect
11896 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11897 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11898 * @return {Array} An array of the unique values
11900 collect : function(dataIndex, allowNull, bypassFilter){
11901 var d = (bypassFilter === true && this.snapshot) ?
11902 this.snapshot.items : this.data.items;
11903 var v, sv, r = [], l = {};
11904 for(var i = 0, len = d.length; i < len; i++){
11905 v = d[i].data[dataIndex];
11907 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11916 * Revert to a view of the Record cache with no filtering applied.
11917 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11919 clearFilter : function(suppressEvent){
11920 if(this.snapshot && this.snapshot != this.data){
11921 this.data = this.snapshot;
11922 delete this.snapshot;
11923 if(suppressEvent !== true){
11924 this.fireEvent("datachanged", this);
11930 afterEdit : function(record){
11931 if(this.modified.indexOf(record) == -1){
11932 this.modified.push(record);
11934 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11938 afterReject : function(record){
11939 this.modified.remove(record);
11940 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11944 afterCommit : function(record){
11945 this.modified.remove(record);
11946 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11950 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11951 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11953 commitChanges : function(){
11954 var m = this.modified.slice(0);
11955 this.modified = [];
11956 for(var i = 0, len = m.length; i < len; i++){
11962 * Cancel outstanding changes on all changed records.
11964 rejectChanges : function(){
11965 var m = this.modified.slice(0);
11966 this.modified = [];
11967 for(var i = 0, len = m.length; i < len; i++){
11972 onMetaChange : function(meta, rtype, o){
11973 this.recordType = rtype;
11974 this.fields = rtype.prototype.fields;
11975 delete this.snapshot;
11976 this.sortInfo = meta.sortInfo || this.sortInfo;
11977 this.modified = [];
11978 this.fireEvent('metachange', this, this.reader.meta);
11981 moveIndex : function(data, type)
11983 var index = this.indexOf(data);
11985 var newIndex = index + type;
11989 this.insert(newIndex, data);
11994 * Ext JS Library 1.1.1
11995 * Copyright(c) 2006-2007, Ext JS, LLC.
11997 * Originally Released Under LGPL - original licence link has changed is not relivant.
12000 * <script type="text/javascript">
12004 * @class Roo.data.SimpleStore
12005 * @extends Roo.data.Store
12006 * Small helper class to make creating Stores from Array data easier.
12007 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12008 * @cfg {Array} fields An array of field definition objects, or field name strings.
12009 * @cfg {Array} data The multi-dimensional array of data
12011 * @param {Object} config
12013 Roo.data.SimpleStore = function(config){
12014 Roo.data.SimpleStore.superclass.constructor.call(this, {
12016 reader: new Roo.data.ArrayReader({
12019 Roo.data.Record.create(config.fields)
12021 proxy : new Roo.data.MemoryProxy(config.data)
12025 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12027 * Ext JS Library 1.1.1
12028 * Copyright(c) 2006-2007, Ext JS, LLC.
12030 * Originally Released Under LGPL - original licence link has changed is not relivant.
12033 * <script type="text/javascript">
12038 * @extends Roo.data.Store
12039 * @class Roo.data.JsonStore
12040 * Small helper class to make creating Stores for JSON data easier. <br/>
12042 var store = new Roo.data.JsonStore({
12043 url: 'get-images.php',
12045 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12048 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12049 * JsonReader and HttpProxy (unless inline data is provided).</b>
12050 * @cfg {Array} fields An array of field definition objects, or field name strings.
12052 * @param {Object} config
12054 Roo.data.JsonStore = function(c){
12055 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12056 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12057 reader: new Roo.data.JsonReader(c, c.fields)
12060 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12062 * Ext JS Library 1.1.1
12063 * Copyright(c) 2006-2007, Ext JS, LLC.
12065 * Originally Released Under LGPL - original licence link has changed is not relivant.
12068 * <script type="text/javascript">
12072 Roo.data.Field = function(config){
12073 if(typeof config == "string"){
12074 config = {name: config};
12076 Roo.apply(this, config);
12079 this.type = "auto";
12082 var st = Roo.data.SortTypes;
12083 // named sortTypes are supported, here we look them up
12084 if(typeof this.sortType == "string"){
12085 this.sortType = st[this.sortType];
12088 // set default sortType for strings and dates
12089 if(!this.sortType){
12092 this.sortType = st.asUCString;
12095 this.sortType = st.asDate;
12098 this.sortType = st.none;
12103 var stripRe = /[\$,%]/g;
12105 // prebuilt conversion function for this field, instead of
12106 // switching every time we're reading a value
12108 var cv, dateFormat = this.dateFormat;
12113 cv = function(v){ return v; };
12116 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12120 return v !== undefined && v !== null && v !== '' ?
12121 parseInt(String(v).replace(stripRe, ""), 10) : '';
12126 return v !== undefined && v !== null && v !== '' ?
12127 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12132 cv = function(v){ return v === true || v === "true" || v == 1; };
12139 if(v instanceof Date){
12143 if(dateFormat == "timestamp"){
12144 return new Date(v*1000);
12146 return Date.parseDate(v, dateFormat);
12148 var parsed = Date.parse(v);
12149 return parsed ? new Date(parsed) : null;
12158 Roo.data.Field.prototype = {
12166 * Ext JS Library 1.1.1
12167 * Copyright(c) 2006-2007, Ext JS, LLC.
12169 * Originally Released Under LGPL - original licence link has changed is not relivant.
12172 * <script type="text/javascript">
12175 // Base class for reading structured data from a data source. This class is intended to be
12176 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12179 * @class Roo.data.DataReader
12180 * Base class for reading structured data from a data source. This class is intended to be
12181 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12184 Roo.data.DataReader = function(meta, recordType){
12188 this.recordType = recordType instanceof Array ?
12189 Roo.data.Record.create(recordType) : recordType;
12192 Roo.data.DataReader.prototype = {
12194 * Create an empty record
12195 * @param {Object} data (optional) - overlay some values
12196 * @return {Roo.data.Record} record created.
12198 newRow : function(d) {
12200 this.recordType.prototype.fields.each(function(c) {
12202 case 'int' : da[c.name] = 0; break;
12203 case 'date' : da[c.name] = new Date(); break;
12204 case 'float' : da[c.name] = 0.0; break;
12205 case 'boolean' : da[c.name] = false; break;
12206 default : da[c.name] = ""; break;
12210 return new this.recordType(Roo.apply(da, d));
12215 * Ext JS Library 1.1.1
12216 * Copyright(c) 2006-2007, Ext JS, LLC.
12218 * Originally Released Under LGPL - original licence link has changed is not relivant.
12221 * <script type="text/javascript">
12225 * @class Roo.data.DataProxy
12226 * @extends Roo.data.Observable
12227 * This class is an abstract base class for implementations which provide retrieval of
12228 * unformatted data objects.<br>
12230 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12231 * (of the appropriate type which knows how to parse the data object) to provide a block of
12232 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12234 * Custom implementations must implement the load method as described in
12235 * {@link Roo.data.HttpProxy#load}.
12237 Roo.data.DataProxy = function(){
12240 * @event beforeload
12241 * Fires before a network request is made to retrieve a data object.
12242 * @param {Object} This DataProxy object.
12243 * @param {Object} params The params parameter to the load function.
12248 * Fires before the load method's callback is called.
12249 * @param {Object} This DataProxy object.
12250 * @param {Object} o The data object.
12251 * @param {Object} arg The callback argument object passed to the load function.
12255 * @event loadexception
12256 * Fires if an Exception occurs during data retrieval.
12257 * @param {Object} This DataProxy object.
12258 * @param {Object} o The data object.
12259 * @param {Object} arg The callback argument object passed to the load function.
12260 * @param {Object} e The Exception.
12262 loadexception : true
12264 Roo.data.DataProxy.superclass.constructor.call(this);
12267 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12270 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12274 * Ext JS Library 1.1.1
12275 * Copyright(c) 2006-2007, Ext JS, LLC.
12277 * Originally Released Under LGPL - original licence link has changed is not relivant.
12280 * <script type="text/javascript">
12283 * @class Roo.data.MemoryProxy
12284 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12285 * to the Reader when its load method is called.
12287 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12289 Roo.data.MemoryProxy = function(data){
12293 Roo.data.MemoryProxy.superclass.constructor.call(this);
12297 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12300 * Load data from the requested source (in this case an in-memory
12301 * data object passed to the constructor), read the data object into
12302 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12303 * process that block using the passed callback.
12304 * @param {Object} params This parameter is not used by the MemoryProxy class.
12305 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12306 * object into a block of Roo.data.Records.
12307 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12308 * The function must be passed <ul>
12309 * <li>The Record block object</li>
12310 * <li>The "arg" argument from the load function</li>
12311 * <li>A boolean success indicator</li>
12313 * @param {Object} scope The scope in which to call the callback
12314 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12316 load : function(params, reader, callback, scope, arg){
12317 params = params || {};
12320 result = reader.readRecords(this.data);
12322 this.fireEvent("loadexception", this, arg, null, e);
12323 callback.call(scope, null, arg, false);
12326 callback.call(scope, result, arg, true);
12330 update : function(params, records){
12335 * Ext JS Library 1.1.1
12336 * Copyright(c) 2006-2007, Ext JS, LLC.
12338 * Originally Released Under LGPL - original licence link has changed is not relivant.
12341 * <script type="text/javascript">
12344 * @class Roo.data.HttpProxy
12345 * @extends Roo.data.DataProxy
12346 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12347 * configured to reference a certain URL.<br><br>
12349 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12350 * from which the running page was served.<br><br>
12352 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12354 * Be aware that to enable the browser to parse an XML document, the server must set
12355 * the Content-Type header in the HTTP response to "text/xml".
12357 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12358 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12359 * will be used to make the request.
12361 Roo.data.HttpProxy = function(conn){
12362 Roo.data.HttpProxy.superclass.constructor.call(this);
12363 // is conn a conn config or a real conn?
12365 this.useAjax = !conn || !conn.events;
12369 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12370 // thse are take from connection...
12373 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12376 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12377 * extra parameters to each request made by this object. (defaults to undefined)
12380 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12381 * to each request made by this object. (defaults to undefined)
12384 * @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)
12387 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12390 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12396 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12400 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12401 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12402 * a finer-grained basis than the DataProxy events.
12404 getConnection : function(){
12405 return this.useAjax ? Roo.Ajax : this.conn;
12409 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12410 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12411 * process that block using the passed callback.
12412 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12413 * for the request to the remote server.
12414 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12415 * object into a block of Roo.data.Records.
12416 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12417 * The function must be passed <ul>
12418 * <li>The Record block object</li>
12419 * <li>The "arg" argument from the load function</li>
12420 * <li>A boolean success indicator</li>
12422 * @param {Object} scope The scope in which to call the callback
12423 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12425 load : function(params, reader, callback, scope, arg){
12426 if(this.fireEvent("beforeload", this, params) !== false){
12428 params : params || {},
12430 callback : callback,
12435 callback : this.loadResponse,
12439 Roo.applyIf(o, this.conn);
12440 if(this.activeRequest){
12441 Roo.Ajax.abort(this.activeRequest);
12443 this.activeRequest = Roo.Ajax.request(o);
12445 this.conn.request(o);
12448 callback.call(scope||this, null, arg, false);
12453 loadResponse : function(o, success, response){
12454 delete this.activeRequest;
12456 this.fireEvent("loadexception", this, o, response);
12457 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12462 result = o.reader.read(response);
12464 this.fireEvent("loadexception", this, o, response, e);
12465 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12469 this.fireEvent("load", this, o, o.request.arg);
12470 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12474 update : function(dataSet){
12479 updateResponse : function(dataSet){
12484 * Ext JS Library 1.1.1
12485 * Copyright(c) 2006-2007, Ext JS, LLC.
12487 * Originally Released Under LGPL - original licence link has changed is not relivant.
12490 * <script type="text/javascript">
12494 * @class Roo.data.ScriptTagProxy
12495 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12496 * other than the originating domain of the running page.<br><br>
12498 * <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
12499 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12501 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12502 * source code that is used as the source inside a <script> tag.<br><br>
12504 * In order for the browser to process the returned data, the server must wrap the data object
12505 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12506 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12507 * depending on whether the callback name was passed:
12510 boolean scriptTag = false;
12511 String cb = request.getParameter("callback");
12514 response.setContentType("text/javascript");
12516 response.setContentType("application/x-json");
12518 Writer out = response.getWriter();
12520 out.write(cb + "(");
12522 out.print(dataBlock.toJsonString());
12529 * @param {Object} config A configuration object.
12531 Roo.data.ScriptTagProxy = function(config){
12532 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12533 Roo.apply(this, config);
12534 this.head = document.getElementsByTagName("head")[0];
12537 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12539 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12541 * @cfg {String} url The URL from which to request the data object.
12544 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12548 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12549 * the server the name of the callback function set up by the load call to process the returned data object.
12550 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12551 * javascript output which calls this named function passing the data object as its only parameter.
12553 callbackParam : "callback",
12555 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12556 * name to the request.
12561 * Load data from the configured URL, read the data object into
12562 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12563 * process that block using the passed callback.
12564 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12565 * for the request to the remote server.
12566 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12567 * object into a block of Roo.data.Records.
12568 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12569 * The function must be passed <ul>
12570 * <li>The Record block object</li>
12571 * <li>The "arg" argument from the load function</li>
12572 * <li>A boolean success indicator</li>
12574 * @param {Object} scope The scope in which to call the callback
12575 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12577 load : function(params, reader, callback, scope, arg){
12578 if(this.fireEvent("beforeload", this, params) !== false){
12580 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12582 var url = this.url;
12583 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12585 url += "&_dc=" + (new Date().getTime());
12587 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12590 cb : "stcCallback"+transId,
12591 scriptId : "stcScript"+transId,
12595 callback : callback,
12601 window[trans.cb] = function(o){
12602 conn.handleResponse(o, trans);
12605 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12607 if(this.autoAbort !== false){
12611 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12613 var script = document.createElement("script");
12614 script.setAttribute("src", url);
12615 script.setAttribute("type", "text/javascript");
12616 script.setAttribute("id", trans.scriptId);
12617 this.head.appendChild(script);
12619 this.trans = trans;
12621 callback.call(scope||this, null, arg, false);
12626 isLoading : function(){
12627 return this.trans ? true : false;
12631 * Abort the current server request.
12633 abort : function(){
12634 if(this.isLoading()){
12635 this.destroyTrans(this.trans);
12640 destroyTrans : function(trans, isLoaded){
12641 this.head.removeChild(document.getElementById(trans.scriptId));
12642 clearTimeout(trans.timeoutId);
12644 window[trans.cb] = undefined;
12646 delete window[trans.cb];
12649 // if hasn't been loaded, wait for load to remove it to prevent script error
12650 window[trans.cb] = function(){
12651 window[trans.cb] = undefined;
12653 delete window[trans.cb];
12660 handleResponse : function(o, trans){
12661 this.trans = false;
12662 this.destroyTrans(trans, true);
12665 result = trans.reader.readRecords(o);
12667 this.fireEvent("loadexception", this, o, trans.arg, e);
12668 trans.callback.call(trans.scope||window, null, trans.arg, false);
12671 this.fireEvent("load", this, o, trans.arg);
12672 trans.callback.call(trans.scope||window, result, trans.arg, true);
12676 handleFailure : function(trans){
12677 this.trans = false;
12678 this.destroyTrans(trans, false);
12679 this.fireEvent("loadexception", this, null, trans.arg);
12680 trans.callback.call(trans.scope||window, null, trans.arg, false);
12684 * Ext JS Library 1.1.1
12685 * Copyright(c) 2006-2007, Ext JS, LLC.
12687 * Originally Released Under LGPL - original licence link has changed is not relivant.
12690 * <script type="text/javascript">
12694 * @class Roo.data.JsonReader
12695 * @extends Roo.data.DataReader
12696 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12697 * based on mappings in a provided Roo.data.Record constructor.
12699 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12700 * in the reply previously.
12705 var RecordDef = Roo.data.Record.create([
12706 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12707 {name: 'occupation'} // This field will use "occupation" as the mapping.
12709 var myReader = new Roo.data.JsonReader({
12710 totalProperty: "results", // The property which contains the total dataset size (optional)
12711 root: "rows", // The property which contains an Array of row objects
12712 id: "id" // The property within each row object that provides an ID for the record (optional)
12716 * This would consume a JSON file like this:
12718 { 'results': 2, 'rows': [
12719 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12720 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12723 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12724 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12725 * paged from the remote server.
12726 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12727 * @cfg {String} root name of the property which contains the Array of row objects.
12728 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12729 * @cfg {Array} fields Array of field definition objects
12731 * Create a new JsonReader
12732 * @param {Object} meta Metadata configuration options
12733 * @param {Object} recordType Either an Array of field definition objects,
12734 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12736 Roo.data.JsonReader = function(meta, recordType){
12739 // set some defaults:
12740 Roo.applyIf(meta, {
12741 totalProperty: 'total',
12742 successProperty : 'success',
12747 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12749 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12752 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12753 * Used by Store query builder to append _requestMeta to params.
12756 metaFromRemote : false,
12758 * This method is only used by a DataProxy which has retrieved data from a remote server.
12759 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12760 * @return {Object} data A data block which is used by an Roo.data.Store object as
12761 * a cache of Roo.data.Records.
12763 read : function(response){
12764 var json = response.responseText;
12766 var o = /* eval:var:o */ eval("("+json+")");
12768 throw {message: "JsonReader.read: Json object not found"};
12774 this.metaFromRemote = true;
12775 this.meta = o.metaData;
12776 this.recordType = Roo.data.Record.create(o.metaData.fields);
12777 this.onMetaChange(this.meta, this.recordType, o);
12779 return this.readRecords(o);
12782 // private function a store will implement
12783 onMetaChange : function(meta, recordType, o){
12790 simpleAccess: function(obj, subsc) {
12797 getJsonAccessor: function(){
12799 return function(expr) {
12801 return(re.test(expr))
12802 ? new Function("obj", "return obj." + expr)
12807 return Roo.emptyFn;
12812 * Create a data block containing Roo.data.Records from an XML document.
12813 * @param {Object} o An object which contains an Array of row objects in the property specified
12814 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12815 * which contains the total size of the dataset.
12816 * @return {Object} data A data block which is used by an Roo.data.Store object as
12817 * a cache of Roo.data.Records.
12819 readRecords : function(o){
12821 * After any data loads, the raw JSON data is available for further custom processing.
12825 var s = this.meta, Record = this.recordType,
12826 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12828 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12830 if(s.totalProperty) {
12831 this.getTotal = this.getJsonAccessor(s.totalProperty);
12833 if(s.successProperty) {
12834 this.getSuccess = this.getJsonAccessor(s.successProperty);
12836 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12838 var g = this.getJsonAccessor(s.id);
12839 this.getId = function(rec) {
12841 return (r === undefined || r === "") ? null : r;
12844 this.getId = function(){return null;};
12847 for(var jj = 0; jj < fl; jj++){
12849 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12850 this.ef[jj] = this.getJsonAccessor(map);
12854 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12855 if(s.totalProperty){
12856 var vt = parseInt(this.getTotal(o), 10);
12861 if(s.successProperty){
12862 var vs = this.getSuccess(o);
12863 if(vs === false || vs === 'false'){
12868 for(var i = 0; i < c; i++){
12871 var id = this.getId(n);
12872 for(var j = 0; j < fl; j++){
12874 var v = this.ef[j](n);
12876 Roo.log('missing convert for ' + f.name);
12880 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12882 var record = new Record(values, id);
12884 records[i] = record;
12890 totalRecords : totalRecords
12895 * Ext JS Library 1.1.1
12896 * Copyright(c) 2006-2007, Ext JS, LLC.
12898 * Originally Released Under LGPL - original licence link has changed is not relivant.
12901 * <script type="text/javascript">
12905 * @class Roo.data.ArrayReader
12906 * @extends Roo.data.DataReader
12907 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12908 * Each element of that Array represents a row of data fields. The
12909 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12910 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12914 var RecordDef = Roo.data.Record.create([
12915 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12916 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12918 var myReader = new Roo.data.ArrayReader({
12919 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12923 * This would consume an Array like this:
12925 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12927 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12929 * Create a new JsonReader
12930 * @param {Object} meta Metadata configuration options.
12931 * @param {Object} recordType Either an Array of field definition objects
12932 * as specified to {@link Roo.data.Record#create},
12933 * or an {@link Roo.data.Record} object
12934 * created using {@link Roo.data.Record#create}.
12936 Roo.data.ArrayReader = function(meta, recordType){
12937 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12940 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12942 * Create a data block containing Roo.data.Records from an XML document.
12943 * @param {Object} o An Array of row objects which represents the dataset.
12944 * @return {Object} data A data block which is used by an Roo.data.Store object as
12945 * a cache of Roo.data.Records.
12947 readRecords : function(o){
12948 var sid = this.meta ? this.meta.id : null;
12949 var recordType = this.recordType, fields = recordType.prototype.fields;
12952 for(var i = 0; i < root.length; i++){
12955 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12956 for(var j = 0, jlen = fields.length; j < jlen; j++){
12957 var f = fields.items[j];
12958 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12959 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12961 values[f.name] = v;
12963 var record = new recordType(values, id);
12965 records[records.length] = record;
12969 totalRecords : records.length
12978 * @class Roo.bootstrap.ComboBox
12979 * @extends Roo.bootstrap.TriggerField
12980 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12981 * @cfg {Boolean} append (true|false) default false
12982 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12983 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12984 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12985 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12986 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12987 * @cfg {Boolean} animate default true
12988 * @cfg {Boolean} emptyResultText only for touch device
12989 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12990 * @cfg {String} emptyTitle default ''
12992 * Create a new ComboBox.
12993 * @param {Object} config Configuration options
12995 Roo.bootstrap.ComboBox = function(config){
12996 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13000 * Fires when the dropdown list is expanded
13001 * @param {Roo.bootstrap.ComboBox} combo This combo box
13006 * Fires when the dropdown list is collapsed
13007 * @param {Roo.bootstrap.ComboBox} combo This combo box
13011 * @event beforeselect
13012 * Fires before a list item is selected. Return false to cancel the selection.
13013 * @param {Roo.bootstrap.ComboBox} combo This combo box
13014 * @param {Roo.data.Record} record The data record returned from the underlying store
13015 * @param {Number} index The index of the selected item in the dropdown list
13017 'beforeselect' : true,
13020 * Fires when a list item is selected
13021 * @param {Roo.bootstrap.ComboBox} combo This combo box
13022 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13023 * @param {Number} index The index of the selected item in the dropdown list
13027 * @event beforequery
13028 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13029 * The event object passed has these properties:
13030 * @param {Roo.bootstrap.ComboBox} combo This combo box
13031 * @param {String} query The query
13032 * @param {Boolean} forceAll true to force "all" query
13033 * @param {Boolean} cancel true to cancel the query
13034 * @param {Object} e The query event object
13036 'beforequery': true,
13039 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13040 * @param {Roo.bootstrap.ComboBox} combo This combo box
13045 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13046 * @param {Roo.bootstrap.ComboBox} combo This combo box
13047 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13052 * Fires when the remove value from the combobox array
13053 * @param {Roo.bootstrap.ComboBox} combo This combo box
13057 * @event afterremove
13058 * Fires when the remove value from the combobox array
13059 * @param {Roo.bootstrap.ComboBox} combo This combo box
13061 'afterremove' : true,
13063 * @event specialfilter
13064 * Fires when specialfilter
13065 * @param {Roo.bootstrap.ComboBox} combo This combo box
13067 'specialfilter' : true,
13070 * Fires when tick the element
13071 * @param {Roo.bootstrap.ComboBox} combo This combo box
13075 * @event touchviewdisplay
13076 * Fires when touch view require special display (default is using displayField)
13077 * @param {Roo.bootstrap.ComboBox} combo This combo box
13078 * @param {Object} cfg set html .
13080 'touchviewdisplay' : true
13085 this.tickItems = [];
13087 this.selectedIndex = -1;
13088 if(this.mode == 'local'){
13089 if(config.queryDelay === undefined){
13090 this.queryDelay = 10;
13092 if(config.minChars === undefined){
13098 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13101 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13102 * rendering into an Roo.Editor, defaults to false)
13105 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13106 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13109 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13112 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13113 * the dropdown list (defaults to undefined, with no header element)
13117 * @cfg {String/Roo.Template} tpl The template to use to render the output
13121 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13123 listWidth: undefined,
13125 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13126 * mode = 'remote' or 'text' if mode = 'local')
13128 displayField: undefined,
13131 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13132 * mode = 'remote' or 'value' if mode = 'local').
13133 * Note: use of a valueField requires the user make a selection
13134 * in order for a value to be mapped.
13136 valueField: undefined,
13138 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13143 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13144 * field's data value (defaults to the underlying DOM element's name)
13146 hiddenName: undefined,
13148 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13152 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13154 selectedClass: 'active',
13157 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13161 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13162 * anchor positions (defaults to 'tl-bl')
13164 listAlign: 'tl-bl?',
13166 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13170 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13171 * query specified by the allQuery config option (defaults to 'query')
13173 triggerAction: 'query',
13175 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13176 * (defaults to 4, does not apply if editable = false)
13180 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13181 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13185 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13186 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13190 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13191 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13195 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13196 * when editable = true (defaults to false)
13198 selectOnFocus:false,
13200 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13202 queryParam: 'query',
13204 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13205 * when mode = 'remote' (defaults to 'Loading...')
13207 loadingText: 'Loading...',
13209 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13213 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13217 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13218 * traditional select (defaults to true)
13222 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13226 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13230 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13231 * listWidth has a higher value)
13235 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13236 * allow the user to set arbitrary text into the field (defaults to false)
13238 forceSelection:false,
13240 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13241 * if typeAhead = true (defaults to 250)
13243 typeAheadDelay : 250,
13245 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13246 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13248 valueNotFoundText : undefined,
13250 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13252 blockFocus : false,
13255 * @cfg {Boolean} disableClear Disable showing of clear button.
13257 disableClear : false,
13259 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13261 alwaysQuery : false,
13264 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13269 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13271 invalidClass : "has-warning",
13274 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13276 validClass : "has-success",
13279 * @cfg {Boolean} specialFilter (true|false) special filter default false
13281 specialFilter : false,
13284 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13286 mobileTouchView : true,
13289 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13291 useNativeIOS : false,
13294 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13296 mobile_restrict_height : false,
13298 ios_options : false,
13310 btnPosition : 'right',
13311 triggerList : true,
13312 showToggleBtn : true,
13314 emptyResultText: 'Empty',
13315 triggerText : 'Select',
13318 // element that contains real text value.. (when hidden is used..)
13320 getAutoCreate : function()
13325 * Render classic select for iso
13328 if(Roo.isIOS && this.useNativeIOS){
13329 cfg = this.getAutoCreateNativeIOS();
13337 if(Roo.isTouch && this.mobileTouchView){
13338 cfg = this.getAutoCreateTouchView();
13345 if(!this.tickable){
13346 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13351 * ComboBox with tickable selections
13354 var align = this.labelAlign || this.parentLabelAlign();
13357 cls : 'form-group roo-combobox-tickable' //input-group
13360 var btn_text_select = '';
13361 var btn_text_done = '';
13362 var btn_text_cancel = '';
13364 if (this.btn_text_show) {
13365 btn_text_select = 'Select';
13366 btn_text_done = 'Done';
13367 btn_text_cancel = 'Cancel';
13372 cls : 'tickable-buttons',
13377 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13378 //html : this.triggerText
13379 html: btn_text_select
13385 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13387 html: btn_text_done
13393 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13395 html: btn_text_cancel
13401 buttons.cn.unshift({
13403 cls: 'roo-select2-search-field-input'
13409 Roo.each(buttons.cn, function(c){
13411 c.cls += ' btn-' + _this.size;
13414 if (_this.disabled) {
13421 style : 'display: contents',
13426 cls: 'form-hidden-field'
13430 cls: 'roo-select2-choices',
13434 cls: 'roo-select2-search-field',
13445 cls: 'roo-select2-container input-group roo-select2-container-multi',
13451 // cls: 'typeahead typeahead-long dropdown-menu',
13452 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13457 if(this.hasFeedback && !this.allowBlank){
13461 cls: 'glyphicon form-control-feedback'
13464 combobox.cn.push(feedback);
13469 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13470 tooltip : 'This field is required'
13472 if (Roo.bootstrap.version == 4) {
13475 style : 'display:none'
13478 if (align ==='left' && this.fieldLabel.length) {
13480 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13487 cls : 'control-label col-form-label',
13488 html : this.fieldLabel
13500 var labelCfg = cfg.cn[1];
13501 var contentCfg = cfg.cn[2];
13504 if(this.indicatorpos == 'right'){
13510 cls : 'control-label col-form-label',
13514 html : this.fieldLabel
13530 labelCfg = cfg.cn[0];
13531 contentCfg = cfg.cn[1];
13535 if(this.labelWidth > 12){
13536 labelCfg.style = "width: " + this.labelWidth + 'px';
13539 if(this.labelWidth < 13 && this.labelmd == 0){
13540 this.labelmd = this.labelWidth;
13543 if(this.labellg > 0){
13544 labelCfg.cls += ' col-lg-' + this.labellg;
13545 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13548 if(this.labelmd > 0){
13549 labelCfg.cls += ' col-md-' + this.labelmd;
13550 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13553 if(this.labelsm > 0){
13554 labelCfg.cls += ' col-sm-' + this.labelsm;
13555 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13558 if(this.labelxs > 0){
13559 labelCfg.cls += ' col-xs-' + this.labelxs;
13560 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13564 } else if ( this.fieldLabel.length) {
13565 // Roo.log(" label");
13570 //cls : 'input-group-addon',
13571 html : this.fieldLabel
13576 if(this.indicatorpos == 'right'){
13580 //cls : 'input-group-addon',
13581 html : this.fieldLabel
13591 // Roo.log(" no label && no align");
13598 ['xs','sm','md','lg'].map(function(size){
13599 if (settings[size]) {
13600 cfg.cls += ' col-' + size + '-' + settings[size];
13608 _initEventsCalled : false,
13611 initEvents: function()
13613 if (this._initEventsCalled) { // as we call render... prevent looping...
13616 this._initEventsCalled = true;
13619 throw "can not find store for combo";
13622 this.indicator = this.indicatorEl();
13624 this.store = Roo.factory(this.store, Roo.data);
13625 this.store.parent = this;
13627 // if we are building from html. then this element is so complex, that we can not really
13628 // use the rendered HTML.
13629 // so we have to trash and replace the previous code.
13630 if (Roo.XComponent.build_from_html) {
13631 // remove this element....
13632 var e = this.el.dom, k=0;
13633 while (e ) { e = e.previousSibling; ++k;}
13638 this.rendered = false;
13640 this.render(this.parent().getChildContainer(true), k);
13643 if(Roo.isIOS && this.useNativeIOS){
13644 this.initIOSView();
13652 if(Roo.isTouch && this.mobileTouchView){
13653 this.initTouchView();
13658 this.initTickableEvents();
13662 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13664 if(this.hiddenName){
13666 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13668 this.hiddenField.dom.value =
13669 this.hiddenValue !== undefined ? this.hiddenValue :
13670 this.value !== undefined ? this.value : '';
13672 // prevent input submission
13673 this.el.dom.removeAttribute('name');
13674 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13679 // this.el.dom.setAttribute('autocomplete', 'off');
13682 var cls = 'x-combo-list';
13684 //this.list = new Roo.Layer({
13685 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13691 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13692 _this.list.setWidth(lw);
13695 this.list.on('mouseover', this.onViewOver, this);
13696 this.list.on('mousemove', this.onViewMove, this);
13697 this.list.on('scroll', this.onViewScroll, this);
13700 this.list.swallowEvent('mousewheel');
13701 this.assetHeight = 0;
13704 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13705 this.assetHeight += this.header.getHeight();
13708 this.innerList = this.list.createChild({cls:cls+'-inner'});
13709 this.innerList.on('mouseover', this.onViewOver, this);
13710 this.innerList.on('mousemove', this.onViewMove, this);
13711 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13713 if(this.allowBlank && !this.pageSize && !this.disableClear){
13714 this.footer = this.list.createChild({cls:cls+'-ft'});
13715 this.pageTb = new Roo.Toolbar(this.footer);
13719 this.footer = this.list.createChild({cls:cls+'-ft'});
13720 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13721 {pageSize: this.pageSize});
13725 if (this.pageTb && this.allowBlank && !this.disableClear) {
13727 this.pageTb.add(new Roo.Toolbar.Fill(), {
13728 cls: 'x-btn-icon x-btn-clear',
13730 handler: function()
13733 _this.clearValue();
13734 _this.onSelect(false, -1);
13739 this.assetHeight += this.footer.getHeight();
13744 this.tpl = Roo.bootstrap.version == 4 ?
13745 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13746 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13749 this.view = new Roo.View(this.list, this.tpl, {
13750 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13752 //this.view.wrapEl.setDisplayed(false);
13753 this.view.on('click', this.onViewClick, this);
13756 this.store.on('beforeload', this.onBeforeLoad, this);
13757 this.store.on('load', this.onLoad, this);
13758 this.store.on('loadexception', this.onLoadException, this);
13760 if(this.resizable){
13761 this.resizer = new Roo.Resizable(this.list, {
13762 pinned:true, handles:'se'
13764 this.resizer.on('resize', function(r, w, h){
13765 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13766 this.listWidth = w;
13767 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13768 this.restrictHeight();
13770 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13773 if(!this.editable){
13774 this.editable = true;
13775 this.setEditable(false);
13780 if (typeof(this.events.add.listeners) != 'undefined') {
13782 this.addicon = this.wrap.createChild(
13783 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13785 this.addicon.on('click', function(e) {
13786 this.fireEvent('add', this);
13789 if (typeof(this.events.edit.listeners) != 'undefined') {
13791 this.editicon = this.wrap.createChild(
13792 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13793 if (this.addicon) {
13794 this.editicon.setStyle('margin-left', '40px');
13796 this.editicon.on('click', function(e) {
13798 // we fire even if inothing is selected..
13799 this.fireEvent('edit', this, this.lastData );
13805 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13806 "up" : function(e){
13807 this.inKeyMode = true;
13811 "down" : function(e){
13812 if(!this.isExpanded()){
13813 this.onTriggerClick();
13815 this.inKeyMode = true;
13820 "enter" : function(e){
13821 // this.onViewClick();
13825 if(this.fireEvent("specialkey", this, e)){
13826 this.onViewClick(false);
13832 "esc" : function(e){
13836 "tab" : function(e){
13839 if(this.fireEvent("specialkey", this, e)){
13840 this.onViewClick(false);
13848 doRelay : function(foo, bar, hname){
13849 if(hname == 'down' || this.scope.isExpanded()){
13850 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13859 this.queryDelay = Math.max(this.queryDelay || 10,
13860 this.mode == 'local' ? 10 : 250);
13863 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13865 if(this.typeAhead){
13866 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13868 if(this.editable !== false){
13869 this.inputEl().on("keyup", this.onKeyUp, this);
13871 if(this.forceSelection){
13872 this.inputEl().on('blur', this.doForce, this);
13876 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13877 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13881 initTickableEvents: function()
13885 if(this.hiddenName){
13887 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13889 this.hiddenField.dom.value =
13890 this.hiddenValue !== undefined ? this.hiddenValue :
13891 this.value !== undefined ? this.value : '';
13893 // prevent input submission
13894 this.el.dom.removeAttribute('name');
13895 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13900 // this.list = this.el.select('ul.dropdown-menu',true).first();
13902 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13903 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13904 if(this.triggerList){
13905 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13908 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13909 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13911 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13912 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13914 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13915 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13917 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13918 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13919 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13922 this.cancelBtn.hide();
13927 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13928 _this.list.setWidth(lw);
13931 this.list.on('mouseover', this.onViewOver, this);
13932 this.list.on('mousemove', this.onViewMove, this);
13934 this.list.on('scroll', this.onViewScroll, this);
13937 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13938 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13941 this.view = new Roo.View(this.list, this.tpl, {
13946 selectedClass: this.selectedClass
13949 //this.view.wrapEl.setDisplayed(false);
13950 this.view.on('click', this.onViewClick, this);
13954 this.store.on('beforeload', this.onBeforeLoad, this);
13955 this.store.on('load', this.onLoad, this);
13956 this.store.on('loadexception', this.onLoadException, this);
13959 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13960 "up" : function(e){
13961 this.inKeyMode = true;
13965 "down" : function(e){
13966 this.inKeyMode = true;
13970 "enter" : function(e){
13971 if(this.fireEvent("specialkey", this, e)){
13972 this.onViewClick(false);
13978 "esc" : function(e){
13979 this.onTickableFooterButtonClick(e, false, false);
13982 "tab" : function(e){
13983 this.fireEvent("specialkey", this, e);
13985 this.onTickableFooterButtonClick(e, false, false);
13992 doRelay : function(e, fn, key){
13993 if(this.scope.isExpanded()){
13994 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14003 this.queryDelay = Math.max(this.queryDelay || 10,
14004 this.mode == 'local' ? 10 : 250);
14007 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14009 if(this.typeAhead){
14010 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14013 if(this.editable !== false){
14014 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14017 this.indicator = this.indicatorEl();
14019 if(this.indicator){
14020 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14021 this.indicator.hide();
14026 onDestroy : function(){
14028 this.view.setStore(null);
14029 this.view.el.removeAllListeners();
14030 this.view.el.remove();
14031 this.view.purgeListeners();
14034 this.list.dom.innerHTML = '';
14038 this.store.un('beforeload', this.onBeforeLoad, this);
14039 this.store.un('load', this.onLoad, this);
14040 this.store.un('loadexception', this.onLoadException, this);
14042 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14046 fireKey : function(e){
14047 if(e.isNavKeyPress() && !this.list.isVisible()){
14048 this.fireEvent("specialkey", this, e);
14053 onResize: function(w, h){
14054 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14056 // if(typeof w != 'number'){
14057 // // we do not handle it!?!?
14060 // var tw = this.trigger.getWidth();
14061 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14062 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14064 // this.inputEl().setWidth( this.adjustWidth('input', x));
14066 // //this.trigger.setStyle('left', x+'px');
14068 // if(this.list && this.listWidth === undefined){
14069 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14070 // this.list.setWidth(lw);
14071 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14079 * Allow or prevent the user from directly editing the field text. If false is passed,
14080 * the user will only be able to select from the items defined in the dropdown list. This method
14081 * is the runtime equivalent of setting the 'editable' config option at config time.
14082 * @param {Boolean} value True to allow the user to directly edit the field text
14084 setEditable : function(value){
14085 if(value == this.editable){
14088 this.editable = value;
14090 this.inputEl().dom.setAttribute('readOnly', true);
14091 this.inputEl().on('mousedown', this.onTriggerClick, this);
14092 this.inputEl().addClass('x-combo-noedit');
14094 this.inputEl().dom.setAttribute('readOnly', false);
14095 this.inputEl().un('mousedown', this.onTriggerClick, this);
14096 this.inputEl().removeClass('x-combo-noedit');
14102 onBeforeLoad : function(combo,opts){
14103 if(!this.hasFocus){
14107 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14109 this.restrictHeight();
14110 this.selectedIndex = -1;
14114 onLoad : function(){
14116 this.hasQuery = false;
14118 if(!this.hasFocus){
14122 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14123 this.loading.hide();
14126 if(this.store.getCount() > 0){
14129 this.restrictHeight();
14130 if(this.lastQuery == this.allQuery){
14131 if(this.editable && !this.tickable){
14132 this.inputEl().dom.select();
14136 !this.selectByValue(this.value, true) &&
14139 !this.store.lastOptions ||
14140 typeof(this.store.lastOptions.add) == 'undefined' ||
14141 this.store.lastOptions.add != true
14144 this.select(0, true);
14147 if(this.autoFocus){
14150 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14151 this.taTask.delay(this.typeAheadDelay);
14155 this.onEmptyResults();
14161 onLoadException : function()
14163 this.hasQuery = false;
14165 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14166 this.loading.hide();
14169 if(this.tickable && this.editable){
14174 // only causes errors at present
14175 //Roo.log(this.store.reader.jsonData);
14176 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14178 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14184 onTypeAhead : function(){
14185 if(this.store.getCount() > 0){
14186 var r = this.store.getAt(0);
14187 var newValue = r.data[this.displayField];
14188 var len = newValue.length;
14189 var selStart = this.getRawValue().length;
14191 if(selStart != len){
14192 this.setRawValue(newValue);
14193 this.selectText(selStart, newValue.length);
14199 onSelect : function(record, index){
14201 if(this.fireEvent('beforeselect', this, record, index) !== false){
14203 this.setFromData(index > -1 ? record.data : false);
14206 this.fireEvent('select', this, record, index);
14211 * Returns the currently selected field value or empty string if no value is set.
14212 * @return {String} value The selected value
14214 getValue : function()
14216 if(Roo.isIOS && this.useNativeIOS){
14217 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14221 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14224 if(this.valueField){
14225 return typeof this.value != 'undefined' ? this.value : '';
14227 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14231 getRawValue : function()
14233 if(Roo.isIOS && this.useNativeIOS){
14234 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14237 var v = this.inputEl().getValue();
14243 * Clears any text/value currently set in the field
14245 clearValue : function(){
14247 if(this.hiddenField){
14248 this.hiddenField.dom.value = '';
14251 this.setRawValue('');
14252 this.lastSelectionText = '';
14253 this.lastData = false;
14255 var close = this.closeTriggerEl();
14266 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14267 * will be displayed in the field. If the value does not match the data value of an existing item,
14268 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14269 * Otherwise the field will be blank (although the value will still be set).
14270 * @param {String} value The value to match
14272 setValue : function(v)
14274 if(Roo.isIOS && this.useNativeIOS){
14275 this.setIOSValue(v);
14285 if(this.valueField){
14286 var r = this.findRecord(this.valueField, v);
14288 text = r.data[this.displayField];
14289 }else if(this.valueNotFoundText !== undefined){
14290 text = this.valueNotFoundText;
14293 this.lastSelectionText = text;
14294 if(this.hiddenField){
14295 this.hiddenField.dom.value = v;
14297 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14300 var close = this.closeTriggerEl();
14303 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14309 * @property {Object} the last set data for the element
14314 * Sets the value of the field based on a object which is related to the record format for the store.
14315 * @param {Object} value the value to set as. or false on reset?
14317 setFromData : function(o){
14324 var dv = ''; // display value
14325 var vv = ''; // value value..
14327 if (this.displayField) {
14328 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14330 // this is an error condition!!!
14331 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14334 if(this.valueField){
14335 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14338 var close = this.closeTriggerEl();
14341 if(dv.length || vv * 1 > 0){
14343 this.blockFocus=true;
14349 if(this.hiddenField){
14350 this.hiddenField.dom.value = vv;
14352 this.lastSelectionText = dv;
14353 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14357 // no hidden field.. - we store the value in 'value', but still display
14358 // display field!!!!
14359 this.lastSelectionText = dv;
14360 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14367 reset : function(){
14368 // overridden so that last data is reset..
14375 this.setValue(this.originalValue);
14376 //this.clearInvalid();
14377 this.lastData = false;
14379 this.view.clearSelections();
14385 findRecord : function(prop, value){
14387 if(this.store.getCount() > 0){
14388 this.store.each(function(r){
14389 if(r.data[prop] == value){
14399 getName: function()
14401 // returns hidden if it's set..
14402 if (!this.rendered) {return ''};
14403 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14407 onViewMove : function(e, t){
14408 this.inKeyMode = false;
14412 onViewOver : function(e, t){
14413 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14416 var item = this.view.findItemFromChild(t);
14419 var index = this.view.indexOf(item);
14420 this.select(index, false);
14425 onViewClick : function(view, doFocus, el, e)
14427 var index = this.view.getSelectedIndexes()[0];
14429 var r = this.store.getAt(index);
14433 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14440 Roo.each(this.tickItems, function(v,k){
14442 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14444 _this.tickItems.splice(k, 1);
14446 if(typeof(e) == 'undefined' && view == false){
14447 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14459 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14460 this.tickItems.push(r.data);
14463 if(typeof(e) == 'undefined' && view == false){
14464 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14471 this.onSelect(r, index);
14473 if(doFocus !== false && !this.blockFocus){
14474 this.inputEl().focus();
14479 restrictHeight : function(){
14480 //this.innerList.dom.style.height = '';
14481 //var inner = this.innerList.dom;
14482 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14483 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14484 //this.list.beginUpdate();
14485 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14486 this.list.alignTo(this.inputEl(), this.listAlign);
14487 this.list.alignTo(this.inputEl(), this.listAlign);
14488 //this.list.endUpdate();
14492 onEmptyResults : function(){
14494 if(this.tickable && this.editable){
14495 this.hasFocus = false;
14496 this.restrictHeight();
14504 * Returns true if the dropdown list is expanded, else false.
14506 isExpanded : function(){
14507 return this.list.isVisible();
14511 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14512 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14513 * @param {String} value The data value of the item to select
14514 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14515 * selected item if it is not currently in view (defaults to true)
14516 * @return {Boolean} True if the value matched an item in the list, else false
14518 selectByValue : function(v, scrollIntoView){
14519 if(v !== undefined && v !== null){
14520 var r = this.findRecord(this.valueField || this.displayField, v);
14522 this.select(this.store.indexOf(r), scrollIntoView);
14530 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14531 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14532 * @param {Number} index The zero-based index of the list item to select
14533 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14534 * selected item if it is not currently in view (defaults to true)
14536 select : function(index, scrollIntoView){
14537 this.selectedIndex = index;
14538 this.view.select(index);
14539 if(scrollIntoView !== false){
14540 var el = this.view.getNode(index);
14542 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14545 this.list.scrollChildIntoView(el, false);
14551 selectNext : function(){
14552 var ct = this.store.getCount();
14554 if(this.selectedIndex == -1){
14556 }else if(this.selectedIndex < ct-1){
14557 this.select(this.selectedIndex+1);
14563 selectPrev : function(){
14564 var ct = this.store.getCount();
14566 if(this.selectedIndex == -1){
14568 }else if(this.selectedIndex != 0){
14569 this.select(this.selectedIndex-1);
14575 onKeyUp : function(e){
14576 if(this.editable !== false && !e.isSpecialKey()){
14577 this.lastKey = e.getKey();
14578 this.dqTask.delay(this.queryDelay);
14583 validateBlur : function(){
14584 return !this.list || !this.list.isVisible();
14588 initQuery : function(){
14590 var v = this.getRawValue();
14592 if(this.tickable && this.editable){
14593 v = this.tickableInputEl().getValue();
14600 doForce : function(){
14601 if(this.inputEl().dom.value.length > 0){
14602 this.inputEl().dom.value =
14603 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14609 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14610 * query allowing the query action to be canceled if needed.
14611 * @param {String} query The SQL query to execute
14612 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14613 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14614 * saved in the current store (defaults to false)
14616 doQuery : function(q, forceAll){
14618 if(q === undefined || q === null){
14623 forceAll: forceAll,
14627 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14632 forceAll = qe.forceAll;
14633 if(forceAll === true || (q.length >= this.minChars)){
14635 this.hasQuery = true;
14637 if(this.lastQuery != q || this.alwaysQuery){
14638 this.lastQuery = q;
14639 if(this.mode == 'local'){
14640 this.selectedIndex = -1;
14642 this.store.clearFilter();
14645 if(this.specialFilter){
14646 this.fireEvent('specialfilter', this);
14651 this.store.filter(this.displayField, q);
14654 this.store.fireEvent("datachanged", this.store);
14661 this.store.baseParams[this.queryParam] = q;
14663 var options = {params : this.getParams(q)};
14666 options.add = true;
14667 options.params.start = this.page * this.pageSize;
14670 this.store.load(options);
14673 * this code will make the page width larger, at the beginning, the list not align correctly,
14674 * we should expand the list on onLoad
14675 * so command out it
14680 this.selectedIndex = -1;
14685 this.loadNext = false;
14689 getParams : function(q){
14691 //p[this.queryParam] = q;
14695 p.limit = this.pageSize;
14701 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14703 collapse : function(){
14704 if(!this.isExpanded()){
14710 this.hasFocus = false;
14714 this.cancelBtn.hide();
14715 this.trigger.show();
14718 this.tickableInputEl().dom.value = '';
14719 this.tickableInputEl().blur();
14724 Roo.get(document).un('mousedown', this.collapseIf, this);
14725 Roo.get(document).un('mousewheel', this.collapseIf, this);
14726 if (!this.editable) {
14727 Roo.get(document).un('keydown', this.listKeyPress, this);
14729 this.fireEvent('collapse', this);
14735 collapseIf : function(e){
14736 var in_combo = e.within(this.el);
14737 var in_list = e.within(this.list);
14738 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14740 if (in_combo || in_list || is_list) {
14741 //e.stopPropagation();
14746 this.onTickableFooterButtonClick(e, false, false);
14754 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14756 expand : function(){
14758 if(this.isExpanded() || !this.hasFocus){
14762 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14763 this.list.setWidth(lw);
14769 this.restrictHeight();
14773 this.tickItems = Roo.apply([], this.item);
14776 this.cancelBtn.show();
14777 this.trigger.hide();
14780 this.tickableInputEl().focus();
14785 Roo.get(document).on('mousedown', this.collapseIf, this);
14786 Roo.get(document).on('mousewheel', this.collapseIf, this);
14787 if (!this.editable) {
14788 Roo.get(document).on('keydown', this.listKeyPress, this);
14791 this.fireEvent('expand', this);
14795 // Implements the default empty TriggerField.onTriggerClick function
14796 onTriggerClick : function(e)
14798 Roo.log('trigger click');
14800 if(this.disabled || !this.triggerList){
14805 this.loadNext = false;
14807 if(this.isExpanded()){
14809 if (!this.blockFocus) {
14810 this.inputEl().focus();
14814 this.hasFocus = true;
14815 if(this.triggerAction == 'all') {
14816 this.doQuery(this.allQuery, true);
14818 this.doQuery(this.getRawValue());
14820 if (!this.blockFocus) {
14821 this.inputEl().focus();
14826 onTickableTriggerClick : function(e)
14833 this.loadNext = false;
14834 this.hasFocus = true;
14836 if(this.triggerAction == 'all') {
14837 this.doQuery(this.allQuery, true);
14839 this.doQuery(this.getRawValue());
14843 onSearchFieldClick : function(e)
14845 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14846 this.onTickableFooterButtonClick(e, false, false);
14850 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14855 this.loadNext = false;
14856 this.hasFocus = true;
14858 if(this.triggerAction == 'all') {
14859 this.doQuery(this.allQuery, true);
14861 this.doQuery(this.getRawValue());
14865 listKeyPress : function(e)
14867 //Roo.log('listkeypress');
14868 // scroll to first matching element based on key pres..
14869 if (e.isSpecialKey()) {
14872 var k = String.fromCharCode(e.getKey()).toUpperCase();
14875 var csel = this.view.getSelectedNodes();
14876 var cselitem = false;
14878 var ix = this.view.indexOf(csel[0]);
14879 cselitem = this.store.getAt(ix);
14880 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14886 this.store.each(function(v) {
14888 // start at existing selection.
14889 if (cselitem.id == v.id) {
14895 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14896 match = this.store.indexOf(v);
14902 if (match === false) {
14903 return true; // no more action?
14906 this.view.select(match);
14907 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14908 sn.scrollIntoView(sn.dom.parentNode, false);
14911 onViewScroll : function(e, t){
14913 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){
14917 this.hasQuery = true;
14919 this.loading = this.list.select('.loading', true).first();
14921 if(this.loading === null){
14922 this.list.createChild({
14924 cls: 'loading roo-select2-more-results roo-select2-active',
14925 html: 'Loading more results...'
14928 this.loading = this.list.select('.loading', true).first();
14930 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14932 this.loading.hide();
14935 this.loading.show();
14940 this.loadNext = true;
14942 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14947 addItem : function(o)
14949 var dv = ''; // display value
14951 if (this.displayField) {
14952 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14954 // this is an error condition!!!
14955 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14962 var choice = this.choices.createChild({
14964 cls: 'roo-select2-search-choice',
14973 cls: 'roo-select2-search-choice-close fa fa-times',
14978 }, this.searchField);
14980 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14982 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14990 this.inputEl().dom.value = '';
14995 onRemoveItem : function(e, _self, o)
14997 e.preventDefault();
14999 this.lastItem = Roo.apply([], this.item);
15001 var index = this.item.indexOf(o.data) * 1;
15004 Roo.log('not this item?!');
15008 this.item.splice(index, 1);
15013 this.fireEvent('remove', this, e);
15019 syncValue : function()
15021 if(!this.item.length){
15028 Roo.each(this.item, function(i){
15029 if(_this.valueField){
15030 value.push(i[_this.valueField]);
15037 this.value = value.join(',');
15039 if(this.hiddenField){
15040 this.hiddenField.dom.value = this.value;
15043 this.store.fireEvent("datachanged", this.store);
15048 clearItem : function()
15050 if(!this.multiple){
15056 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15064 if(this.tickable && !Roo.isTouch){
15065 this.view.refresh();
15069 inputEl: function ()
15071 if(Roo.isIOS && this.useNativeIOS){
15072 return this.el.select('select.roo-ios-select', true).first();
15075 if(Roo.isTouch && this.mobileTouchView){
15076 return this.el.select('input.form-control',true).first();
15080 return this.searchField;
15083 return this.el.select('input.form-control',true).first();
15086 onTickableFooterButtonClick : function(e, btn, el)
15088 e.preventDefault();
15090 this.lastItem = Roo.apply([], this.item);
15092 if(btn && btn.name == 'cancel'){
15093 this.tickItems = Roo.apply([], this.item);
15102 Roo.each(this.tickItems, function(o){
15110 validate : function()
15112 if(this.getVisibilityEl().hasClass('hidden')){
15116 var v = this.getRawValue();
15119 v = this.getValue();
15122 if(this.disabled || this.allowBlank || v.length){
15127 this.markInvalid();
15131 tickableInputEl : function()
15133 if(!this.tickable || !this.editable){
15134 return this.inputEl();
15137 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15141 getAutoCreateTouchView : function()
15146 cls: 'form-group' //input-group
15152 type : this.inputType,
15153 cls : 'form-control x-combo-noedit',
15154 autocomplete: 'new-password',
15155 placeholder : this.placeholder || '',
15160 input.name = this.name;
15164 input.cls += ' input-' + this.size;
15167 if (this.disabled) {
15168 input.disabled = true;
15179 inputblock.cls += ' input-group';
15181 inputblock.cn.unshift({
15183 cls : 'input-group-addon input-group-prepend input-group-text',
15188 if(this.removable && !this.multiple){
15189 inputblock.cls += ' roo-removable';
15191 inputblock.cn.push({
15194 cls : 'roo-combo-removable-btn close'
15198 if(this.hasFeedback && !this.allowBlank){
15200 inputblock.cls += ' has-feedback';
15202 inputblock.cn.push({
15204 cls: 'glyphicon form-control-feedback'
15211 inputblock.cls += (this.before) ? '' : ' input-group';
15213 inputblock.cn.push({
15215 cls : 'input-group-addon input-group-append input-group-text',
15221 var ibwrap = inputblock;
15226 cls: 'roo-select2-choices',
15230 cls: 'roo-select2-search-field',
15243 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15248 cls: 'form-hidden-field'
15254 if(!this.multiple && this.showToggleBtn){
15261 if (this.caret != false) {
15264 cls: 'fa fa-' + this.caret
15271 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15276 cls: 'combobox-clear',
15290 combobox.cls += ' roo-select2-container-multi';
15293 var align = this.labelAlign || this.parentLabelAlign();
15295 if (align ==='left' && this.fieldLabel.length) {
15300 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15301 tooltip : 'This field is required'
15305 cls : 'control-label col-form-label',
15306 html : this.fieldLabel
15317 var labelCfg = cfg.cn[1];
15318 var contentCfg = cfg.cn[2];
15321 if(this.indicatorpos == 'right'){
15326 cls : 'control-label col-form-label',
15330 html : this.fieldLabel
15334 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15335 tooltip : 'This field is required'
15348 labelCfg = cfg.cn[0];
15349 contentCfg = cfg.cn[1];
15354 if(this.labelWidth > 12){
15355 labelCfg.style = "width: " + this.labelWidth + 'px';
15358 if(this.labelWidth < 13 && this.labelmd == 0){
15359 this.labelmd = this.labelWidth;
15362 if(this.labellg > 0){
15363 labelCfg.cls += ' col-lg-' + this.labellg;
15364 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15367 if(this.labelmd > 0){
15368 labelCfg.cls += ' col-md-' + this.labelmd;
15369 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15372 if(this.labelsm > 0){
15373 labelCfg.cls += ' col-sm-' + this.labelsm;
15374 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15377 if(this.labelxs > 0){
15378 labelCfg.cls += ' col-xs-' + this.labelxs;
15379 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15383 } else if ( this.fieldLabel.length) {
15387 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15388 tooltip : 'This field is required'
15392 cls : 'control-label',
15393 html : this.fieldLabel
15404 if(this.indicatorpos == 'right'){
15408 cls : 'control-label',
15409 html : this.fieldLabel,
15413 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15414 tooltip : 'This field is required'
15431 var settings = this;
15433 ['xs','sm','md','lg'].map(function(size){
15434 if (settings[size]) {
15435 cfg.cls += ' col-' + size + '-' + settings[size];
15442 initTouchView : function()
15444 this.renderTouchView();
15446 this.touchViewEl.on('scroll', function(){
15447 this.el.dom.scrollTop = 0;
15450 this.originalValue = this.getValue();
15452 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15454 this.inputEl().on("click", this.showTouchView, this);
15455 if (this.triggerEl) {
15456 this.triggerEl.on("click", this.showTouchView, this);
15460 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15461 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15463 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15465 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15466 this.store.on('load', this.onTouchViewLoad, this);
15467 this.store.on('loadexception', this.onTouchViewLoadException, this);
15469 if(this.hiddenName){
15471 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15473 this.hiddenField.dom.value =
15474 this.hiddenValue !== undefined ? this.hiddenValue :
15475 this.value !== undefined ? this.value : '';
15477 this.el.dom.removeAttribute('name');
15478 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15482 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15483 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15486 if(this.removable && !this.multiple){
15487 var close = this.closeTriggerEl();
15489 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15490 close.on('click', this.removeBtnClick, this, close);
15494 * fix the bug in Safari iOS8
15496 this.inputEl().on("focus", function(e){
15497 document.activeElement.blur();
15500 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15507 renderTouchView : function()
15509 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15510 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15512 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15513 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15515 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15516 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15517 this.touchViewBodyEl.setStyle('overflow', 'auto');
15519 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15520 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15522 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15523 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15527 showTouchView : function()
15533 this.touchViewHeaderEl.hide();
15535 if(this.modalTitle.length){
15536 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15537 this.touchViewHeaderEl.show();
15540 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15541 this.touchViewEl.show();
15543 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15545 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15546 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15548 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15550 if(this.modalTitle.length){
15551 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15554 this.touchViewBodyEl.setHeight(bodyHeight);
15558 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15560 this.touchViewEl.addClass('in');
15563 if(this._touchViewMask){
15564 Roo.get(document.body).addClass("x-body-masked");
15565 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15566 this._touchViewMask.setStyle('z-index', 10000);
15567 this._touchViewMask.addClass('show');
15570 this.doTouchViewQuery();
15574 hideTouchView : function()
15576 this.touchViewEl.removeClass('in');
15580 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15582 this.touchViewEl.setStyle('display', 'none');
15585 if(this._touchViewMask){
15586 this._touchViewMask.removeClass('show');
15587 Roo.get(document.body).removeClass("x-body-masked");
15591 setTouchViewValue : function()
15598 Roo.each(this.tickItems, function(o){
15603 this.hideTouchView();
15606 doTouchViewQuery : function()
15615 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15619 if(!this.alwaysQuery || this.mode == 'local'){
15620 this.onTouchViewLoad();
15627 onTouchViewBeforeLoad : function(combo,opts)
15633 onTouchViewLoad : function()
15635 if(this.store.getCount() < 1){
15636 this.onTouchViewEmptyResults();
15640 this.clearTouchView();
15642 var rawValue = this.getRawValue();
15644 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15646 this.tickItems = [];
15648 this.store.data.each(function(d, rowIndex){
15649 var row = this.touchViewListGroup.createChild(template);
15651 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15652 row.addClass(d.data.cls);
15655 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15658 html : d.data[this.displayField]
15661 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15662 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15665 row.removeClass('selected');
15666 if(!this.multiple && this.valueField &&
15667 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15670 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15671 row.addClass('selected');
15674 if(this.multiple && this.valueField &&
15675 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15679 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15680 this.tickItems.push(d.data);
15683 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15687 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15689 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15691 if(this.modalTitle.length){
15692 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15695 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15697 if(this.mobile_restrict_height && listHeight < bodyHeight){
15698 this.touchViewBodyEl.setHeight(listHeight);
15703 if(firstChecked && listHeight > bodyHeight){
15704 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15709 onTouchViewLoadException : function()
15711 this.hideTouchView();
15714 onTouchViewEmptyResults : function()
15716 this.clearTouchView();
15718 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15720 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15724 clearTouchView : function()
15726 this.touchViewListGroup.dom.innerHTML = '';
15729 onTouchViewClick : function(e, el, o)
15731 e.preventDefault();
15734 var rowIndex = o.rowIndex;
15736 var r = this.store.getAt(rowIndex);
15738 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15740 if(!this.multiple){
15741 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15742 c.dom.removeAttribute('checked');
15745 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15747 this.setFromData(r.data);
15749 var close = this.closeTriggerEl();
15755 this.hideTouchView();
15757 this.fireEvent('select', this, r, rowIndex);
15762 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15763 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15764 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15768 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15769 this.addItem(r.data);
15770 this.tickItems.push(r.data);
15774 getAutoCreateNativeIOS : function()
15777 cls: 'form-group' //input-group,
15782 cls : 'roo-ios-select'
15786 combobox.name = this.name;
15789 if (this.disabled) {
15790 combobox.disabled = true;
15793 var settings = this;
15795 ['xs','sm','md','lg'].map(function(size){
15796 if (settings[size]) {
15797 cfg.cls += ' col-' + size + '-' + settings[size];
15807 initIOSView : function()
15809 this.store.on('load', this.onIOSViewLoad, this);
15814 onIOSViewLoad : function()
15816 if(this.store.getCount() < 1){
15820 this.clearIOSView();
15822 if(this.allowBlank) {
15824 var default_text = '-- SELECT --';
15826 if(this.placeholder.length){
15827 default_text = this.placeholder;
15830 if(this.emptyTitle.length){
15831 default_text += ' - ' + this.emptyTitle + ' -';
15834 var opt = this.inputEl().createChild({
15837 html : default_text
15841 o[this.valueField] = 0;
15842 o[this.displayField] = default_text;
15844 this.ios_options.push({
15851 this.store.data.each(function(d, rowIndex){
15855 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15856 html = d.data[this.displayField];
15861 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15862 value = d.data[this.valueField];
15871 if(this.value == d.data[this.valueField]){
15872 option['selected'] = true;
15875 var opt = this.inputEl().createChild(option);
15877 this.ios_options.push({
15884 this.inputEl().on('change', function(){
15885 this.fireEvent('select', this);
15890 clearIOSView: function()
15892 this.inputEl().dom.innerHTML = '';
15894 this.ios_options = [];
15897 setIOSValue: function(v)
15901 if(!this.ios_options){
15905 Roo.each(this.ios_options, function(opts){
15907 opts.el.dom.removeAttribute('selected');
15909 if(opts.data[this.valueField] != v){
15913 opts.el.dom.setAttribute('selected', true);
15919 * @cfg {Boolean} grow
15923 * @cfg {Number} growMin
15927 * @cfg {Number} growMax
15936 Roo.apply(Roo.bootstrap.ComboBox, {
15940 cls: 'modal-header',
15962 cls: 'list-group-item',
15966 cls: 'roo-combobox-list-group-item-value'
15970 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15984 listItemCheckbox : {
15986 cls: 'list-group-item',
15990 cls: 'roo-combobox-list-group-item-value'
15994 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16010 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16015 cls: 'modal-footer',
16023 cls: 'col-xs-6 text-left',
16026 cls: 'btn btn-danger roo-touch-view-cancel',
16032 cls: 'col-xs-6 text-right',
16035 cls: 'btn btn-success roo-touch-view-ok',
16046 Roo.apply(Roo.bootstrap.ComboBox, {
16048 touchViewTemplate : {
16050 cls: 'modal fade roo-combobox-touch-view',
16054 cls: 'modal-dialog',
16055 style : 'position:fixed', // we have to fix position....
16059 cls: 'modal-content',
16061 Roo.bootstrap.ComboBox.header,
16062 Roo.bootstrap.ComboBox.body,
16063 Roo.bootstrap.ComboBox.footer
16072 * Ext JS Library 1.1.1
16073 * Copyright(c) 2006-2007, Ext JS, LLC.
16075 * Originally Released Under LGPL - original licence link has changed is not relivant.
16078 * <script type="text/javascript">
16083 * @extends Roo.util.Observable
16084 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16085 * This class also supports single and multi selection modes. <br>
16086 * Create a data model bound view:
16088 var store = new Roo.data.Store(...);
16090 var view = new Roo.View({
16092 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16094 singleSelect: true,
16095 selectedClass: "ydataview-selected",
16099 // listen for node click?
16100 view.on("click", function(vw, index, node, e){
16101 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16105 dataModel.load("foobar.xml");
16107 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16109 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16110 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16112 * Note: old style constructor is still suported (container, template, config)
16115 * Create a new View
16116 * @param {Object} config The config object
16119 Roo.View = function(config, depreciated_tpl, depreciated_config){
16121 this.parent = false;
16123 if (typeof(depreciated_tpl) == 'undefined') {
16124 // new way.. - universal constructor.
16125 Roo.apply(this, config);
16126 this.el = Roo.get(this.el);
16129 this.el = Roo.get(config);
16130 this.tpl = depreciated_tpl;
16131 Roo.apply(this, depreciated_config);
16133 this.wrapEl = this.el.wrap().wrap();
16134 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16137 if(typeof(this.tpl) == "string"){
16138 this.tpl = new Roo.Template(this.tpl);
16140 // support xtype ctors..
16141 this.tpl = new Roo.factory(this.tpl, Roo);
16145 this.tpl.compile();
16150 * @event beforeclick
16151 * Fires before a click is processed. Returns false to cancel the default action.
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 "beforeclick" : true,
16160 * Fires when a template node is clicked.
16161 * @param {Roo.View} this
16162 * @param {Number} index The index of the target node
16163 * @param {HTMLElement} node The target node
16164 * @param {Roo.EventObject} e The raw event object
16169 * Fires when a template node is double clicked.
16170 * @param {Roo.View} this
16171 * @param {Number} index The index of the target node
16172 * @param {HTMLElement} node The target node
16173 * @param {Roo.EventObject} e The raw event object
16177 * @event contextmenu
16178 * Fires when a template node is right clicked.
16179 * @param {Roo.View} this
16180 * @param {Number} index The index of the target node
16181 * @param {HTMLElement} node The target node
16182 * @param {Roo.EventObject} e The raw event object
16184 "contextmenu" : true,
16186 * @event selectionchange
16187 * Fires when the selected nodes change.
16188 * @param {Roo.View} this
16189 * @param {Array} selections Array of the selected nodes
16191 "selectionchange" : true,
16194 * @event beforeselect
16195 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16196 * @param {Roo.View} this
16197 * @param {HTMLElement} node The node to be selected
16198 * @param {Array} selections Array of currently selected nodes
16200 "beforeselect" : true,
16202 * @event preparedata
16203 * Fires on every row to render, to allow you to change the data.
16204 * @param {Roo.View} this
16205 * @param {Object} data to be rendered (change this)
16207 "preparedata" : true
16215 "click": this.onClick,
16216 "dblclick": this.onDblClick,
16217 "contextmenu": this.onContextMenu,
16221 this.selections = [];
16223 this.cmp = new Roo.CompositeElementLite([]);
16225 this.store = Roo.factory(this.store, Roo.data);
16226 this.setStore(this.store, true);
16229 if ( this.footer && this.footer.xtype) {
16231 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16233 this.footer.dataSource = this.store;
16234 this.footer.container = fctr;
16235 this.footer = Roo.factory(this.footer, Roo);
16236 fctr.insertFirst(this.el);
16238 // this is a bit insane - as the paging toolbar seems to detach the el..
16239 // dom.parentNode.parentNode.parentNode
16240 // they get detached?
16244 Roo.View.superclass.constructor.call(this);
16249 Roo.extend(Roo.View, Roo.util.Observable, {
16252 * @cfg {Roo.data.Store} store Data store to load data from.
16257 * @cfg {String|Roo.Element} el The container element.
16262 * @cfg {String|Roo.Template} tpl The template used by this View
16266 * @cfg {String} dataName the named area of the template to use as the data area
16267 * Works with domtemplates roo-name="name"
16271 * @cfg {String} selectedClass The css class to add to selected nodes
16273 selectedClass : "x-view-selected",
16275 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16280 * @cfg {String} text to display on mask (default Loading)
16284 * @cfg {Boolean} multiSelect Allow multiple selection
16286 multiSelect : false,
16288 * @cfg {Boolean} singleSelect Allow single selection
16290 singleSelect: false,
16293 * @cfg {Boolean} toggleSelect - selecting
16295 toggleSelect : false,
16298 * @cfg {Boolean} tickable - selecting
16303 * Returns the element this view is bound to.
16304 * @return {Roo.Element}
16306 getEl : function(){
16307 return this.wrapEl;
16313 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16315 refresh : function(){
16316 //Roo.log('refresh');
16319 // if we are using something like 'domtemplate', then
16320 // the what gets used is:
16321 // t.applySubtemplate(NAME, data, wrapping data..)
16322 // the outer template then get' applied with
16323 // the store 'extra data'
16324 // and the body get's added to the
16325 // roo-name="data" node?
16326 // <span class='roo-tpl-{name}'></span> ?????
16330 this.clearSelections();
16331 this.el.update("");
16333 var records = this.store.getRange();
16334 if(records.length < 1) {
16336 // is this valid?? = should it render a template??
16338 this.el.update(this.emptyText);
16342 if (this.dataName) {
16343 this.el.update(t.apply(this.store.meta)); //????
16344 el = this.el.child('.roo-tpl-' + this.dataName);
16347 for(var i = 0, len = records.length; i < len; i++){
16348 var data = this.prepareData(records[i].data, i, records[i]);
16349 this.fireEvent("preparedata", this, data, i, records[i]);
16351 var d = Roo.apply({}, data);
16354 Roo.apply(d, {'roo-id' : Roo.id()});
16358 Roo.each(this.parent.item, function(item){
16359 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16362 Roo.apply(d, {'roo-data-checked' : 'checked'});
16366 html[html.length] = Roo.util.Format.trim(
16368 t.applySubtemplate(this.dataName, d, this.store.meta) :
16375 el.update(html.join(""));
16376 this.nodes = el.dom.childNodes;
16377 this.updateIndexes(0);
16382 * Function to override to reformat the data that is sent to
16383 * the template for each node.
16384 * DEPRICATED - use the preparedata event handler.
16385 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16386 * a JSON object for an UpdateManager bound view).
16388 prepareData : function(data, index, record)
16390 this.fireEvent("preparedata", this, data, index, record);
16394 onUpdate : function(ds, record){
16395 // Roo.log('on update');
16396 this.clearSelections();
16397 var index = this.store.indexOf(record);
16398 var n = this.nodes[index];
16399 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16400 n.parentNode.removeChild(n);
16401 this.updateIndexes(index, index);
16407 onAdd : function(ds, records, index)
16409 //Roo.log(['on Add', ds, records, index] );
16410 this.clearSelections();
16411 if(this.nodes.length == 0){
16415 var n = this.nodes[index];
16416 for(var i = 0, len = records.length; i < len; i++){
16417 var d = this.prepareData(records[i].data, i, records[i]);
16419 this.tpl.insertBefore(n, d);
16422 this.tpl.append(this.el, d);
16425 this.updateIndexes(index);
16428 onRemove : function(ds, record, index){
16429 // Roo.log('onRemove');
16430 this.clearSelections();
16431 var el = this.dataName ?
16432 this.el.child('.roo-tpl-' + this.dataName) :
16435 el.dom.removeChild(this.nodes[index]);
16436 this.updateIndexes(index);
16440 * Refresh an individual node.
16441 * @param {Number} index
16443 refreshNode : function(index){
16444 this.onUpdate(this.store, this.store.getAt(index));
16447 updateIndexes : function(startIndex, endIndex){
16448 var ns = this.nodes;
16449 startIndex = startIndex || 0;
16450 endIndex = endIndex || ns.length - 1;
16451 for(var i = startIndex; i <= endIndex; i++){
16452 ns[i].nodeIndex = i;
16457 * Changes the data store this view uses and refresh the view.
16458 * @param {Store} store
16460 setStore : function(store, initial){
16461 if(!initial && this.store){
16462 this.store.un("datachanged", this.refresh);
16463 this.store.un("add", this.onAdd);
16464 this.store.un("remove", this.onRemove);
16465 this.store.un("update", this.onUpdate);
16466 this.store.un("clear", this.refresh);
16467 this.store.un("beforeload", this.onBeforeLoad);
16468 this.store.un("load", this.onLoad);
16469 this.store.un("loadexception", this.onLoad);
16473 store.on("datachanged", this.refresh, this);
16474 store.on("add", this.onAdd, this);
16475 store.on("remove", this.onRemove, this);
16476 store.on("update", this.onUpdate, this);
16477 store.on("clear", this.refresh, this);
16478 store.on("beforeload", this.onBeforeLoad, this);
16479 store.on("load", this.onLoad, this);
16480 store.on("loadexception", this.onLoad, this);
16488 * onbeforeLoad - masks the loading area.
16491 onBeforeLoad : function(store,opts)
16493 //Roo.log('onBeforeLoad');
16495 this.el.update("");
16497 this.el.mask(this.mask ? this.mask : "Loading" );
16499 onLoad : function ()
16506 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16507 * @param {HTMLElement} node
16508 * @return {HTMLElement} The template node
16510 findItemFromChild : function(node){
16511 var el = this.dataName ?
16512 this.el.child('.roo-tpl-' + this.dataName,true) :
16515 if(!node || node.parentNode == el){
16518 var p = node.parentNode;
16519 while(p && p != el){
16520 if(p.parentNode == el){
16529 onClick : function(e){
16530 var item = this.findItemFromChild(e.getTarget());
16532 var index = this.indexOf(item);
16533 if(this.onItemClick(item, index, e) !== false){
16534 this.fireEvent("click", this, index, item, e);
16537 this.clearSelections();
16542 onContextMenu : function(e){
16543 var item = this.findItemFromChild(e.getTarget());
16545 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16550 onDblClick : function(e){
16551 var item = this.findItemFromChild(e.getTarget());
16553 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16557 onItemClick : function(item, index, e)
16559 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16562 if (this.toggleSelect) {
16563 var m = this.isSelected(item) ? 'unselect' : 'select';
16566 _t[m](item, true, false);
16569 if(this.multiSelect || this.singleSelect){
16570 if(this.multiSelect && e.shiftKey && this.lastSelection){
16571 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16573 this.select(item, this.multiSelect && e.ctrlKey);
16574 this.lastSelection = item;
16577 if(!this.tickable){
16578 e.preventDefault();
16586 * Get the number of selected nodes.
16589 getSelectionCount : function(){
16590 return this.selections.length;
16594 * Get the currently selected nodes.
16595 * @return {Array} An array of HTMLElements
16597 getSelectedNodes : function(){
16598 return this.selections;
16602 * Get the indexes of the selected nodes.
16605 getSelectedIndexes : function(){
16606 var indexes = [], s = this.selections;
16607 for(var i = 0, len = s.length; i < len; i++){
16608 indexes.push(s[i].nodeIndex);
16614 * Clear all selections
16615 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16617 clearSelections : function(suppressEvent){
16618 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16619 this.cmp.elements = this.selections;
16620 this.cmp.removeClass(this.selectedClass);
16621 this.selections = [];
16622 if(!suppressEvent){
16623 this.fireEvent("selectionchange", this, this.selections);
16629 * Returns true if the passed node is selected
16630 * @param {HTMLElement/Number} node The node or node index
16631 * @return {Boolean}
16633 isSelected : function(node){
16634 var s = this.selections;
16638 node = this.getNode(node);
16639 return s.indexOf(node) !== -1;
16644 * @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
16645 * @param {Boolean} keepExisting (optional) true to keep existing selections
16646 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16648 select : function(nodeInfo, keepExisting, suppressEvent){
16649 if(nodeInfo instanceof Array){
16651 this.clearSelections(true);
16653 for(var i = 0, len = nodeInfo.length; i < len; i++){
16654 this.select(nodeInfo[i], true, true);
16658 var node = this.getNode(nodeInfo);
16659 if(!node || this.isSelected(node)){
16660 return; // already selected.
16663 this.clearSelections(true);
16666 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16667 Roo.fly(node).addClass(this.selectedClass);
16668 this.selections.push(node);
16669 if(!suppressEvent){
16670 this.fireEvent("selectionchange", this, this.selections);
16678 * @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
16679 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16680 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16682 unselect : function(nodeInfo, keepExisting, suppressEvent)
16684 if(nodeInfo instanceof Array){
16685 Roo.each(this.selections, function(s) {
16686 this.unselect(s, nodeInfo);
16690 var node = this.getNode(nodeInfo);
16691 if(!node || !this.isSelected(node)){
16692 //Roo.log("not selected");
16693 return; // not selected.
16697 Roo.each(this.selections, function(s) {
16699 Roo.fly(node).removeClass(this.selectedClass);
16706 this.selections= ns;
16707 this.fireEvent("selectionchange", this, this.selections);
16711 * Gets a template node.
16712 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16713 * @return {HTMLElement} The node or null if it wasn't found
16715 getNode : function(nodeInfo){
16716 if(typeof nodeInfo == "string"){
16717 return document.getElementById(nodeInfo);
16718 }else if(typeof nodeInfo == "number"){
16719 return this.nodes[nodeInfo];
16725 * Gets a range template nodes.
16726 * @param {Number} startIndex
16727 * @param {Number} endIndex
16728 * @return {Array} An array of nodes
16730 getNodes : function(start, end){
16731 var ns = this.nodes;
16732 start = start || 0;
16733 end = typeof end == "undefined" ? ns.length - 1 : end;
16736 for(var i = start; i <= end; i++){
16740 for(var i = start; i >= end; i--){
16748 * Finds the index of the passed node
16749 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16750 * @return {Number} The index of the node or -1
16752 indexOf : function(node){
16753 node = this.getNode(node);
16754 if(typeof node.nodeIndex == "number"){
16755 return node.nodeIndex;
16757 var ns = this.nodes;
16758 for(var i = 0, len = ns.length; i < len; i++){
16769 * based on jquery fullcalendar
16773 Roo.bootstrap = Roo.bootstrap || {};
16775 * @class Roo.bootstrap.Calendar
16776 * @extends Roo.bootstrap.Component
16777 * Bootstrap Calendar class
16778 * @cfg {Boolean} loadMask (true|false) default false
16779 * @cfg {Object} header generate the user specific header of the calendar, default false
16782 * Create a new Container
16783 * @param {Object} config The config object
16788 Roo.bootstrap.Calendar = function(config){
16789 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16793 * Fires when a date is selected
16794 * @param {DatePicker} this
16795 * @param {Date} date The selected date
16799 * @event monthchange
16800 * Fires when the displayed month changes
16801 * @param {DatePicker} this
16802 * @param {Date} date The selected month
16804 'monthchange': true,
16806 * @event evententer
16807 * Fires when mouse over an event
16808 * @param {Calendar} this
16809 * @param {event} Event
16811 'evententer': true,
16813 * @event eventleave
16814 * Fires when the mouse leaves an
16815 * @param {Calendar} this
16818 'eventleave': true,
16820 * @event eventclick
16821 * Fires when the mouse click an
16822 * @param {Calendar} this
16831 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16834 * @cfg {Number} startDay
16835 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16843 getAutoCreate : function(){
16846 var fc_button = function(name, corner, style, content ) {
16847 return Roo.apply({},{
16849 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16851 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16854 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16865 style : 'width:100%',
16872 cls : 'fc-header-left',
16874 fc_button('prev', 'left', 'arrow', '‹' ),
16875 fc_button('next', 'right', 'arrow', '›' ),
16876 { tag: 'span', cls: 'fc-header-space' },
16877 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16885 cls : 'fc-header-center',
16889 cls: 'fc-header-title',
16892 html : 'month / year'
16900 cls : 'fc-header-right',
16902 /* fc_button('month', 'left', '', 'month' ),
16903 fc_button('week', '', '', 'week' ),
16904 fc_button('day', 'right', '', 'day' )
16916 header = this.header;
16919 var cal_heads = function() {
16921 // fixme - handle this.
16923 for (var i =0; i < Date.dayNames.length; i++) {
16924 var d = Date.dayNames[i];
16927 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16928 html : d.substring(0,3)
16932 ret[0].cls += ' fc-first';
16933 ret[6].cls += ' fc-last';
16936 var cal_cell = function(n) {
16939 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16944 cls: 'fc-day-number',
16948 cls: 'fc-day-content',
16952 style: 'position: relative;' // height: 17px;
16964 var cal_rows = function() {
16967 for (var r = 0; r < 6; r++) {
16974 for (var i =0; i < Date.dayNames.length; i++) {
16975 var d = Date.dayNames[i];
16976 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16979 row.cn[0].cls+=' fc-first';
16980 row.cn[0].cn[0].style = 'min-height:90px';
16981 row.cn[6].cls+=' fc-last';
16985 ret[0].cls += ' fc-first';
16986 ret[4].cls += ' fc-prev-last';
16987 ret[5].cls += ' fc-last';
16994 cls: 'fc-border-separate',
16995 style : 'width:100%',
17003 cls : 'fc-first fc-last',
17021 cls : 'fc-content',
17022 style : "position: relative;",
17025 cls : 'fc-view fc-view-month fc-grid',
17026 style : 'position: relative',
17027 unselectable : 'on',
17030 cls : 'fc-event-container',
17031 style : 'position:absolute;z-index:8;top:0;left:0;'
17049 initEvents : function()
17052 throw "can not find store for calendar";
17058 style: "text-align:center",
17062 style: "background-color:white;width:50%;margin:250 auto",
17066 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17077 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17079 var size = this.el.select('.fc-content', true).first().getSize();
17080 this.maskEl.setSize(size.width, size.height);
17081 this.maskEl.enableDisplayMode("block");
17082 if(!this.loadMask){
17083 this.maskEl.hide();
17086 this.store = Roo.factory(this.store, Roo.data);
17087 this.store.on('load', this.onLoad, this);
17088 this.store.on('beforeload', this.onBeforeLoad, this);
17092 this.cells = this.el.select('.fc-day',true);
17093 //Roo.log(this.cells);
17094 this.textNodes = this.el.query('.fc-day-number');
17095 this.cells.addClassOnOver('fc-state-hover');
17097 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17098 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17099 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17100 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17102 this.on('monthchange', this.onMonthChange, this);
17104 this.update(new Date().clearTime());
17107 resize : function() {
17108 var sz = this.el.getSize();
17110 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17111 this.el.select('.fc-day-content div',true).setHeight(34);
17116 showPrevMonth : function(e){
17117 this.update(this.activeDate.add("mo", -1));
17119 showToday : function(e){
17120 this.update(new Date().clearTime());
17123 showNextMonth : function(e){
17124 this.update(this.activeDate.add("mo", 1));
17128 showPrevYear : function(){
17129 this.update(this.activeDate.add("y", -1));
17133 showNextYear : function(){
17134 this.update(this.activeDate.add("y", 1));
17139 update : function(date)
17141 var vd = this.activeDate;
17142 this.activeDate = date;
17143 // if(vd && this.el){
17144 // var t = date.getTime();
17145 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17146 // Roo.log('using add remove');
17148 // this.fireEvent('monthchange', this, date);
17150 // this.cells.removeClass("fc-state-highlight");
17151 // this.cells.each(function(c){
17152 // if(c.dateValue == t){
17153 // c.addClass("fc-state-highlight");
17154 // setTimeout(function(){
17155 // try{c.dom.firstChild.focus();}catch(e){}
17165 var days = date.getDaysInMonth();
17167 var firstOfMonth = date.getFirstDateOfMonth();
17168 var startingPos = firstOfMonth.getDay()-this.startDay;
17170 if(startingPos < this.startDay){
17174 var pm = date.add(Date.MONTH, -1);
17175 var prevStart = pm.getDaysInMonth()-startingPos;
17177 this.cells = this.el.select('.fc-day',true);
17178 this.textNodes = this.el.query('.fc-day-number');
17179 this.cells.addClassOnOver('fc-state-hover');
17181 var cells = this.cells.elements;
17182 var textEls = this.textNodes;
17184 Roo.each(cells, function(cell){
17185 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17188 days += startingPos;
17190 // convert everything to numbers so it's fast
17191 var day = 86400000;
17192 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17195 //Roo.log(prevStart);
17197 var today = new Date().clearTime().getTime();
17198 var sel = date.clearTime().getTime();
17199 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17200 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17201 var ddMatch = this.disabledDatesRE;
17202 var ddText = this.disabledDatesText;
17203 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17204 var ddaysText = this.disabledDaysText;
17205 var format = this.format;
17207 var setCellClass = function(cal, cell){
17211 //Roo.log('set Cell Class');
17213 var t = d.getTime();
17217 cell.dateValue = t;
17219 cell.className += " fc-today";
17220 cell.className += " fc-state-highlight";
17221 cell.title = cal.todayText;
17224 // disable highlight in other month..
17225 //cell.className += " fc-state-highlight";
17230 cell.className = " fc-state-disabled";
17231 cell.title = cal.minText;
17235 cell.className = " fc-state-disabled";
17236 cell.title = cal.maxText;
17240 if(ddays.indexOf(d.getDay()) != -1){
17241 cell.title = ddaysText;
17242 cell.className = " fc-state-disabled";
17245 if(ddMatch && format){
17246 var fvalue = d.dateFormat(format);
17247 if(ddMatch.test(fvalue)){
17248 cell.title = ddText.replace("%0", fvalue);
17249 cell.className = " fc-state-disabled";
17253 if (!cell.initialClassName) {
17254 cell.initialClassName = cell.dom.className;
17257 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17262 for(; i < startingPos; i++) {
17263 textEls[i].innerHTML = (++prevStart);
17264 d.setDate(d.getDate()+1);
17266 cells[i].className = "fc-past fc-other-month";
17267 setCellClass(this, cells[i]);
17272 for(; i < days; i++){
17273 intDay = i - startingPos + 1;
17274 textEls[i].innerHTML = (intDay);
17275 d.setDate(d.getDate()+1);
17277 cells[i].className = ''; // "x-date-active";
17278 setCellClass(this, cells[i]);
17282 for(; i < 42; i++) {
17283 textEls[i].innerHTML = (++extraDays);
17284 d.setDate(d.getDate()+1);
17286 cells[i].className = "fc-future fc-other-month";
17287 setCellClass(this, cells[i]);
17290 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17292 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17294 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17295 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17297 if(totalRows != 6){
17298 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17299 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17302 this.fireEvent('monthchange', this, date);
17306 if(!this.internalRender){
17307 var main = this.el.dom.firstChild;
17308 var w = main.offsetWidth;
17309 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17310 Roo.fly(main).setWidth(w);
17311 this.internalRender = true;
17312 // opera does not respect the auto grow header center column
17313 // then, after it gets a width opera refuses to recalculate
17314 // without a second pass
17315 if(Roo.isOpera && !this.secondPass){
17316 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17317 this.secondPass = true;
17318 this.update.defer(10, this, [date]);
17325 findCell : function(dt) {
17326 dt = dt.clearTime().getTime();
17328 this.cells.each(function(c){
17329 //Roo.log("check " +c.dateValue + '?=' + dt);
17330 if(c.dateValue == dt){
17340 findCells : function(ev) {
17341 var s = ev.start.clone().clearTime().getTime();
17343 var e= ev.end.clone().clearTime().getTime();
17346 this.cells.each(function(c){
17347 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17349 if(c.dateValue > e){
17352 if(c.dateValue < s){
17361 // findBestRow: function(cells)
17365 // for (var i =0 ; i < cells.length;i++) {
17366 // ret = Math.max(cells[i].rows || 0,ret);
17373 addItem : function(ev)
17375 // look for vertical location slot in
17376 var cells = this.findCells(ev);
17378 // ev.row = this.findBestRow(cells);
17380 // work out the location.
17384 for(var i =0; i < cells.length; i++) {
17386 cells[i].row = cells[0].row;
17389 cells[i].row = cells[i].row + 1;
17399 if (crow.start.getY() == cells[i].getY()) {
17401 crow.end = cells[i];
17418 cells[0].events.push(ev);
17420 this.calevents.push(ev);
17423 clearEvents: function() {
17425 if(!this.calevents){
17429 Roo.each(this.cells.elements, function(c){
17435 Roo.each(this.calevents, function(e) {
17436 Roo.each(e.els, function(el) {
17437 el.un('mouseenter' ,this.onEventEnter, this);
17438 el.un('mouseleave' ,this.onEventLeave, this);
17443 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17449 renderEvents: function()
17453 this.cells.each(function(c) {
17462 if(c.row != c.events.length){
17463 r = 4 - (4 - (c.row - c.events.length));
17466 c.events = ev.slice(0, r);
17467 c.more = ev.slice(r);
17469 if(c.more.length && c.more.length == 1){
17470 c.events.push(c.more.pop());
17473 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17477 this.cells.each(function(c) {
17479 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17482 for (var e = 0; e < c.events.length; e++){
17483 var ev = c.events[e];
17484 var rows = ev.rows;
17486 for(var i = 0; i < rows.length; i++) {
17488 // how many rows should it span..
17491 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17492 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17494 unselectable : "on",
17497 cls: 'fc-event-inner',
17501 // cls: 'fc-event-time',
17502 // html : cells.length > 1 ? '' : ev.time
17506 cls: 'fc-event-title',
17507 html : String.format('{0}', ev.title)
17514 cls: 'ui-resizable-handle ui-resizable-e',
17515 html : '  '
17522 cfg.cls += ' fc-event-start';
17524 if ((i+1) == rows.length) {
17525 cfg.cls += ' fc-event-end';
17528 var ctr = _this.el.select('.fc-event-container',true).first();
17529 var cg = ctr.createChild(cfg);
17531 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17532 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17534 var r = (c.more.length) ? 1 : 0;
17535 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17536 cg.setWidth(ebox.right - sbox.x -2);
17538 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17539 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17540 cg.on('click', _this.onEventClick, _this, ev);
17551 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17552 style : 'position: absolute',
17553 unselectable : "on",
17556 cls: 'fc-event-inner',
17560 cls: 'fc-event-title',
17568 cls: 'ui-resizable-handle ui-resizable-e',
17569 html : '  '
17575 var ctr = _this.el.select('.fc-event-container',true).first();
17576 var cg = ctr.createChild(cfg);
17578 var sbox = c.select('.fc-day-content',true).first().getBox();
17579 var ebox = c.select('.fc-day-content',true).first().getBox();
17581 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17582 cg.setWidth(ebox.right - sbox.x -2);
17584 cg.on('click', _this.onMoreEventClick, _this, c.more);
17594 onEventEnter: function (e, el,event,d) {
17595 this.fireEvent('evententer', this, el, event);
17598 onEventLeave: function (e, el,event,d) {
17599 this.fireEvent('eventleave', this, el, event);
17602 onEventClick: function (e, el,event,d) {
17603 this.fireEvent('eventclick', this, el, event);
17606 onMonthChange: function () {
17610 onMoreEventClick: function(e, el, more)
17614 this.calpopover.placement = 'right';
17615 this.calpopover.setTitle('More');
17617 this.calpopover.setContent('');
17619 var ctr = this.calpopover.el.select('.popover-content', true).first();
17621 Roo.each(more, function(m){
17623 cls : 'fc-event-hori fc-event-draggable',
17626 var cg = ctr.createChild(cfg);
17628 cg.on('click', _this.onEventClick, _this, m);
17631 this.calpopover.show(el);
17636 onLoad: function ()
17638 this.calevents = [];
17641 if(this.store.getCount() > 0){
17642 this.store.data.each(function(d){
17645 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17646 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17647 time : d.data.start_time,
17648 title : d.data.title,
17649 description : d.data.description,
17650 venue : d.data.venue
17655 this.renderEvents();
17657 if(this.calevents.length && this.loadMask){
17658 this.maskEl.hide();
17662 onBeforeLoad: function()
17664 this.clearEvents();
17666 this.maskEl.show();
17680 * @class Roo.bootstrap.Popover
17681 * @extends Roo.bootstrap.Component
17682 * Bootstrap Popover class
17683 * @cfg {String} html contents of the popover (or false to use children..)
17684 * @cfg {String} title of popover (or false to hide)
17685 * @cfg {String} placement how it is placed
17686 * @cfg {String} trigger click || hover (or false to trigger manually)
17687 * @cfg {String} over what (parent or false to trigger manually.)
17688 * @cfg {Number} delay - delay before showing
17691 * Create a new Popover
17692 * @param {Object} config The config object
17695 Roo.bootstrap.Popover = function(config){
17696 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17702 * After the popover show
17704 * @param {Roo.bootstrap.Popover} this
17709 * After the popover hide
17711 * @param {Roo.bootstrap.Popover} this
17717 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17719 title: 'Fill in a title',
17722 placement : 'right',
17723 trigger : 'hover', // hover
17729 can_build_overlaid : false,
17731 getChildContainer : function()
17733 return this.el.select('.popover-content',true).first();
17736 getAutoCreate : function(){
17739 cls : 'popover roo-dynamic',
17740 style: 'display:block',
17746 cls : 'popover-inner',
17750 cls: 'popover-title popover-header',
17754 cls : 'popover-content popover-body',
17765 setTitle: function(str)
17768 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17770 setContent: function(str)
17773 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17775 // as it get's added to the bottom of the page.
17776 onRender : function(ct, position)
17778 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17780 var cfg = Roo.apply({}, this.getAutoCreate());
17784 cfg.cls += ' ' + this.cls;
17787 cfg.style = this.style;
17789 //Roo.log("adding to ");
17790 this.el = Roo.get(document.body).createChild(cfg, position);
17791 // Roo.log(this.el);
17796 initEvents : function()
17798 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17799 this.el.enableDisplayMode('block');
17801 if (this.over === false) {
17804 if (this.triggers === false) {
17807 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17808 var triggers = this.trigger ? this.trigger.split(' ') : [];
17809 Roo.each(triggers, function(trigger) {
17811 if (trigger == 'click') {
17812 on_el.on('click', this.toggle, this);
17813 } else if (trigger != 'manual') {
17814 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17815 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17817 on_el.on(eventIn ,this.enter, this);
17818 on_el.on(eventOut, this.leave, this);
17829 toggle : function () {
17830 this.hoverState == 'in' ? this.leave() : this.enter();
17833 enter : function () {
17835 clearTimeout(this.timeout);
17837 this.hoverState = 'in';
17839 if (!this.delay || !this.delay.show) {
17844 this.timeout = setTimeout(function () {
17845 if (_t.hoverState == 'in') {
17848 }, this.delay.show)
17851 leave : function() {
17852 clearTimeout(this.timeout);
17854 this.hoverState = 'out';
17856 if (!this.delay || !this.delay.hide) {
17861 this.timeout = setTimeout(function () {
17862 if (_t.hoverState == 'out') {
17865 }, this.delay.hide)
17868 show : function (on_el)
17871 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17875 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17876 if (this.html !== false) {
17877 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17879 this.el.removeClass([
17880 'fade','top','bottom', 'left', 'right','in',
17881 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17883 if (!this.title.length) {
17884 this.el.select('.popover-title',true).hide();
17887 var placement = typeof this.placement == 'function' ?
17888 this.placement.call(this, this.el, on_el) :
17891 var autoToken = /\s?auto?\s?/i;
17892 var autoPlace = autoToken.test(placement);
17894 placement = placement.replace(autoToken, '') || 'top';
17898 //this.el.setXY([0,0]);
17900 this.el.dom.style.display='block';
17901 this.el.addClass(placement);
17903 //this.el.appendTo(on_el);
17905 var p = this.getPosition();
17906 var box = this.el.getBox();
17911 var align = Roo.bootstrap.Popover.alignment[placement];
17914 this.el.alignTo(on_el, align[0],align[1]);
17915 //var arrow = this.el.select('.arrow',true).first();
17916 //arrow.set(align[2],
17918 this.el.addClass('in');
17921 if (this.el.hasClass('fade')) {
17925 this.hoverState = 'in';
17927 this.fireEvent('show', this);
17932 this.el.setXY([0,0]);
17933 this.el.removeClass('in');
17935 this.hoverState = null;
17937 this.fireEvent('hide', this);
17942 Roo.bootstrap.Popover.alignment = {
17943 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17944 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17945 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17946 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17957 * @class Roo.bootstrap.Progress
17958 * @extends Roo.bootstrap.Component
17959 * Bootstrap Progress class
17960 * @cfg {Boolean} striped striped of the progress bar
17961 * @cfg {Boolean} active animated of the progress bar
17965 * Create a new Progress
17966 * @param {Object} config The config object
17969 Roo.bootstrap.Progress = function(config){
17970 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17973 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17978 getAutoCreate : function(){
17986 cfg.cls += ' progress-striped';
17990 cfg.cls += ' active';
18009 * @class Roo.bootstrap.ProgressBar
18010 * @extends Roo.bootstrap.Component
18011 * Bootstrap ProgressBar class
18012 * @cfg {Number} aria_valuenow aria-value now
18013 * @cfg {Number} aria_valuemin aria-value min
18014 * @cfg {Number} aria_valuemax aria-value max
18015 * @cfg {String} label label for the progress bar
18016 * @cfg {String} panel (success | info | warning | danger )
18017 * @cfg {String} role role of the progress bar
18018 * @cfg {String} sr_only text
18022 * Create a new ProgressBar
18023 * @param {Object} config The config object
18026 Roo.bootstrap.ProgressBar = function(config){
18027 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18030 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18034 aria_valuemax : 100,
18040 getAutoCreate : function()
18045 cls: 'progress-bar',
18046 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18058 cfg.role = this.role;
18061 if(this.aria_valuenow){
18062 cfg['aria-valuenow'] = this.aria_valuenow;
18065 if(this.aria_valuemin){
18066 cfg['aria-valuemin'] = this.aria_valuemin;
18069 if(this.aria_valuemax){
18070 cfg['aria-valuemax'] = this.aria_valuemax;
18073 if(this.label && !this.sr_only){
18074 cfg.html = this.label;
18078 cfg.cls += ' progress-bar-' + this.panel;
18084 update : function(aria_valuenow)
18086 this.aria_valuenow = aria_valuenow;
18088 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18103 * @class Roo.bootstrap.TabGroup
18104 * @extends Roo.bootstrap.Column
18105 * Bootstrap Column class
18106 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18107 * @cfg {Boolean} carousel true to make the group behave like a carousel
18108 * @cfg {Boolean} bullets show bullets for the panels
18109 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18110 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18111 * @cfg {Boolean} showarrow (true|false) show arrow default true
18114 * Create a new TabGroup
18115 * @param {Object} config The config object
18118 Roo.bootstrap.TabGroup = function(config){
18119 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18121 this.navId = Roo.id();
18124 Roo.bootstrap.TabGroup.register(this);
18128 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18131 transition : false,
18136 slideOnTouch : false,
18139 getAutoCreate : function()
18141 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18143 cfg.cls += ' tab-content';
18145 if (this.carousel) {
18146 cfg.cls += ' carousel slide';
18149 cls : 'carousel-inner',
18153 if(this.bullets && !Roo.isTouch){
18156 cls : 'carousel-bullets',
18160 if(this.bullets_cls){
18161 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18168 cfg.cn[0].cn.push(bullets);
18171 if(this.showarrow){
18172 cfg.cn[0].cn.push({
18174 class : 'carousel-arrow',
18178 class : 'carousel-prev',
18182 class : 'fa fa-chevron-left'
18188 class : 'carousel-next',
18192 class : 'fa fa-chevron-right'
18205 initEvents: function()
18207 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18208 // this.el.on("touchstart", this.onTouchStart, this);
18211 if(this.autoslide){
18214 this.slideFn = window.setInterval(function() {
18215 _this.showPanelNext();
18219 if(this.showarrow){
18220 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18221 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18227 // onTouchStart : function(e, el, o)
18229 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18233 // this.showPanelNext();
18237 getChildContainer : function()
18239 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18243 * register a Navigation item
18244 * @param {Roo.bootstrap.NavItem} the navitem to add
18246 register : function(item)
18248 this.tabs.push( item);
18249 item.navId = this.navId; // not really needed..
18254 getActivePanel : function()
18257 Roo.each(this.tabs, function(t) {
18267 getPanelByName : function(n)
18270 Roo.each(this.tabs, function(t) {
18271 if (t.tabId == n) {
18279 indexOfPanel : function(p)
18282 Roo.each(this.tabs, function(t,i) {
18283 if (t.tabId == p.tabId) {
18292 * show a specific panel
18293 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18294 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18296 showPanel : function (pan)
18298 if(this.transition || typeof(pan) == 'undefined'){
18299 Roo.log("waiting for the transitionend");
18303 if (typeof(pan) == 'number') {
18304 pan = this.tabs[pan];
18307 if (typeof(pan) == 'string') {
18308 pan = this.getPanelByName(pan);
18311 var cur = this.getActivePanel();
18314 Roo.log('pan or acitve pan is undefined');
18318 if (pan.tabId == this.getActivePanel().tabId) {
18322 if (false === cur.fireEvent('beforedeactivate')) {
18326 if(this.bullets > 0 && !Roo.isTouch){
18327 this.setActiveBullet(this.indexOfPanel(pan));
18330 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18332 this.transition = true;
18333 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18334 var lr = dir == 'next' ? 'left' : 'right';
18335 pan.el.addClass(dir); // or prev
18336 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18337 cur.el.addClass(lr); // or right
18338 pan.el.addClass(lr);
18341 cur.el.on('transitionend', function() {
18342 Roo.log("trans end?");
18344 pan.el.removeClass([lr,dir]);
18345 pan.setActive(true);
18347 cur.el.removeClass([lr]);
18348 cur.setActive(false);
18350 _this.transition = false;
18352 }, this, { single: true } );
18357 cur.setActive(false);
18358 pan.setActive(true);
18363 showPanelNext : function()
18365 var i = this.indexOfPanel(this.getActivePanel());
18367 if (i >= this.tabs.length - 1 && !this.autoslide) {
18371 if (i >= this.tabs.length - 1 && this.autoslide) {
18375 this.showPanel(this.tabs[i+1]);
18378 showPanelPrev : function()
18380 var i = this.indexOfPanel(this.getActivePanel());
18382 if (i < 1 && !this.autoslide) {
18386 if (i < 1 && this.autoslide) {
18387 i = this.tabs.length;
18390 this.showPanel(this.tabs[i-1]);
18394 addBullet: function()
18396 if(!this.bullets || Roo.isTouch){
18399 var ctr = this.el.select('.carousel-bullets',true).first();
18400 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18401 var bullet = ctr.createChild({
18402 cls : 'bullet bullet-' + i
18403 },ctr.dom.lastChild);
18408 bullet.on('click', (function(e, el, o, ii, t){
18410 e.preventDefault();
18412 this.showPanel(ii);
18414 if(this.autoslide && this.slideFn){
18415 clearInterval(this.slideFn);
18416 this.slideFn = window.setInterval(function() {
18417 _this.showPanelNext();
18421 }).createDelegate(this, [i, bullet], true));
18426 setActiveBullet : function(i)
18432 Roo.each(this.el.select('.bullet', true).elements, function(el){
18433 el.removeClass('selected');
18436 var bullet = this.el.select('.bullet-' + i, true).first();
18442 bullet.addClass('selected');
18453 Roo.apply(Roo.bootstrap.TabGroup, {
18457 * register a Navigation Group
18458 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18460 register : function(navgrp)
18462 this.groups[navgrp.navId] = navgrp;
18466 * fetch a Navigation Group based on the navigation ID
18467 * if one does not exist , it will get created.
18468 * @param {string} the navgroup to add
18469 * @returns {Roo.bootstrap.NavGroup} the navgroup
18471 get: function(navId) {
18472 if (typeof(this.groups[navId]) == 'undefined') {
18473 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18475 return this.groups[navId] ;
18490 * @class Roo.bootstrap.TabPanel
18491 * @extends Roo.bootstrap.Component
18492 * Bootstrap TabPanel class
18493 * @cfg {Boolean} active panel active
18494 * @cfg {String} html panel content
18495 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18496 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18497 * @cfg {String} href click to link..
18501 * Create a new TabPanel
18502 * @param {Object} config The config object
18505 Roo.bootstrap.TabPanel = function(config){
18506 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18510 * Fires when the active status changes
18511 * @param {Roo.bootstrap.TabPanel} this
18512 * @param {Boolean} state the new state
18517 * @event beforedeactivate
18518 * Fires before a tab is de-activated - can be used to do validation on a form.
18519 * @param {Roo.bootstrap.TabPanel} this
18520 * @return {Boolean} false if there is an error
18523 'beforedeactivate': true
18526 this.tabId = this.tabId || Roo.id();
18530 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18538 getAutoCreate : function(){
18541 // item is needed for carousel - not sure if it has any effect otherwise
18542 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18543 html: this.html || ''
18547 cfg.cls += ' active';
18551 cfg.tabId = this.tabId;
18558 initEvents: function()
18560 var p = this.parent();
18562 this.navId = this.navId || p.navId;
18564 if (typeof(this.navId) != 'undefined') {
18565 // not really needed.. but just in case.. parent should be a NavGroup.
18566 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18570 var i = tg.tabs.length - 1;
18572 if(this.active && tg.bullets > 0 && i < tg.bullets){
18573 tg.setActiveBullet(i);
18577 this.el.on('click', this.onClick, this);
18580 this.el.on("touchstart", this.onTouchStart, this);
18581 this.el.on("touchmove", this.onTouchMove, this);
18582 this.el.on("touchend", this.onTouchEnd, this);
18587 onRender : function(ct, position)
18589 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18592 setActive : function(state)
18594 Roo.log("panel - set active " + this.tabId + "=" + state);
18596 this.active = state;
18598 this.el.removeClass('active');
18600 } else if (!this.el.hasClass('active')) {
18601 this.el.addClass('active');
18604 this.fireEvent('changed', this, state);
18607 onClick : function(e)
18609 e.preventDefault();
18611 if(!this.href.length){
18615 window.location.href = this.href;
18624 onTouchStart : function(e)
18626 this.swiping = false;
18628 this.startX = e.browserEvent.touches[0].clientX;
18629 this.startY = e.browserEvent.touches[0].clientY;
18632 onTouchMove : function(e)
18634 this.swiping = true;
18636 this.endX = e.browserEvent.touches[0].clientX;
18637 this.endY = e.browserEvent.touches[0].clientY;
18640 onTouchEnd : function(e)
18647 var tabGroup = this.parent();
18649 if(this.endX > this.startX){ // swiping right
18650 tabGroup.showPanelPrev();
18654 if(this.startX > this.endX){ // swiping left
18655 tabGroup.showPanelNext();
18674 * @class Roo.bootstrap.DateField
18675 * @extends Roo.bootstrap.Input
18676 * Bootstrap DateField class
18677 * @cfg {Number} weekStart default 0
18678 * @cfg {String} viewMode default empty, (months|years)
18679 * @cfg {String} minViewMode default empty, (months|years)
18680 * @cfg {Number} startDate default -Infinity
18681 * @cfg {Number} endDate default Infinity
18682 * @cfg {Boolean} todayHighlight default false
18683 * @cfg {Boolean} todayBtn default false
18684 * @cfg {Boolean} calendarWeeks default false
18685 * @cfg {Object} daysOfWeekDisabled default empty
18686 * @cfg {Boolean} singleMode default false (true | false)
18688 * @cfg {Boolean} keyboardNavigation default true
18689 * @cfg {String} language default en
18692 * Create a new DateField
18693 * @param {Object} config The config object
18696 Roo.bootstrap.DateField = function(config){
18697 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18701 * Fires when this field show.
18702 * @param {Roo.bootstrap.DateField} this
18703 * @param {Mixed} date The date value
18708 * Fires when this field hide.
18709 * @param {Roo.bootstrap.DateField} this
18710 * @param {Mixed} date The date value
18715 * Fires when select a date.
18716 * @param {Roo.bootstrap.DateField} this
18717 * @param {Mixed} date The date value
18721 * @event beforeselect
18722 * Fires when before select a date.
18723 * @param {Roo.bootstrap.DateField} this
18724 * @param {Mixed} date The date value
18726 beforeselect : true
18730 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18733 * @cfg {String} format
18734 * The default date format string which can be overriden for localization support. The format must be
18735 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18739 * @cfg {String} altFormats
18740 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18741 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18743 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18751 todayHighlight : false,
18757 keyboardNavigation: true,
18759 calendarWeeks: false,
18761 startDate: -Infinity,
18765 daysOfWeekDisabled: [],
18769 singleMode : false,
18771 UTCDate: function()
18773 return new Date(Date.UTC.apply(Date, arguments));
18776 UTCToday: function()
18778 var today = new Date();
18779 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18782 getDate: function() {
18783 var d = this.getUTCDate();
18784 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18787 getUTCDate: function() {
18791 setDate: function(d) {
18792 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18795 setUTCDate: function(d) {
18797 this.setValue(this.formatDate(this.date));
18800 onRender: function(ct, position)
18803 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18805 this.language = this.language || 'en';
18806 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18807 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18809 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18810 this.format = this.format || 'm/d/y';
18811 this.isInline = false;
18812 this.isInput = true;
18813 this.component = this.el.select('.add-on', true).first() || false;
18814 this.component = (this.component && this.component.length === 0) ? false : this.component;
18815 this.hasInput = this.component && this.inputEl().length;
18817 if (typeof(this.minViewMode === 'string')) {
18818 switch (this.minViewMode) {
18820 this.minViewMode = 1;
18823 this.minViewMode = 2;
18826 this.minViewMode = 0;
18831 if (typeof(this.viewMode === 'string')) {
18832 switch (this.viewMode) {
18845 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18847 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18849 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18851 this.picker().on('mousedown', this.onMousedown, this);
18852 this.picker().on('click', this.onClick, this);
18854 this.picker().addClass('datepicker-dropdown');
18856 this.startViewMode = this.viewMode;
18858 if(this.singleMode){
18859 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18860 v.setVisibilityMode(Roo.Element.DISPLAY);
18864 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18865 v.setStyle('width', '189px');
18869 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18870 if(!this.calendarWeeks){
18875 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18876 v.attr('colspan', function(i, val){
18877 return parseInt(val) + 1;
18882 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18884 this.setStartDate(this.startDate);
18885 this.setEndDate(this.endDate);
18887 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18894 if(this.isInline) {
18899 picker : function()
18901 return this.pickerEl;
18902 // return this.el.select('.datepicker', true).first();
18905 fillDow: function()
18907 var dowCnt = this.weekStart;
18916 if(this.calendarWeeks){
18924 while (dowCnt < this.weekStart + 7) {
18928 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18932 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18935 fillMonths: function()
18938 var months = this.picker().select('>.datepicker-months td', true).first();
18940 months.dom.innerHTML = '';
18946 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18949 months.createChild(month);
18956 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;
18958 if (this.date < this.startDate) {
18959 this.viewDate = new Date(this.startDate);
18960 } else if (this.date > this.endDate) {
18961 this.viewDate = new Date(this.endDate);
18963 this.viewDate = new Date(this.date);
18971 var d = new Date(this.viewDate),
18972 year = d.getUTCFullYear(),
18973 month = d.getUTCMonth(),
18974 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18975 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18976 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18977 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18978 currentDate = this.date && this.date.valueOf(),
18979 today = this.UTCToday();
18981 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18983 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18985 // this.picker.select('>tfoot th.today').
18986 // .text(dates[this.language].today)
18987 // .toggle(this.todayBtn !== false);
18989 this.updateNavArrows();
18992 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18994 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18996 prevMonth.setUTCDate(day);
18998 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19000 var nextMonth = new Date(prevMonth);
19002 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19004 nextMonth = nextMonth.valueOf();
19006 var fillMonths = false;
19008 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19010 while(prevMonth.valueOf() <= nextMonth) {
19013 if (prevMonth.getUTCDay() === this.weekStart) {
19015 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19023 if(this.calendarWeeks){
19024 // ISO 8601: First week contains first thursday.
19025 // ISO also states week starts on Monday, but we can be more abstract here.
19027 // Start of current week: based on weekstart/current date
19028 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19029 // Thursday of this week
19030 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19031 // First Thursday of year, year from thursday
19032 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19033 // Calendar week: ms between thursdays, div ms per day, div 7 days
19034 calWeek = (th - yth) / 864e5 / 7 + 1;
19036 fillMonths.cn.push({
19044 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19046 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19049 if (this.todayHighlight &&
19050 prevMonth.getUTCFullYear() == today.getFullYear() &&
19051 prevMonth.getUTCMonth() == today.getMonth() &&
19052 prevMonth.getUTCDate() == today.getDate()) {
19053 clsName += ' today';
19056 if (currentDate && prevMonth.valueOf() === currentDate) {
19057 clsName += ' active';
19060 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19061 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19062 clsName += ' disabled';
19065 fillMonths.cn.push({
19067 cls: 'day ' + clsName,
19068 html: prevMonth.getDate()
19071 prevMonth.setDate(prevMonth.getDate()+1);
19074 var currentYear = this.date && this.date.getUTCFullYear();
19075 var currentMonth = this.date && this.date.getUTCMonth();
19077 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19079 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19080 v.removeClass('active');
19082 if(currentYear === year && k === currentMonth){
19083 v.addClass('active');
19086 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19087 v.addClass('disabled');
19093 year = parseInt(year/10, 10) * 10;
19095 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19097 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19100 for (var i = -1; i < 11; i++) {
19101 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19103 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19111 showMode: function(dir)
19114 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19117 Roo.each(this.picker().select('>div',true).elements, function(v){
19118 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19121 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19126 if(this.isInline) {
19130 this.picker().removeClass(['bottom', 'top']);
19132 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19134 * place to the top of element!
19138 this.picker().addClass('top');
19139 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19144 this.picker().addClass('bottom');
19146 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19149 parseDate : function(value)
19151 if(!value || value instanceof Date){
19154 var v = Date.parseDate(value, this.format);
19155 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19156 v = Date.parseDate(value, 'Y-m-d');
19158 if(!v && this.altFormats){
19159 if(!this.altFormatsArray){
19160 this.altFormatsArray = this.altFormats.split("|");
19162 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19163 v = Date.parseDate(value, this.altFormatsArray[i]);
19169 formatDate : function(date, fmt)
19171 return (!date || !(date instanceof Date)) ?
19172 date : date.dateFormat(fmt || this.format);
19175 onFocus : function()
19177 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19181 onBlur : function()
19183 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19185 var d = this.inputEl().getValue();
19192 showPopup : function()
19194 this.picker().show();
19198 this.fireEvent('showpopup', this, this.date);
19201 hidePopup : function()
19203 if(this.isInline) {
19206 this.picker().hide();
19207 this.viewMode = this.startViewMode;
19210 this.fireEvent('hidepopup', this, this.date);
19214 onMousedown: function(e)
19216 e.stopPropagation();
19217 e.preventDefault();
19222 Roo.bootstrap.DateField.superclass.keyup.call(this);
19226 setValue: function(v)
19228 if(this.fireEvent('beforeselect', this, v) !== false){
19229 var d = new Date(this.parseDate(v) ).clearTime();
19231 if(isNaN(d.getTime())){
19232 this.date = this.viewDate = '';
19233 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19237 v = this.formatDate(d);
19239 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19241 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19245 this.fireEvent('select', this, this.date);
19249 getValue: function()
19251 return this.formatDate(this.date);
19254 fireKey: function(e)
19256 if (!this.picker().isVisible()){
19257 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19263 var dateChanged = false,
19265 newDate, newViewDate;
19270 e.preventDefault();
19274 if (!this.keyboardNavigation) {
19277 dir = e.keyCode == 37 ? -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);
19288 newViewDate = new Date(this.viewDate);
19289 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
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;
19302 if (!this.keyboardNavigation) {
19305 dir = e.keyCode == 38 ? -1 : 1;
19307 newDate = this.moveYear(this.date, dir);
19308 newViewDate = this.moveYear(this.viewDate, dir);
19309 } else if (e.shiftKey){
19310 newDate = this.moveMonth(this.date, dir);
19311 newViewDate = this.moveMonth(this.viewDate, dir);
19313 newDate = new Date(this.date);
19314 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19315 newViewDate = new Date(this.viewDate);
19316 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19318 if (this.dateWithinRange(newDate)){
19319 this.date = newDate;
19320 this.viewDate = newViewDate;
19321 this.setValue(this.formatDate(this.date));
19323 e.preventDefault();
19324 dateChanged = true;
19328 this.setValue(this.formatDate(this.date));
19330 e.preventDefault();
19333 this.setValue(this.formatDate(this.date));
19347 onClick: function(e)
19349 e.stopPropagation();
19350 e.preventDefault();
19352 var target = e.getTarget();
19354 if(target.nodeName.toLowerCase() === 'i'){
19355 target = Roo.get(target).dom.parentNode;
19358 var nodeName = target.nodeName;
19359 var className = target.className;
19360 var html = target.innerHTML;
19361 //Roo.log(nodeName);
19363 switch(nodeName.toLowerCase()) {
19365 switch(className) {
19371 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19372 switch(this.viewMode){
19374 this.viewDate = this.moveMonth(this.viewDate, dir);
19378 this.viewDate = this.moveYear(this.viewDate, dir);
19384 var date = new Date();
19385 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19387 this.setValue(this.formatDate(this.date));
19394 if (className.indexOf('disabled') < 0) {
19395 this.viewDate.setUTCDate(1);
19396 if (className.indexOf('month') > -1) {
19397 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19399 var year = parseInt(html, 10) || 0;
19400 this.viewDate.setUTCFullYear(year);
19404 if(this.singleMode){
19405 this.setValue(this.formatDate(this.viewDate));
19416 //Roo.log(className);
19417 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19418 var day = parseInt(html, 10) || 1;
19419 var year = this.viewDate.getUTCFullYear(),
19420 month = this.viewDate.getUTCMonth();
19422 if (className.indexOf('old') > -1) {
19429 } else if (className.indexOf('new') > -1) {
19437 //Roo.log([year,month,day]);
19438 this.date = this.UTCDate(year, month, day,0,0,0,0);
19439 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19441 //Roo.log(this.formatDate(this.date));
19442 this.setValue(this.formatDate(this.date));
19449 setStartDate: function(startDate)
19451 this.startDate = startDate || -Infinity;
19452 if (this.startDate !== -Infinity) {
19453 this.startDate = this.parseDate(this.startDate);
19456 this.updateNavArrows();
19459 setEndDate: function(endDate)
19461 this.endDate = endDate || Infinity;
19462 if (this.endDate !== Infinity) {
19463 this.endDate = this.parseDate(this.endDate);
19466 this.updateNavArrows();
19469 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19471 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19472 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19473 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19475 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19476 return parseInt(d, 10);
19479 this.updateNavArrows();
19482 updateNavArrows: function()
19484 if(this.singleMode){
19488 var d = new Date(this.viewDate),
19489 year = d.getUTCFullYear(),
19490 month = d.getUTCMonth();
19492 Roo.each(this.picker().select('.prev', true).elements, function(v){
19494 switch (this.viewMode) {
19497 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19503 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19510 Roo.each(this.picker().select('.next', true).elements, function(v){
19512 switch (this.viewMode) {
19515 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19521 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19529 moveMonth: function(date, dir)
19534 var new_date = new Date(date.valueOf()),
19535 day = new_date.getUTCDate(),
19536 month = new_date.getUTCMonth(),
19537 mag = Math.abs(dir),
19539 dir = dir > 0 ? 1 : -1;
19542 // If going back one month, make sure month is not current month
19543 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19545 return new_date.getUTCMonth() == month;
19547 // If going forward one month, make sure month is as expected
19548 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19550 return new_date.getUTCMonth() != new_month;
19552 new_month = month + dir;
19553 new_date.setUTCMonth(new_month);
19554 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19555 if (new_month < 0 || new_month > 11) {
19556 new_month = (new_month + 12) % 12;
19559 // For magnitudes >1, move one month at a time...
19560 for (var i=0; i<mag; i++) {
19561 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19562 new_date = this.moveMonth(new_date, dir);
19564 // ...then reset the day, keeping it in the new month
19565 new_month = new_date.getUTCMonth();
19566 new_date.setUTCDate(day);
19568 return new_month != new_date.getUTCMonth();
19571 // Common date-resetting loop -- if date is beyond end of month, make it
19574 new_date.setUTCDate(--day);
19575 new_date.setUTCMonth(new_month);
19580 moveYear: function(date, dir)
19582 return this.moveMonth(date, dir*12);
19585 dateWithinRange: function(date)
19587 return date >= this.startDate && date <= this.endDate;
19593 this.picker().remove();
19596 validateValue : function(value)
19598 if(this.getVisibilityEl().hasClass('hidden')){
19602 if(value.length < 1) {
19603 if(this.allowBlank){
19609 if(value.length < this.minLength){
19612 if(value.length > this.maxLength){
19616 var vt = Roo.form.VTypes;
19617 if(!vt[this.vtype](value, this)){
19621 if(typeof this.validator == "function"){
19622 var msg = this.validator(value);
19628 if(this.regex && !this.regex.test(value)){
19632 if(typeof(this.parseDate(value)) == 'undefined'){
19636 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19640 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19650 this.date = this.viewDate = '';
19652 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19657 Roo.apply(Roo.bootstrap.DateField, {
19668 html: '<i class="fa fa-arrow-left"/>'
19678 html: '<i class="fa fa-arrow-right"/>'
19720 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19721 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19722 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19723 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19724 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19737 navFnc: 'FullYear',
19742 navFnc: 'FullYear',
19747 Roo.apply(Roo.bootstrap.DateField, {
19751 cls: 'datepicker dropdown-menu roo-dynamic',
19755 cls: 'datepicker-days',
19759 cls: 'table-condensed',
19761 Roo.bootstrap.DateField.head,
19765 Roo.bootstrap.DateField.footer
19772 cls: 'datepicker-months',
19776 cls: 'table-condensed',
19778 Roo.bootstrap.DateField.head,
19779 Roo.bootstrap.DateField.content,
19780 Roo.bootstrap.DateField.footer
19787 cls: 'datepicker-years',
19791 cls: 'table-condensed',
19793 Roo.bootstrap.DateField.head,
19794 Roo.bootstrap.DateField.content,
19795 Roo.bootstrap.DateField.footer
19814 * @class Roo.bootstrap.TimeField
19815 * @extends Roo.bootstrap.Input
19816 * Bootstrap DateField class
19820 * Create a new TimeField
19821 * @param {Object} config The config object
19824 Roo.bootstrap.TimeField = function(config){
19825 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19829 * Fires when this field show.
19830 * @param {Roo.bootstrap.DateField} thisthis
19831 * @param {Mixed} date The date value
19836 * Fires when this field hide.
19837 * @param {Roo.bootstrap.DateField} this
19838 * @param {Mixed} date The date value
19843 * Fires when select a date.
19844 * @param {Roo.bootstrap.DateField} this
19845 * @param {Mixed} date The date value
19851 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19854 * @cfg {String} format
19855 * The default time format string which can be overriden for localization support. The format must be
19856 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19860 onRender: function(ct, position)
19863 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19865 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19867 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19869 this.pop = this.picker().select('>.datepicker-time',true).first();
19870 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19872 this.picker().on('mousedown', this.onMousedown, this);
19873 this.picker().on('click', this.onClick, this);
19875 this.picker().addClass('datepicker-dropdown');
19880 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19881 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19882 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19883 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19884 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19885 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19889 fireKey: function(e){
19890 if (!this.picker().isVisible()){
19891 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19897 e.preventDefault();
19905 this.onTogglePeriod();
19908 this.onIncrementMinutes();
19911 this.onDecrementMinutes();
19920 onClick: function(e) {
19921 e.stopPropagation();
19922 e.preventDefault();
19925 picker : function()
19927 return this.el.select('.datepicker', true).first();
19930 fillTime: function()
19932 var time = this.pop.select('tbody', true).first();
19934 time.dom.innerHTML = '';
19949 cls: 'hours-up glyphicon glyphicon-chevron-up'
19969 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19990 cls: 'timepicker-hour',
20005 cls: 'timepicker-minute',
20020 cls: 'btn btn-primary period',
20042 cls: 'hours-down glyphicon glyphicon-chevron-down'
20062 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20080 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20087 var hours = this.time.getHours();
20088 var minutes = this.time.getMinutes();
20101 hours = hours - 12;
20105 hours = '0' + hours;
20109 minutes = '0' + minutes;
20112 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20113 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20114 this.pop.select('button', true).first().dom.innerHTML = period;
20120 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20122 var cls = ['bottom'];
20124 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20131 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20136 this.picker().addClass(cls.join('-'));
20140 Roo.each(cls, function(c){
20142 _this.picker().setTop(_this.inputEl().getHeight());
20146 _this.picker().setTop(0 - _this.picker().getHeight());
20151 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20155 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20162 onFocus : function()
20164 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20168 onBlur : function()
20170 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20176 this.picker().show();
20181 this.fireEvent('show', this, this.date);
20186 this.picker().hide();
20189 this.fireEvent('hide', this, this.date);
20192 setTime : function()
20195 this.setValue(this.time.format(this.format));
20197 this.fireEvent('select', this, this.date);
20202 onMousedown: function(e){
20203 e.stopPropagation();
20204 e.preventDefault();
20207 onIncrementHours: function()
20209 Roo.log('onIncrementHours');
20210 this.time = this.time.add(Date.HOUR, 1);
20215 onDecrementHours: function()
20217 Roo.log('onDecrementHours');
20218 this.time = this.time.add(Date.HOUR, -1);
20222 onIncrementMinutes: function()
20224 Roo.log('onIncrementMinutes');
20225 this.time = this.time.add(Date.MINUTE, 1);
20229 onDecrementMinutes: function()
20231 Roo.log('onDecrementMinutes');
20232 this.time = this.time.add(Date.MINUTE, -1);
20236 onTogglePeriod: function()
20238 Roo.log('onTogglePeriod');
20239 this.time = this.time.add(Date.HOUR, 12);
20246 Roo.apply(Roo.bootstrap.TimeField, {
20276 cls: 'btn btn-info ok',
20288 Roo.apply(Roo.bootstrap.TimeField, {
20292 cls: 'datepicker dropdown-menu',
20296 cls: 'datepicker-time',
20300 cls: 'table-condensed',
20302 Roo.bootstrap.TimeField.content,
20303 Roo.bootstrap.TimeField.footer
20322 * @class Roo.bootstrap.MonthField
20323 * @extends Roo.bootstrap.Input
20324 * Bootstrap MonthField class
20326 * @cfg {String} language default en
20329 * Create a new MonthField
20330 * @param {Object} config The config object
20333 Roo.bootstrap.MonthField = function(config){
20334 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20339 * Fires when this field show.
20340 * @param {Roo.bootstrap.MonthField} this
20341 * @param {Mixed} date The date value
20346 * Fires when this field hide.
20347 * @param {Roo.bootstrap.MonthField} this
20348 * @param {Mixed} date The date value
20353 * Fires when select a date.
20354 * @param {Roo.bootstrap.MonthField} this
20355 * @param {String} oldvalue The old value
20356 * @param {String} newvalue The new value
20362 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20364 onRender: function(ct, position)
20367 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20369 this.language = this.language || 'en';
20370 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20371 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20373 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20374 this.isInline = false;
20375 this.isInput = true;
20376 this.component = this.el.select('.add-on', true).first() || false;
20377 this.component = (this.component && this.component.length === 0) ? false : this.component;
20378 this.hasInput = this.component && this.inputEL().length;
20380 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20382 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20384 this.picker().on('mousedown', this.onMousedown, this);
20385 this.picker().on('click', this.onClick, this);
20387 this.picker().addClass('datepicker-dropdown');
20389 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20390 v.setStyle('width', '189px');
20397 if(this.isInline) {
20403 setValue: function(v, suppressEvent)
20405 var o = this.getValue();
20407 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20411 if(suppressEvent !== true){
20412 this.fireEvent('select', this, o, v);
20417 getValue: function()
20422 onClick: function(e)
20424 e.stopPropagation();
20425 e.preventDefault();
20427 var target = e.getTarget();
20429 if(target.nodeName.toLowerCase() === 'i'){
20430 target = Roo.get(target).dom.parentNode;
20433 var nodeName = target.nodeName;
20434 var className = target.className;
20435 var html = target.innerHTML;
20437 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20441 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20443 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20449 picker : function()
20451 return this.pickerEl;
20454 fillMonths: function()
20457 var months = this.picker().select('>.datepicker-months td', true).first();
20459 months.dom.innerHTML = '';
20465 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20468 months.createChild(month);
20477 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20478 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20481 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20482 e.removeClass('active');
20484 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20485 e.addClass('active');
20492 if(this.isInline) {
20496 this.picker().removeClass(['bottom', 'top']);
20498 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20500 * place to the top of element!
20504 this.picker().addClass('top');
20505 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20510 this.picker().addClass('bottom');
20512 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20515 onFocus : function()
20517 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20521 onBlur : function()
20523 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20525 var d = this.inputEl().getValue();
20534 this.picker().show();
20535 this.picker().select('>.datepicker-months', true).first().show();
20539 this.fireEvent('show', this, this.date);
20544 if(this.isInline) {
20547 this.picker().hide();
20548 this.fireEvent('hide', this, this.date);
20552 onMousedown: function(e)
20554 e.stopPropagation();
20555 e.preventDefault();
20560 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20564 fireKey: function(e)
20566 if (!this.picker().isVisible()){
20567 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20578 e.preventDefault();
20582 dir = e.keyCode == 37 ? -1 : 1;
20584 this.vIndex = this.vIndex + dir;
20586 if(this.vIndex < 0){
20590 if(this.vIndex > 11){
20594 if(isNaN(this.vIndex)){
20598 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20604 dir = e.keyCode == 38 ? -1 : 1;
20606 this.vIndex = this.vIndex + dir * 4;
20608 if(this.vIndex < 0){
20612 if(this.vIndex > 11){
20616 if(isNaN(this.vIndex)){
20620 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20625 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20626 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20630 e.preventDefault();
20633 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20634 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20650 this.picker().remove();
20655 Roo.apply(Roo.bootstrap.MonthField, {
20674 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20675 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20680 Roo.apply(Roo.bootstrap.MonthField, {
20684 cls: 'datepicker dropdown-menu roo-dynamic',
20688 cls: 'datepicker-months',
20692 cls: 'table-condensed',
20694 Roo.bootstrap.DateField.content
20714 * @class Roo.bootstrap.CheckBox
20715 * @extends Roo.bootstrap.Input
20716 * Bootstrap CheckBox class
20718 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20719 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20720 * @cfg {String} boxLabel The text that appears beside the checkbox
20721 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20722 * @cfg {Boolean} checked initnal the element
20723 * @cfg {Boolean} inline inline the element (default false)
20724 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20725 * @cfg {String} tooltip label tooltip
20728 * Create a new CheckBox
20729 * @param {Object} config The config object
20732 Roo.bootstrap.CheckBox = function(config){
20733 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20738 * Fires when the element is checked or unchecked.
20739 * @param {Roo.bootstrap.CheckBox} this This input
20740 * @param {Boolean} checked The new checked value
20745 * Fires when the element is click.
20746 * @param {Roo.bootstrap.CheckBox} this This input
20753 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20755 inputType: 'checkbox',
20764 getAutoCreate : function()
20766 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20772 cfg.cls = 'form-group ' + this.inputType; //input-group
20775 cfg.cls += ' ' + this.inputType + '-inline';
20781 type : this.inputType,
20782 value : this.inputValue,
20783 cls : 'roo-' + this.inputType, //'form-box',
20784 placeholder : this.placeholder || ''
20788 if(this.inputType != 'radio'){
20792 cls : 'roo-hidden-value',
20793 value : this.checked ? this.inputValue : this.valueOff
20798 if (this.weight) { // Validity check?
20799 cfg.cls += " " + this.inputType + "-" + this.weight;
20802 if (this.disabled) {
20803 input.disabled=true;
20807 input.checked = this.checked;
20812 input.name = this.name;
20814 if(this.inputType != 'radio'){
20815 hidden.name = this.name;
20816 input.name = '_hidden_' + this.name;
20821 input.cls += ' input-' + this.size;
20826 ['xs','sm','md','lg'].map(function(size){
20827 if (settings[size]) {
20828 cfg.cls += ' col-' + size + '-' + settings[size];
20832 var inputblock = input;
20834 if (this.before || this.after) {
20837 cls : 'input-group',
20842 inputblock.cn.push({
20844 cls : 'input-group-addon',
20849 inputblock.cn.push(input);
20851 if(this.inputType != 'radio'){
20852 inputblock.cn.push(hidden);
20856 inputblock.cn.push({
20858 cls : 'input-group-addon',
20865 if (align ==='left' && this.fieldLabel.length) {
20866 // Roo.log("left and has label");
20871 cls : 'control-label',
20872 html : this.fieldLabel
20882 if(this.labelWidth > 12){
20883 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20886 if(this.labelWidth < 13 && this.labelmd == 0){
20887 this.labelmd = this.labelWidth;
20890 if(this.labellg > 0){
20891 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20892 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20895 if(this.labelmd > 0){
20896 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20897 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20900 if(this.labelsm > 0){
20901 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20902 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20905 if(this.labelxs > 0){
20906 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20907 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20910 } else if ( this.fieldLabel.length) {
20911 // Roo.log(" label");
20915 tag: this.boxLabel ? 'span' : 'label',
20917 cls: 'control-label box-input-label',
20918 //cls : 'input-group-addon',
20919 html : this.fieldLabel
20928 // Roo.log(" no label && no align");
20929 cfg.cn = [ inputblock ] ;
20935 var boxLabelCfg = {
20937 //'for': id, // box label is handled by onclick - so no for...
20939 html: this.boxLabel
20943 boxLabelCfg.tooltip = this.tooltip;
20946 cfg.cn.push(boxLabelCfg);
20949 if(this.inputType != 'radio'){
20950 cfg.cn.push(hidden);
20958 * return the real input element.
20960 inputEl: function ()
20962 return this.el.select('input.roo-' + this.inputType,true).first();
20964 hiddenEl: function ()
20966 return this.el.select('input.roo-hidden-value',true).first();
20969 labelEl: function()
20971 return this.el.select('label.control-label',true).first();
20973 /* depricated... */
20977 return this.labelEl();
20980 boxLabelEl: function()
20982 return this.el.select('label.box-label',true).first();
20985 initEvents : function()
20987 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20989 this.inputEl().on('click', this.onClick, this);
20991 if (this.boxLabel) {
20992 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20995 this.startValue = this.getValue();
20998 Roo.bootstrap.CheckBox.register(this);
21002 onClick : function(e)
21004 if(this.fireEvent('click', this, e) !== false){
21005 this.setChecked(!this.checked);
21010 setChecked : function(state,suppressEvent)
21012 this.startValue = this.getValue();
21014 if(this.inputType == 'radio'){
21016 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21017 e.dom.checked = false;
21020 this.inputEl().dom.checked = true;
21022 this.inputEl().dom.value = this.inputValue;
21024 if(suppressEvent !== true){
21025 this.fireEvent('check', this, true);
21033 this.checked = state;
21035 this.inputEl().dom.checked = state;
21038 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21040 if(suppressEvent !== true){
21041 this.fireEvent('check', this, state);
21047 getValue : function()
21049 if(this.inputType == 'radio'){
21050 return this.getGroupValue();
21053 return this.hiddenEl().dom.value;
21057 getGroupValue : function()
21059 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21063 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21066 setValue : function(v,suppressEvent)
21068 if(this.inputType == 'radio'){
21069 this.setGroupValue(v, suppressEvent);
21073 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21078 setGroupValue : function(v, suppressEvent)
21080 this.startValue = this.getValue();
21082 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21083 e.dom.checked = false;
21085 if(e.dom.value == v){
21086 e.dom.checked = true;
21090 if(suppressEvent !== true){
21091 this.fireEvent('check', this, true);
21099 validate : function()
21101 if(this.getVisibilityEl().hasClass('hidden')){
21107 (this.inputType == 'radio' && this.validateRadio()) ||
21108 (this.inputType == 'checkbox' && this.validateCheckbox())
21114 this.markInvalid();
21118 validateRadio : function()
21120 if(this.getVisibilityEl().hasClass('hidden')){
21124 if(this.allowBlank){
21130 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21131 if(!e.dom.checked){
21143 validateCheckbox : function()
21146 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21147 //return (this.getValue() == this.inputValue) ? true : false;
21150 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21158 for(var i in group){
21159 if(group[i].el.isVisible(true)){
21167 for(var i in group){
21172 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21179 * Mark this field as valid
21181 markValid : function()
21185 this.fireEvent('valid', this);
21187 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21190 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21197 if(this.inputType == 'radio'){
21198 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21199 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21200 e.findParent('.form-group', false, true).addClass(_this.validClass);
21207 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21208 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21212 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21218 for(var i in group){
21219 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21220 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21225 * Mark this field as invalid
21226 * @param {String} msg The validation message
21228 markInvalid : function(msg)
21230 if(this.allowBlank){
21236 this.fireEvent('invalid', this, msg);
21238 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21241 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21245 label.markInvalid();
21248 if(this.inputType == 'radio'){
21249 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21250 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21251 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21258 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21259 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21263 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21269 for(var i in group){
21270 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21271 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21276 clearInvalid : function()
21278 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21280 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21282 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21284 if (label && label.iconEl) {
21285 label.iconEl.removeClass(label.validClass);
21286 label.iconEl.removeClass(label.invalidClass);
21290 disable : function()
21292 if(this.inputType != 'radio'){
21293 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21300 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21301 _this.getActionEl().addClass(this.disabledClass);
21302 e.dom.disabled = true;
21306 this.disabled = true;
21307 this.fireEvent("disable", this);
21311 enable : function()
21313 if(this.inputType != 'radio'){
21314 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21321 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21322 _this.getActionEl().removeClass(this.disabledClass);
21323 e.dom.disabled = false;
21327 this.disabled = false;
21328 this.fireEvent("enable", this);
21332 setBoxLabel : function(v)
21337 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21343 Roo.apply(Roo.bootstrap.CheckBox, {
21348 * register a CheckBox Group
21349 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21351 register : function(checkbox)
21353 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21354 this.groups[checkbox.groupId] = {};
21357 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21361 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21365 * fetch a CheckBox Group based on the group ID
21366 * @param {string} the group ID
21367 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21369 get: function(groupId) {
21370 if (typeof(this.groups[groupId]) == 'undefined') {
21374 return this.groups[groupId] ;
21387 * @class Roo.bootstrap.Radio
21388 * @extends Roo.bootstrap.Component
21389 * Bootstrap Radio class
21390 * @cfg {String} boxLabel - the label associated
21391 * @cfg {String} value - the value of radio
21394 * Create a new Radio
21395 * @param {Object} config The config object
21397 Roo.bootstrap.Radio = function(config){
21398 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21402 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21408 getAutoCreate : function()
21412 cls : 'form-group radio',
21417 html : this.boxLabel
21425 initEvents : function()
21427 this.parent().register(this);
21429 this.el.on('click', this.onClick, this);
21433 onClick : function(e)
21435 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21436 this.setChecked(true);
21440 setChecked : function(state, suppressEvent)
21442 this.parent().setValue(this.value, suppressEvent);
21446 setBoxLabel : function(v)
21451 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21466 * @class Roo.bootstrap.SecurePass
21467 * @extends Roo.bootstrap.Input
21468 * Bootstrap SecurePass class
21472 * Create a new SecurePass
21473 * @param {Object} config The config object
21476 Roo.bootstrap.SecurePass = function (config) {
21477 // these go here, so the translation tool can replace them..
21479 PwdEmpty: "Please type a password, and then retype it to confirm.",
21480 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21481 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21482 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21483 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21484 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21485 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21486 TooWeak: "Your password is Too Weak."
21488 this.meterLabel = "Password strength:";
21489 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21490 this.meterClass = [
21491 "roo-password-meter-tooweak",
21492 "roo-password-meter-weak",
21493 "roo-password-meter-medium",
21494 "roo-password-meter-strong",
21495 "roo-password-meter-grey"
21500 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21503 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21505 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21507 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21508 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21509 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21510 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21511 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21512 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21513 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21523 * @cfg {String/Object} Label for the strength meter (defaults to
21524 * 'Password strength:')
21529 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21530 * ['Weak', 'Medium', 'Strong'])
21533 pwdStrengths: false,
21546 initEvents: function ()
21548 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21550 if (this.el.is('input[type=password]') && Roo.isSafari) {
21551 this.el.on('keydown', this.SafariOnKeyDown, this);
21554 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21557 onRender: function (ct, position)
21559 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21560 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21561 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21563 this.trigger.createChild({
21568 cls: 'roo-password-meter-grey col-xs-12',
21571 //width: this.meterWidth + 'px'
21575 cls: 'roo-password-meter-text'
21581 if (this.hideTrigger) {
21582 this.trigger.setDisplayed(false);
21584 this.setSize(this.width || '', this.height || '');
21587 onDestroy: function ()
21589 if (this.trigger) {
21590 this.trigger.removeAllListeners();
21591 this.trigger.remove();
21594 this.wrap.remove();
21596 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21599 checkStrength: function ()
21601 var pwd = this.inputEl().getValue();
21602 if (pwd == this._lastPwd) {
21607 if (this.ClientSideStrongPassword(pwd)) {
21609 } else if (this.ClientSideMediumPassword(pwd)) {
21611 } else if (this.ClientSideWeakPassword(pwd)) {
21617 Roo.log('strength1: ' + strength);
21619 //var pm = this.trigger.child('div/div/div').dom;
21620 var pm = this.trigger.child('div/div');
21621 pm.removeClass(this.meterClass);
21622 pm.addClass(this.meterClass[strength]);
21625 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21627 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21629 this._lastPwd = pwd;
21633 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21635 this._lastPwd = '';
21637 var pm = this.trigger.child('div/div');
21638 pm.removeClass(this.meterClass);
21639 pm.addClass('roo-password-meter-grey');
21642 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21645 this.inputEl().dom.type='password';
21648 validateValue: function (value)
21651 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21654 if (value.length == 0) {
21655 if (this.allowBlank) {
21656 this.clearInvalid();
21660 this.markInvalid(this.errors.PwdEmpty);
21661 this.errorMsg = this.errors.PwdEmpty;
21669 if ('[\x21-\x7e]*'.match(value)) {
21670 this.markInvalid(this.errors.PwdBadChar);
21671 this.errorMsg = this.errors.PwdBadChar;
21674 if (value.length < 6) {
21675 this.markInvalid(this.errors.PwdShort);
21676 this.errorMsg = this.errors.PwdShort;
21679 if (value.length > 16) {
21680 this.markInvalid(this.errors.PwdLong);
21681 this.errorMsg = this.errors.PwdLong;
21685 if (this.ClientSideStrongPassword(value)) {
21687 } else if (this.ClientSideMediumPassword(value)) {
21689 } else if (this.ClientSideWeakPassword(value)) {
21696 if (strength < 2) {
21697 //this.markInvalid(this.errors.TooWeak);
21698 this.errorMsg = this.errors.TooWeak;
21703 console.log('strength2: ' + strength);
21705 //var pm = this.trigger.child('div/div/div').dom;
21707 var pm = this.trigger.child('div/div');
21708 pm.removeClass(this.meterClass);
21709 pm.addClass(this.meterClass[strength]);
21711 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21713 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21715 this.errorMsg = '';
21719 CharacterSetChecks: function (type)
21722 this.fResult = false;
21725 isctype: function (character, type)
21728 case this.kCapitalLetter:
21729 if (character >= 'A' && character <= 'Z') {
21734 case this.kSmallLetter:
21735 if (character >= 'a' && character <= 'z') {
21741 if (character >= '0' && character <= '9') {
21746 case this.kPunctuation:
21747 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21758 IsLongEnough: function (pwd, size)
21760 return !(pwd == null || isNaN(size) || pwd.length < size);
21763 SpansEnoughCharacterSets: function (word, nb)
21765 if (!this.IsLongEnough(word, nb))
21770 var characterSetChecks = new Array(
21771 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21772 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21775 for (var index = 0; index < word.length; ++index) {
21776 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21777 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21778 characterSetChecks[nCharSet].fResult = true;
21785 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21786 if (characterSetChecks[nCharSet].fResult) {
21791 if (nCharSets < nb) {
21797 ClientSideStrongPassword: function (pwd)
21799 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21802 ClientSideMediumPassword: function (pwd)
21804 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21807 ClientSideWeakPassword: function (pwd)
21809 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21812 })//<script type="text/javascript">
21815 * Based Ext JS Library 1.1.1
21816 * Copyright(c) 2006-2007, Ext JS, LLC.
21822 * @class Roo.HtmlEditorCore
21823 * @extends Roo.Component
21824 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21826 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21829 Roo.HtmlEditorCore = function(config){
21832 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21837 * @event initialize
21838 * Fires when the editor is fully initialized (including the iframe)
21839 * @param {Roo.HtmlEditorCore} this
21844 * Fires when the editor is first receives the focus. Any insertion must wait
21845 * until after this event.
21846 * @param {Roo.HtmlEditorCore} this
21850 * @event beforesync
21851 * Fires before the textarea is updated with content from the editor iframe. Return false
21852 * to cancel the sync.
21853 * @param {Roo.HtmlEditorCore} this
21854 * @param {String} html
21858 * @event beforepush
21859 * Fires before the iframe editor is updated with content from the textarea. Return false
21860 * to cancel the push.
21861 * @param {Roo.HtmlEditorCore} this
21862 * @param {String} html
21867 * Fires when the textarea is updated with content from the editor iframe.
21868 * @param {Roo.HtmlEditorCore} this
21869 * @param {String} html
21874 * Fires when the iframe editor is updated with content from the textarea.
21875 * @param {Roo.HtmlEditorCore} this
21876 * @param {String} html
21881 * @event editorevent
21882 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21883 * @param {Roo.HtmlEditorCore} this
21889 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21891 // defaults : white / black...
21892 this.applyBlacklists();
21899 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21903 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21909 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21914 * @cfg {Number} height (in pixels)
21918 * @cfg {Number} width (in pixels)
21923 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21926 stylesheets: false,
21931 // private properties
21932 validationEvent : false,
21934 initialized : false,
21936 sourceEditMode : false,
21937 onFocus : Roo.emptyFn,
21939 hideMode:'offsets',
21943 // blacklist + whitelisted elements..
21950 * Protected method that will not generally be called directly. It
21951 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21952 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21954 getDocMarkup : function(){
21958 // inherit styels from page...??
21959 if (this.stylesheets === false) {
21961 Roo.get(document.head).select('style').each(function(node) {
21962 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21965 Roo.get(document.head).select('link').each(function(node) {
21966 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21969 } else if (!this.stylesheets.length) {
21971 st = '<style type="text/css">' +
21972 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21975 st = '<style type="text/css">' +
21980 st += '<style type="text/css">' +
21981 'IMG { cursor: pointer } ' +
21984 var cls = 'roo-htmleditor-body';
21986 if(this.bodyCls.length){
21987 cls += ' ' + this.bodyCls;
21990 return '<html><head>' + st +
21991 //<style type="text/css">' +
21992 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21994 ' </head><body class="' + cls + '"></body></html>';
21998 onRender : function(ct, position)
22001 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22002 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22005 this.el.dom.style.border = '0 none';
22006 this.el.dom.setAttribute('tabIndex', -1);
22007 this.el.addClass('x-hidden hide');
22011 if(Roo.isIE){ // fix IE 1px bogus margin
22012 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22016 this.frameId = Roo.id();
22020 var iframe = this.owner.wrap.createChild({
22022 cls: 'form-control', // bootstrap..
22024 name: this.frameId,
22025 frameBorder : 'no',
22026 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22031 this.iframe = iframe.dom;
22033 this.assignDocWin();
22035 this.doc.designMode = 'on';
22038 this.doc.write(this.getDocMarkup());
22042 var task = { // must defer to wait for browser to be ready
22044 //console.log("run task?" + this.doc.readyState);
22045 this.assignDocWin();
22046 if(this.doc.body || this.doc.readyState == 'complete'){
22048 this.doc.designMode="on";
22052 Roo.TaskMgr.stop(task);
22053 this.initEditor.defer(10, this);
22060 Roo.TaskMgr.start(task);
22065 onResize : function(w, h)
22067 Roo.log('resize: ' +w + ',' + h );
22068 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22072 if(typeof w == 'number'){
22074 this.iframe.style.width = w + 'px';
22076 if(typeof h == 'number'){
22078 this.iframe.style.height = h + 'px';
22080 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22087 * Toggles the editor between standard and source edit mode.
22088 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22090 toggleSourceEdit : function(sourceEditMode){
22092 this.sourceEditMode = sourceEditMode === true;
22094 if(this.sourceEditMode){
22096 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22099 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22100 //this.iframe.className = '';
22103 //this.setSize(this.owner.wrap.getSize());
22104 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22111 * Protected method that will not generally be called directly. If you need/want
22112 * custom HTML cleanup, this is the method you should override.
22113 * @param {String} html The HTML to be cleaned
22114 * return {String} The cleaned HTML
22116 cleanHtml : function(html){
22117 html = String(html);
22118 if(html.length > 5){
22119 if(Roo.isSafari){ // strip safari nonsense
22120 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22123 if(html == ' '){
22130 * HTML Editor -> Textarea
22131 * Protected method that will not generally be called directly. Syncs the contents
22132 * of the editor iframe with the textarea.
22134 syncValue : function(){
22135 if(this.initialized){
22136 var bd = (this.doc.body || this.doc.documentElement);
22137 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22138 var html = bd.innerHTML;
22140 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22141 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22143 html = '<div style="'+m[0]+'">' + html + '</div>';
22146 html = this.cleanHtml(html);
22147 // fix up the special chars.. normaly like back quotes in word...
22148 // however we do not want to do this with chinese..
22149 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22150 var cc = b.charCodeAt();
22152 (cc >= 0x4E00 && cc < 0xA000 ) ||
22153 (cc >= 0x3400 && cc < 0x4E00 ) ||
22154 (cc >= 0xf900 && cc < 0xfb00 )
22160 if(this.owner.fireEvent('beforesync', this, html) !== false){
22161 this.el.dom.value = html;
22162 this.owner.fireEvent('sync', this, html);
22168 * Protected method that will not generally be called directly. Pushes the value of the textarea
22169 * into the iframe editor.
22171 pushValue : function(){
22172 if(this.initialized){
22173 var v = this.el.dom.value.trim();
22175 // if(v.length < 1){
22179 if(this.owner.fireEvent('beforepush', this, v) !== false){
22180 var d = (this.doc.body || this.doc.documentElement);
22182 this.cleanUpPaste();
22183 this.el.dom.value = d.innerHTML;
22184 this.owner.fireEvent('push', this, v);
22190 deferFocus : function(){
22191 this.focus.defer(10, this);
22195 focus : function(){
22196 if(this.win && !this.sourceEditMode){
22203 assignDocWin: function()
22205 var iframe = this.iframe;
22208 this.doc = iframe.contentWindow.document;
22209 this.win = iframe.contentWindow;
22211 // if (!Roo.get(this.frameId)) {
22214 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22215 // this.win = Roo.get(this.frameId).dom.contentWindow;
22217 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22221 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22222 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22227 initEditor : function(){
22228 //console.log("INIT EDITOR");
22229 this.assignDocWin();
22233 this.doc.designMode="on";
22235 this.doc.write(this.getDocMarkup());
22238 var dbody = (this.doc.body || this.doc.documentElement);
22239 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22240 // this copies styles from the containing element into thsi one..
22241 // not sure why we need all of this..
22242 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22244 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22245 //ss['background-attachment'] = 'fixed'; // w3c
22246 dbody.bgProperties = 'fixed'; // ie
22247 //Roo.DomHelper.applyStyles(dbody, ss);
22248 Roo.EventManager.on(this.doc, {
22249 //'mousedown': this.onEditorEvent,
22250 'mouseup': this.onEditorEvent,
22251 'dblclick': this.onEditorEvent,
22252 'click': this.onEditorEvent,
22253 'keyup': this.onEditorEvent,
22258 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22260 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22261 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22263 this.initialized = true;
22265 this.owner.fireEvent('initialize', this);
22270 onDestroy : function(){
22276 //for (var i =0; i < this.toolbars.length;i++) {
22277 // // fixme - ask toolbars for heights?
22278 // this.toolbars[i].onDestroy();
22281 //this.wrap.dom.innerHTML = '';
22282 //this.wrap.remove();
22287 onFirstFocus : function(){
22289 this.assignDocWin();
22292 this.activated = true;
22295 if(Roo.isGecko){ // prevent silly gecko errors
22297 var s = this.win.getSelection();
22298 if(!s.focusNode || s.focusNode.nodeType != 3){
22299 var r = s.getRangeAt(0);
22300 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22305 this.execCmd('useCSS', true);
22306 this.execCmd('styleWithCSS', false);
22309 this.owner.fireEvent('activate', this);
22313 adjustFont: function(btn){
22314 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22315 //if(Roo.isSafari){ // safari
22318 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22319 if(Roo.isSafari){ // safari
22320 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22321 v = (v < 10) ? 10 : v;
22322 v = (v > 48) ? 48 : v;
22323 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22328 v = Math.max(1, v+adjust);
22330 this.execCmd('FontSize', v );
22333 onEditorEvent : function(e)
22335 this.owner.fireEvent('editorevent', this, e);
22336 // this.updateToolbar();
22337 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22340 insertTag : function(tg)
22342 // could be a bit smarter... -> wrap the current selected tRoo..
22343 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22345 range = this.createRange(this.getSelection());
22346 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22347 wrappingNode.appendChild(range.extractContents());
22348 range.insertNode(wrappingNode);
22355 this.execCmd("formatblock", tg);
22359 insertText : function(txt)
22363 var range = this.createRange();
22364 range.deleteContents();
22365 //alert(Sender.getAttribute('label'));
22367 range.insertNode(this.doc.createTextNode(txt));
22373 * Executes a Midas editor command on the editor document and performs necessary focus and
22374 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22375 * @param {String} cmd The Midas command
22376 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22378 relayCmd : function(cmd, value){
22380 this.execCmd(cmd, value);
22381 this.owner.fireEvent('editorevent', this);
22382 //this.updateToolbar();
22383 this.owner.deferFocus();
22387 * Executes a Midas editor command directly on the editor document.
22388 * For visual commands, you should use {@link #relayCmd} instead.
22389 * <b>This should only be called after the editor is initialized.</b>
22390 * @param {String} cmd The Midas command
22391 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22393 execCmd : function(cmd, value){
22394 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22401 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22403 * @param {String} text | dom node..
22405 insertAtCursor : function(text)
22408 if(!this.activated){
22414 var r = this.doc.selection.createRange();
22425 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22429 // from jquery ui (MIT licenced)
22431 var win = this.win;
22433 if (win.getSelection && win.getSelection().getRangeAt) {
22434 range = win.getSelection().getRangeAt(0);
22435 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22436 range.insertNode(node);
22437 } else if (win.document.selection && win.document.selection.createRange) {
22438 // no firefox support
22439 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22440 win.document.selection.createRange().pasteHTML(txt);
22442 // no firefox support
22443 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22444 this.execCmd('InsertHTML', txt);
22453 mozKeyPress : function(e){
22455 var c = e.getCharCode(), cmd;
22458 c = String.fromCharCode(c).toLowerCase();
22472 this.cleanUpPaste.defer(100, this);
22480 e.preventDefault();
22488 fixKeys : function(){ // load time branching for fastest keydown performance
22490 return function(e){
22491 var k = e.getKey(), r;
22494 r = this.doc.selection.createRange();
22497 r.pasteHTML('    ');
22504 r = this.doc.selection.createRange();
22506 var target = r.parentElement();
22507 if(!target || target.tagName.toLowerCase() != 'li'){
22509 r.pasteHTML('<br />');
22515 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22516 this.cleanUpPaste.defer(100, this);
22522 }else if(Roo.isOpera){
22523 return function(e){
22524 var k = e.getKey();
22528 this.execCmd('InsertHTML','    ');
22531 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22532 this.cleanUpPaste.defer(100, this);
22537 }else if(Roo.isSafari){
22538 return function(e){
22539 var k = e.getKey();
22543 this.execCmd('InsertText','\t');
22547 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22548 this.cleanUpPaste.defer(100, this);
22556 getAllAncestors: function()
22558 var p = this.getSelectedNode();
22561 a.push(p); // push blank onto stack..
22562 p = this.getParentElement();
22566 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22570 a.push(this.doc.body);
22574 lastSelNode : false,
22577 getSelection : function()
22579 this.assignDocWin();
22580 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22583 getSelectedNode: function()
22585 // this may only work on Gecko!!!
22587 // should we cache this!!!!
22592 var range = this.createRange(this.getSelection()).cloneRange();
22595 var parent = range.parentElement();
22597 var testRange = range.duplicate();
22598 testRange.moveToElementText(parent);
22599 if (testRange.inRange(range)) {
22602 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22605 parent = parent.parentElement;
22610 // is ancestor a text element.
22611 var ac = range.commonAncestorContainer;
22612 if (ac.nodeType == 3) {
22613 ac = ac.parentNode;
22616 var ar = ac.childNodes;
22619 var other_nodes = [];
22620 var has_other_nodes = false;
22621 for (var i=0;i<ar.length;i++) {
22622 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22625 // fullly contained node.
22627 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22632 // probably selected..
22633 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22634 other_nodes.push(ar[i]);
22638 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22643 has_other_nodes = true;
22645 if (!nodes.length && other_nodes.length) {
22646 nodes= other_nodes;
22648 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22654 createRange: function(sel)
22656 // this has strange effects when using with
22657 // top toolbar - not sure if it's a great idea.
22658 //this.editor.contentWindow.focus();
22659 if (typeof sel != "undefined") {
22661 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22663 return this.doc.createRange();
22666 return this.doc.createRange();
22669 getParentElement: function()
22672 this.assignDocWin();
22673 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22675 var range = this.createRange(sel);
22678 var p = range.commonAncestorContainer;
22679 while (p.nodeType == 3) { // text node
22690 * Range intersection.. the hard stuff...
22694 * [ -- selected range --- ]
22698 * if end is before start or hits it. fail.
22699 * if start is after end or hits it fail.
22701 * if either hits (but other is outside. - then it's not
22707 // @see http://www.thismuchiknow.co.uk/?p=64.
22708 rangeIntersectsNode : function(range, node)
22710 var nodeRange = node.ownerDocument.createRange();
22712 nodeRange.selectNode(node);
22714 nodeRange.selectNodeContents(node);
22717 var rangeStartRange = range.cloneRange();
22718 rangeStartRange.collapse(true);
22720 var rangeEndRange = range.cloneRange();
22721 rangeEndRange.collapse(false);
22723 var nodeStartRange = nodeRange.cloneRange();
22724 nodeStartRange.collapse(true);
22726 var nodeEndRange = nodeRange.cloneRange();
22727 nodeEndRange.collapse(false);
22729 return rangeStartRange.compareBoundaryPoints(
22730 Range.START_TO_START, nodeEndRange) == -1 &&
22731 rangeEndRange.compareBoundaryPoints(
22732 Range.START_TO_START, nodeStartRange) == 1;
22736 rangeCompareNode : function(range, node)
22738 var nodeRange = node.ownerDocument.createRange();
22740 nodeRange.selectNode(node);
22742 nodeRange.selectNodeContents(node);
22746 range.collapse(true);
22748 nodeRange.collapse(true);
22750 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22751 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22753 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22755 var nodeIsBefore = ss == 1;
22756 var nodeIsAfter = ee == -1;
22758 if (nodeIsBefore && nodeIsAfter) {
22761 if (!nodeIsBefore && nodeIsAfter) {
22762 return 1; //right trailed.
22765 if (nodeIsBefore && !nodeIsAfter) {
22766 return 2; // left trailed.
22772 // private? - in a new class?
22773 cleanUpPaste : function()
22775 // cleans up the whole document..
22776 Roo.log('cleanuppaste');
22778 this.cleanUpChildren(this.doc.body);
22779 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22780 if (clean != this.doc.body.innerHTML) {
22781 this.doc.body.innerHTML = clean;
22786 cleanWordChars : function(input) {// change the chars to hex code
22787 var he = Roo.HtmlEditorCore;
22789 var output = input;
22790 Roo.each(he.swapCodes, function(sw) {
22791 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22793 output = output.replace(swapper, sw[1]);
22800 cleanUpChildren : function (n)
22802 if (!n.childNodes.length) {
22805 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22806 this.cleanUpChild(n.childNodes[i]);
22813 cleanUpChild : function (node)
22816 //console.log(node);
22817 if (node.nodeName == "#text") {
22818 // clean up silly Windows -- stuff?
22821 if (node.nodeName == "#comment") {
22822 node.parentNode.removeChild(node);
22823 // clean up silly Windows -- stuff?
22826 var lcname = node.tagName.toLowerCase();
22827 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22828 // whitelist of tags..
22830 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22832 node.parentNode.removeChild(node);
22837 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22839 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22840 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22842 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22843 // remove_keep_children = true;
22846 if (remove_keep_children) {
22847 this.cleanUpChildren(node);
22848 // inserts everything just before this node...
22849 while (node.childNodes.length) {
22850 var cn = node.childNodes[0];
22851 node.removeChild(cn);
22852 node.parentNode.insertBefore(cn, node);
22854 node.parentNode.removeChild(node);
22858 if (!node.attributes || !node.attributes.length) {
22859 this.cleanUpChildren(node);
22863 function cleanAttr(n,v)
22866 if (v.match(/^\./) || v.match(/^\//)) {
22869 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22872 if (v.match(/^#/)) {
22875 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22876 node.removeAttribute(n);
22880 var cwhite = this.cwhite;
22881 var cblack = this.cblack;
22883 function cleanStyle(n,v)
22885 if (v.match(/expression/)) { //XSS?? should we even bother..
22886 node.removeAttribute(n);
22890 var parts = v.split(/;/);
22893 Roo.each(parts, function(p) {
22894 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22898 var l = p.split(':').shift().replace(/\s+/g,'');
22899 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22901 if ( cwhite.length && cblack.indexOf(l) > -1) {
22902 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22903 //node.removeAttribute(n);
22907 // only allow 'c whitelisted system attributes'
22908 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22909 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22910 //node.removeAttribute(n);
22920 if (clean.length) {
22921 node.setAttribute(n, clean.join(';'));
22923 node.removeAttribute(n);
22929 for (var i = node.attributes.length-1; i > -1 ; i--) {
22930 var a = node.attributes[i];
22933 if (a.name.toLowerCase().substr(0,2)=='on') {
22934 node.removeAttribute(a.name);
22937 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22938 node.removeAttribute(a.name);
22941 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22942 cleanAttr(a.name,a.value); // fixme..
22945 if (a.name == 'style') {
22946 cleanStyle(a.name,a.value);
22949 /// clean up MS crap..
22950 // tecnically this should be a list of valid class'es..
22953 if (a.name == 'class') {
22954 if (a.value.match(/^Mso/)) {
22955 node.className = '';
22958 if (a.value.match(/^body$/)) {
22959 node.className = '';
22970 this.cleanUpChildren(node);
22976 * Clean up MS wordisms...
22978 cleanWord : function(node)
22983 this.cleanWord(this.doc.body);
22986 if (node.nodeName == "#text") {
22987 // clean up silly Windows -- stuff?
22990 if (node.nodeName == "#comment") {
22991 node.parentNode.removeChild(node);
22992 // clean up silly Windows -- stuff?
22996 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22997 node.parentNode.removeChild(node);
23001 // remove - but keep children..
23002 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23003 while (node.childNodes.length) {
23004 var cn = node.childNodes[0];
23005 node.removeChild(cn);
23006 node.parentNode.insertBefore(cn, node);
23008 node.parentNode.removeChild(node);
23009 this.iterateChildren(node, this.cleanWord);
23013 if (node.className.length) {
23015 var cn = node.className.split(/\W+/);
23017 Roo.each(cn, function(cls) {
23018 if (cls.match(/Mso[a-zA-Z]+/)) {
23023 node.className = cna.length ? cna.join(' ') : '';
23025 node.removeAttribute("class");
23029 if (node.hasAttribute("lang")) {
23030 node.removeAttribute("lang");
23033 if (node.hasAttribute("style")) {
23035 var styles = node.getAttribute("style").split(";");
23037 Roo.each(styles, function(s) {
23038 if (!s.match(/:/)) {
23041 var kv = s.split(":");
23042 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23045 // what ever is left... we allow.
23048 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23049 if (!nstyle.length) {
23050 node.removeAttribute('style');
23053 this.iterateChildren(node, this.cleanWord);
23059 * iterateChildren of a Node, calling fn each time, using this as the scole..
23060 * @param {DomNode} node node to iterate children of.
23061 * @param {Function} fn method of this class to call on each item.
23063 iterateChildren : function(node, fn)
23065 if (!node.childNodes.length) {
23068 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23069 fn.call(this, node.childNodes[i])
23075 * cleanTableWidths.
23077 * Quite often pasting from word etc.. results in tables with column and widths.
23078 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23081 cleanTableWidths : function(node)
23086 this.cleanTableWidths(this.doc.body);
23091 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23094 Roo.log(node.tagName);
23095 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23096 this.iterateChildren(node, this.cleanTableWidths);
23099 if (node.hasAttribute('width')) {
23100 node.removeAttribute('width');
23104 if (node.hasAttribute("style")) {
23107 var styles = node.getAttribute("style").split(";");
23109 Roo.each(styles, function(s) {
23110 if (!s.match(/:/)) {
23113 var kv = s.split(":");
23114 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23117 // what ever is left... we allow.
23120 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23121 if (!nstyle.length) {
23122 node.removeAttribute('style');
23126 this.iterateChildren(node, this.cleanTableWidths);
23134 domToHTML : function(currentElement, depth, nopadtext) {
23136 depth = depth || 0;
23137 nopadtext = nopadtext || false;
23139 if (!currentElement) {
23140 return this.domToHTML(this.doc.body);
23143 //Roo.log(currentElement);
23145 var allText = false;
23146 var nodeName = currentElement.nodeName;
23147 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23149 if (nodeName == '#text') {
23151 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23156 if (nodeName != 'BODY') {
23159 // Prints the node tagName, such as <A>, <IMG>, etc
23162 for(i = 0; i < currentElement.attributes.length;i++) {
23164 var aname = currentElement.attributes.item(i).name;
23165 if (!currentElement.attributes.item(i).value.length) {
23168 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23171 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23180 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23183 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23188 // Traverse the tree
23190 var currentElementChild = currentElement.childNodes.item(i);
23191 var allText = true;
23192 var innerHTML = '';
23194 while (currentElementChild) {
23195 // Formatting code (indent the tree so it looks nice on the screen)
23196 var nopad = nopadtext;
23197 if (lastnode == 'SPAN') {
23201 if (currentElementChild.nodeName == '#text') {
23202 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23203 toadd = nopadtext ? toadd : toadd.trim();
23204 if (!nopad && toadd.length > 80) {
23205 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23207 innerHTML += toadd;
23210 currentElementChild = currentElement.childNodes.item(i);
23216 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23218 // Recursively traverse the tree structure of the child node
23219 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23220 lastnode = currentElementChild.nodeName;
23222 currentElementChild=currentElement.childNodes.item(i);
23228 // The remaining code is mostly for formatting the tree
23229 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23234 ret+= "</"+tagName+">";
23240 applyBlacklists : function()
23242 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23243 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23247 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23248 if (b.indexOf(tag) > -1) {
23251 this.white.push(tag);
23255 Roo.each(w, function(tag) {
23256 if (b.indexOf(tag) > -1) {
23259 if (this.white.indexOf(tag) > -1) {
23262 this.white.push(tag);
23267 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23268 if (w.indexOf(tag) > -1) {
23271 this.black.push(tag);
23275 Roo.each(b, function(tag) {
23276 if (w.indexOf(tag) > -1) {
23279 if (this.black.indexOf(tag) > -1) {
23282 this.black.push(tag);
23287 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23288 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23292 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23293 if (b.indexOf(tag) > -1) {
23296 this.cwhite.push(tag);
23300 Roo.each(w, function(tag) {
23301 if (b.indexOf(tag) > -1) {
23304 if (this.cwhite.indexOf(tag) > -1) {
23307 this.cwhite.push(tag);
23312 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23313 if (w.indexOf(tag) > -1) {
23316 this.cblack.push(tag);
23320 Roo.each(b, function(tag) {
23321 if (w.indexOf(tag) > -1) {
23324 if (this.cblack.indexOf(tag) > -1) {
23327 this.cblack.push(tag);
23332 setStylesheets : function(stylesheets)
23334 if(typeof(stylesheets) == 'string'){
23335 Roo.get(this.iframe.contentDocument.head).createChild({
23337 rel : 'stylesheet',
23346 Roo.each(stylesheets, function(s) {
23351 Roo.get(_this.iframe.contentDocument.head).createChild({
23353 rel : 'stylesheet',
23362 removeStylesheets : function()
23366 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23371 setStyle : function(style)
23373 Roo.get(this.iframe.contentDocument.head).createChild({
23382 // hide stuff that is not compatible
23396 * @event specialkey
23400 * @cfg {String} fieldClass @hide
23403 * @cfg {String} focusClass @hide
23406 * @cfg {String} autoCreate @hide
23409 * @cfg {String} inputType @hide
23412 * @cfg {String} invalidClass @hide
23415 * @cfg {String} invalidText @hide
23418 * @cfg {String} msgFx @hide
23421 * @cfg {String} validateOnBlur @hide
23425 Roo.HtmlEditorCore.white = [
23426 'area', 'br', 'img', 'input', 'hr', 'wbr',
23428 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23429 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23430 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23431 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23432 'table', 'ul', 'xmp',
23434 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23437 'dir', 'menu', 'ol', 'ul', 'dl',
23443 Roo.HtmlEditorCore.black = [
23444 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23446 'base', 'basefont', 'bgsound', 'blink', 'body',
23447 'frame', 'frameset', 'head', 'html', 'ilayer',
23448 'iframe', 'layer', 'link', 'meta', 'object',
23449 'script', 'style' ,'title', 'xml' // clean later..
23451 Roo.HtmlEditorCore.clean = [
23452 'script', 'style', 'title', 'xml'
23454 Roo.HtmlEditorCore.remove = [
23459 Roo.HtmlEditorCore.ablack = [
23463 Roo.HtmlEditorCore.aclean = [
23464 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23468 Roo.HtmlEditorCore.pwhite= [
23469 'http', 'https', 'mailto'
23472 // white listed style attributes.
23473 Roo.HtmlEditorCore.cwhite= [
23474 // 'text-align', /// default is to allow most things..
23480 // black listed style attributes.
23481 Roo.HtmlEditorCore.cblack= [
23482 // 'font-size' -- this can be set by the project
23486 Roo.HtmlEditorCore.swapCodes =[
23505 * @class Roo.bootstrap.HtmlEditor
23506 * @extends Roo.bootstrap.TextArea
23507 * Bootstrap HtmlEditor class
23510 * Create a new HtmlEditor
23511 * @param {Object} config The config object
23514 Roo.bootstrap.HtmlEditor = function(config){
23515 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23516 if (!this.toolbars) {
23517 this.toolbars = [];
23520 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23523 * @event initialize
23524 * Fires when the editor is fully initialized (including the iframe)
23525 * @param {HtmlEditor} this
23530 * Fires when the editor is first receives the focus. Any insertion must wait
23531 * until after this event.
23532 * @param {HtmlEditor} this
23536 * @event beforesync
23537 * Fires before the textarea is updated with content from the editor iframe. Return false
23538 * to cancel the sync.
23539 * @param {HtmlEditor} this
23540 * @param {String} html
23544 * @event beforepush
23545 * Fires before the iframe editor is updated with content from the textarea. Return false
23546 * to cancel the push.
23547 * @param {HtmlEditor} this
23548 * @param {String} html
23553 * Fires when the textarea is updated with content from the editor iframe.
23554 * @param {HtmlEditor} this
23555 * @param {String} html
23560 * Fires when the iframe editor is updated with content from the textarea.
23561 * @param {HtmlEditor} this
23562 * @param {String} html
23566 * @event editmodechange
23567 * Fires when the editor switches edit modes
23568 * @param {HtmlEditor} this
23569 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23571 editmodechange: true,
23573 * @event editorevent
23574 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23575 * @param {HtmlEditor} this
23579 * @event firstfocus
23580 * Fires when on first focus - needed by toolbars..
23581 * @param {HtmlEditor} this
23586 * Auto save the htmlEditor value as a file into Events
23587 * @param {HtmlEditor} this
23591 * @event savedpreview
23592 * preview the saved version of htmlEditor
23593 * @param {HtmlEditor} this
23600 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23604 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23609 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23614 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23619 * @cfg {Number} height (in pixels)
23623 * @cfg {Number} width (in pixels)
23628 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23631 stylesheets: false,
23636 // private properties
23637 validationEvent : false,
23639 initialized : false,
23642 onFocus : Roo.emptyFn,
23644 hideMode:'offsets',
23646 tbContainer : false,
23650 toolbarContainer :function() {
23651 return this.wrap.select('.x-html-editor-tb',true).first();
23655 * Protected method that will not generally be called directly. It
23656 * is called when the editor creates its toolbar. Override this method if you need to
23657 * add custom toolbar buttons.
23658 * @param {HtmlEditor} editor
23660 createToolbar : function(){
23661 Roo.log('renewing');
23662 Roo.log("create toolbars");
23664 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23665 this.toolbars[0].render(this.toolbarContainer());
23669 // if (!editor.toolbars || !editor.toolbars.length) {
23670 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23673 // for (var i =0 ; i < editor.toolbars.length;i++) {
23674 // editor.toolbars[i] = Roo.factory(
23675 // typeof(editor.toolbars[i]) == 'string' ?
23676 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23677 // Roo.bootstrap.HtmlEditor);
23678 // editor.toolbars[i].init(editor);
23684 onRender : function(ct, position)
23686 // Roo.log("Call onRender: " + this.xtype);
23688 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23690 this.wrap = this.inputEl().wrap({
23691 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23694 this.editorcore.onRender(ct, position);
23696 if (this.resizable) {
23697 this.resizeEl = new Roo.Resizable(this.wrap, {
23701 minHeight : this.height,
23702 height: this.height,
23703 handles : this.resizable,
23706 resize : function(r, w, h) {
23707 _t.onResize(w,h); // -something
23713 this.createToolbar(this);
23716 if(!this.width && this.resizable){
23717 this.setSize(this.wrap.getSize());
23719 if (this.resizeEl) {
23720 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23721 // should trigger onReize..
23727 onResize : function(w, h)
23729 Roo.log('resize: ' +w + ',' + h );
23730 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23734 if(this.inputEl() ){
23735 if(typeof w == 'number'){
23736 var aw = w - this.wrap.getFrameWidth('lr');
23737 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23740 if(typeof h == 'number'){
23741 var tbh = -11; // fixme it needs to tool bar size!
23742 for (var i =0; i < this.toolbars.length;i++) {
23743 // fixme - ask toolbars for heights?
23744 tbh += this.toolbars[i].el.getHeight();
23745 //if (this.toolbars[i].footer) {
23746 // tbh += this.toolbars[i].footer.el.getHeight();
23754 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23755 ah -= 5; // knock a few pixes off for look..
23756 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23760 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23761 this.editorcore.onResize(ew,eh);
23766 * Toggles the editor between standard and source edit mode.
23767 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23769 toggleSourceEdit : function(sourceEditMode)
23771 this.editorcore.toggleSourceEdit(sourceEditMode);
23773 if(this.editorcore.sourceEditMode){
23774 Roo.log('editor - showing textarea');
23777 // Roo.log(this.syncValue());
23779 this.inputEl().removeClass(['hide', 'x-hidden']);
23780 this.inputEl().dom.removeAttribute('tabIndex');
23781 this.inputEl().focus();
23783 Roo.log('editor - hiding textarea');
23785 // Roo.log(this.pushValue());
23788 this.inputEl().addClass(['hide', 'x-hidden']);
23789 this.inputEl().dom.setAttribute('tabIndex', -1);
23790 //this.deferFocus();
23793 if(this.resizable){
23794 this.setSize(this.wrap.getSize());
23797 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23800 // private (for BoxComponent)
23801 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23803 // private (for BoxComponent)
23804 getResizeEl : function(){
23808 // private (for BoxComponent)
23809 getPositionEl : function(){
23814 initEvents : function(){
23815 this.originalValue = this.getValue();
23819 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23822 // markInvalid : Roo.emptyFn,
23824 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23827 // clearInvalid : Roo.emptyFn,
23829 setValue : function(v){
23830 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23831 this.editorcore.pushValue();
23836 deferFocus : function(){
23837 this.focus.defer(10, this);
23841 focus : function(){
23842 this.editorcore.focus();
23848 onDestroy : function(){
23854 for (var i =0; i < this.toolbars.length;i++) {
23855 // fixme - ask toolbars for heights?
23856 this.toolbars[i].onDestroy();
23859 this.wrap.dom.innerHTML = '';
23860 this.wrap.remove();
23865 onFirstFocus : function(){
23866 //Roo.log("onFirstFocus");
23867 this.editorcore.onFirstFocus();
23868 for (var i =0; i < this.toolbars.length;i++) {
23869 this.toolbars[i].onFirstFocus();
23875 syncValue : function()
23877 this.editorcore.syncValue();
23880 pushValue : function()
23882 this.editorcore.pushValue();
23886 // hide stuff that is not compatible
23900 * @event specialkey
23904 * @cfg {String} fieldClass @hide
23907 * @cfg {String} focusClass @hide
23910 * @cfg {String} autoCreate @hide
23913 * @cfg {String} inputType @hide
23916 * @cfg {String} invalidClass @hide
23919 * @cfg {String} invalidText @hide
23922 * @cfg {String} msgFx @hide
23925 * @cfg {String} validateOnBlur @hide
23934 Roo.namespace('Roo.bootstrap.htmleditor');
23936 * @class Roo.bootstrap.HtmlEditorToolbar1
23941 new Roo.bootstrap.HtmlEditor({
23944 new Roo.bootstrap.HtmlEditorToolbar1({
23945 disable : { fonts: 1 , format: 1, ..., ... , ...],
23951 * @cfg {Object} disable List of elements to disable..
23952 * @cfg {Array} btns List of additional buttons.
23956 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23959 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23962 Roo.apply(this, config);
23964 // default disabled, based on 'good practice'..
23965 this.disable = this.disable || {};
23966 Roo.applyIf(this.disable, {
23969 specialElements : true
23971 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23973 this.editor = config.editor;
23974 this.editorcore = config.editor.editorcore;
23976 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23978 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23979 // dont call parent... till later.
23981 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23986 editorcore : false,
23991 "h1","h2","h3","h4","h5","h6",
23993 "abbr", "acronym", "address", "cite", "samp", "var",
23997 onRender : function(ct, position)
23999 // Roo.log("Call onRender: " + this.xtype);
24001 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24003 this.el.dom.style.marginBottom = '0';
24005 var editorcore = this.editorcore;
24006 var editor= this.editor;
24009 var btn = function(id,cmd , toggle, handler, html){
24011 var event = toggle ? 'toggle' : 'click';
24016 xns: Roo.bootstrap,
24020 enableToggle:toggle !== false,
24022 pressed : toggle ? false : null,
24025 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24026 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24032 // var cb_box = function...
24037 xns: Roo.bootstrap,
24042 xns: Roo.bootstrap,
24046 Roo.each(this.formats, function(f) {
24047 style.menu.items.push({
24049 xns: Roo.bootstrap,
24050 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24055 editorcore.insertTag(this.tagname);
24062 children.push(style);
24064 btn('bold',false,true);
24065 btn('italic',false,true);
24066 btn('align-left', 'justifyleft',true);
24067 btn('align-center', 'justifycenter',true);
24068 btn('align-right' , 'justifyright',true);
24069 btn('link', false, false, function(btn) {
24070 //Roo.log("create link?");
24071 var url = prompt(this.createLinkText, this.defaultLinkValue);
24072 if(url && url != 'http:/'+'/'){
24073 this.editorcore.relayCmd('createlink', url);
24076 btn('list','insertunorderedlist',true);
24077 btn('pencil', false,true, function(btn){
24079 this.toggleSourceEdit(btn.pressed);
24082 if (this.editor.btns.length > 0) {
24083 for (var i = 0; i<this.editor.btns.length; i++) {
24084 children.push(this.editor.btns[i]);
24092 xns: Roo.bootstrap,
24097 xns: Roo.bootstrap,
24102 cog.menu.items.push({
24104 xns: Roo.bootstrap,
24105 html : Clean styles,
24110 editorcore.insertTag(this.tagname);
24119 this.xtype = 'NavSimplebar';
24121 for(var i=0;i< children.length;i++) {
24123 this.buttons.add(this.addxtypeChild(children[i]));
24127 editor.on('editorevent', this.updateToolbar, this);
24129 onBtnClick : function(id)
24131 this.editorcore.relayCmd(id);
24132 this.editorcore.focus();
24136 * Protected method that will not generally be called directly. It triggers
24137 * a toolbar update by reading the markup state of the current selection in the editor.
24139 updateToolbar: function(){
24141 if(!this.editorcore.activated){
24142 this.editor.onFirstFocus(); // is this neeed?
24146 var btns = this.buttons;
24147 var doc = this.editorcore.doc;
24148 btns.get('bold').setActive(doc.queryCommandState('bold'));
24149 btns.get('italic').setActive(doc.queryCommandState('italic'));
24150 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24152 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24153 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24154 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24156 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24157 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24160 var ans = this.editorcore.getAllAncestors();
24161 if (this.formatCombo) {
24164 var store = this.formatCombo.store;
24165 this.formatCombo.setValue("");
24166 for (var i =0; i < ans.length;i++) {
24167 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24169 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24177 // hides menus... - so this cant be on a menu...
24178 Roo.bootstrap.MenuMgr.hideAll();
24180 Roo.bootstrap.MenuMgr.hideAll();
24181 //this.editorsyncValue();
24183 onFirstFocus: function() {
24184 this.buttons.each(function(item){
24188 toggleSourceEdit : function(sourceEditMode){
24191 if(sourceEditMode){
24192 Roo.log("disabling buttons");
24193 this.buttons.each( function(item){
24194 if(item.cmd != 'pencil'){
24200 Roo.log("enabling buttons");
24201 if(this.editorcore.initialized){
24202 this.buttons.each( function(item){
24208 Roo.log("calling toggole on editor");
24209 // tell the editor that it's been pressed..
24210 this.editor.toggleSourceEdit(sourceEditMode);
24220 * @class Roo.bootstrap.Table.AbstractSelectionModel
24221 * @extends Roo.util.Observable
24222 * Abstract base class for grid SelectionModels. It provides the interface that should be
24223 * implemented by descendant classes. This class should not be directly instantiated.
24226 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24227 this.locked = false;
24228 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24232 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24233 /** @ignore Called by the grid automatically. Do not call directly. */
24234 init : function(grid){
24240 * Locks the selections.
24243 this.locked = true;
24247 * Unlocks the selections.
24249 unlock : function(){
24250 this.locked = false;
24254 * Returns true if the selections are locked.
24255 * @return {Boolean}
24257 isLocked : function(){
24258 return this.locked;
24262 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24263 * @class Roo.bootstrap.Table.RowSelectionModel
24264 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24265 * It supports multiple selections and keyboard selection/navigation.
24267 * @param {Object} config
24270 Roo.bootstrap.Table.RowSelectionModel = function(config){
24271 Roo.apply(this, config);
24272 this.selections = new Roo.util.MixedCollection(false, function(o){
24277 this.lastActive = false;
24281 * @event selectionchange
24282 * Fires when the selection changes
24283 * @param {SelectionModel} this
24285 "selectionchange" : true,
24287 * @event afterselectionchange
24288 * Fires after the selection changes (eg. by key press or clicking)
24289 * @param {SelectionModel} this
24291 "afterselectionchange" : true,
24293 * @event beforerowselect
24294 * Fires when a row is selected being selected, return false to cancel.
24295 * @param {SelectionModel} this
24296 * @param {Number} rowIndex The selected index
24297 * @param {Boolean} keepExisting False if other selections will be cleared
24299 "beforerowselect" : true,
24302 * Fires when a row is selected.
24303 * @param {SelectionModel} this
24304 * @param {Number} rowIndex The selected index
24305 * @param {Roo.data.Record} r The record
24307 "rowselect" : true,
24309 * @event rowdeselect
24310 * Fires when a row is deselected.
24311 * @param {SelectionModel} this
24312 * @param {Number} rowIndex The selected index
24314 "rowdeselect" : true
24316 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24317 this.locked = false;
24320 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24322 * @cfg {Boolean} singleSelect
24323 * True to allow selection of only one row at a time (defaults to false)
24325 singleSelect : false,
24328 initEvents : function()
24331 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24332 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24333 //}else{ // allow click to work like normal
24334 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24336 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24337 this.grid.on("rowclick", this.handleMouseDown, this);
24339 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24340 "up" : function(e){
24342 this.selectPrevious(e.shiftKey);
24343 }else if(this.last !== false && this.lastActive !== false){
24344 var last = this.last;
24345 this.selectRange(this.last, this.lastActive-1);
24346 this.grid.getView().focusRow(this.lastActive);
24347 if(last !== false){
24351 this.selectFirstRow();
24353 this.fireEvent("afterselectionchange", this);
24355 "down" : function(e){
24357 this.selectNext(e.shiftKey);
24358 }else if(this.last !== false && this.lastActive !== false){
24359 var last = this.last;
24360 this.selectRange(this.last, this.lastActive+1);
24361 this.grid.getView().focusRow(this.lastActive);
24362 if(last !== false){
24366 this.selectFirstRow();
24368 this.fireEvent("afterselectionchange", this);
24372 this.grid.store.on('load', function(){
24373 this.selections.clear();
24376 var view = this.grid.view;
24377 view.on("refresh", this.onRefresh, this);
24378 view.on("rowupdated", this.onRowUpdated, this);
24379 view.on("rowremoved", this.onRemove, this);
24384 onRefresh : function()
24386 var ds = this.grid.store, i, v = this.grid.view;
24387 var s = this.selections;
24388 s.each(function(r){
24389 if((i = ds.indexOfId(r.id)) != -1){
24398 onRemove : function(v, index, r){
24399 this.selections.remove(r);
24403 onRowUpdated : function(v, index, r){
24404 if(this.isSelected(r)){
24405 v.onRowSelect(index);
24411 * @param {Array} records The records to select
24412 * @param {Boolean} keepExisting (optional) True to keep existing selections
24414 selectRecords : function(records, keepExisting)
24417 this.clearSelections();
24419 var ds = this.grid.store;
24420 for(var i = 0, len = records.length; i < len; i++){
24421 this.selectRow(ds.indexOf(records[i]), true);
24426 * Gets the number of selected rows.
24429 getCount : function(){
24430 return this.selections.length;
24434 * Selects the first row in the grid.
24436 selectFirstRow : function(){
24441 * Select the last row.
24442 * @param {Boolean} keepExisting (optional) True to keep existing selections
24444 selectLastRow : function(keepExisting){
24445 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24446 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24450 * Selects the row immediately following the last selected row.
24451 * @param {Boolean} keepExisting (optional) True to keep existing selections
24453 selectNext : function(keepExisting)
24455 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24456 this.selectRow(this.last+1, keepExisting);
24457 this.grid.getView().focusRow(this.last);
24462 * Selects the row that precedes the last selected row.
24463 * @param {Boolean} keepExisting (optional) True to keep existing selections
24465 selectPrevious : function(keepExisting){
24467 this.selectRow(this.last-1, keepExisting);
24468 this.grid.getView().focusRow(this.last);
24473 * Returns the selected records
24474 * @return {Array} Array of selected records
24476 getSelections : function(){
24477 return [].concat(this.selections.items);
24481 * Returns the first selected record.
24484 getSelected : function(){
24485 return this.selections.itemAt(0);
24490 * Clears all selections.
24492 clearSelections : function(fast)
24498 var ds = this.grid.store;
24499 var s = this.selections;
24500 s.each(function(r){
24501 this.deselectRow(ds.indexOfId(r.id));
24505 this.selections.clear();
24512 * Selects all rows.
24514 selectAll : function(){
24518 this.selections.clear();
24519 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24520 this.selectRow(i, true);
24525 * Returns True if there is a selection.
24526 * @return {Boolean}
24528 hasSelection : function(){
24529 return this.selections.length > 0;
24533 * Returns True if the specified row is selected.
24534 * @param {Number/Record} record The record or index of the record to check
24535 * @return {Boolean}
24537 isSelected : function(index){
24538 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24539 return (r && this.selections.key(r.id) ? true : false);
24543 * Returns True if the specified record id is selected.
24544 * @param {String} id The id of record to check
24545 * @return {Boolean}
24547 isIdSelected : function(id){
24548 return (this.selections.key(id) ? true : false);
24553 handleMouseDBClick : function(e, t){
24557 handleMouseDown : function(e, t)
24559 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24560 if(this.isLocked() || rowIndex < 0 ){
24563 if(e.shiftKey && this.last !== false){
24564 var last = this.last;
24565 this.selectRange(last, rowIndex, e.ctrlKey);
24566 this.last = last; // reset the last
24570 var isSelected = this.isSelected(rowIndex);
24571 //Roo.log("select row:" + rowIndex);
24573 this.deselectRow(rowIndex);
24575 this.selectRow(rowIndex, true);
24579 if(e.button !== 0 && isSelected){
24580 alert('rowIndex 2: ' + rowIndex);
24581 view.focusRow(rowIndex);
24582 }else if(e.ctrlKey && isSelected){
24583 this.deselectRow(rowIndex);
24584 }else if(!isSelected){
24585 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24586 view.focusRow(rowIndex);
24590 this.fireEvent("afterselectionchange", this);
24593 handleDragableRowClick : function(grid, rowIndex, e)
24595 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24596 this.selectRow(rowIndex, false);
24597 grid.view.focusRow(rowIndex);
24598 this.fireEvent("afterselectionchange", this);
24603 * Selects multiple rows.
24604 * @param {Array} rows Array of the indexes of the row to select
24605 * @param {Boolean} keepExisting (optional) True to keep existing selections
24607 selectRows : function(rows, keepExisting){
24609 this.clearSelections();
24611 for(var i = 0, len = rows.length; i < len; i++){
24612 this.selectRow(rows[i], true);
24617 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24618 * @param {Number} startRow The index of the first row in the range
24619 * @param {Number} endRow The index of the last row in the range
24620 * @param {Boolean} keepExisting (optional) True to retain existing selections
24622 selectRange : function(startRow, endRow, keepExisting){
24627 this.clearSelections();
24629 if(startRow <= endRow){
24630 for(var i = startRow; i <= endRow; i++){
24631 this.selectRow(i, true);
24634 for(var i = startRow; i >= endRow; i--){
24635 this.selectRow(i, true);
24641 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24642 * @param {Number} startRow The index of the first row in the range
24643 * @param {Number} endRow The index of the last row in the range
24645 deselectRange : function(startRow, endRow, preventViewNotify){
24649 for(var i = startRow; i <= endRow; i++){
24650 this.deselectRow(i, preventViewNotify);
24656 * @param {Number} row The index of the row to select
24657 * @param {Boolean} keepExisting (optional) True to keep existing selections
24659 selectRow : function(index, keepExisting, preventViewNotify)
24661 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24664 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24665 if(!keepExisting || this.singleSelect){
24666 this.clearSelections();
24669 var r = this.grid.store.getAt(index);
24670 //console.log('selectRow - record id :' + r.id);
24672 this.selections.add(r);
24673 this.last = this.lastActive = index;
24674 if(!preventViewNotify){
24675 var proxy = new Roo.Element(
24676 this.grid.getRowDom(index)
24678 proxy.addClass('bg-info info');
24680 this.fireEvent("rowselect", this, index, r);
24681 this.fireEvent("selectionchange", this);
24687 * @param {Number} row The index of the row to deselect
24689 deselectRow : function(index, preventViewNotify)
24694 if(this.last == index){
24697 if(this.lastActive == index){
24698 this.lastActive = false;
24701 var r = this.grid.store.getAt(index);
24706 this.selections.remove(r);
24707 //.console.log('deselectRow - record id :' + r.id);
24708 if(!preventViewNotify){
24710 var proxy = new Roo.Element(
24711 this.grid.getRowDom(index)
24713 proxy.removeClass('bg-info info');
24715 this.fireEvent("rowdeselect", this, index);
24716 this.fireEvent("selectionchange", this);
24720 restoreLast : function(){
24722 this.last = this._last;
24727 acceptsNav : function(row, col, cm){
24728 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24732 onEditorKey : function(field, e){
24733 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24738 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24740 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24742 }else if(k == e.ENTER && !e.ctrlKey){
24746 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24748 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24750 }else if(k == e.ESC){
24754 g.startEditing(newCell[0], newCell[1]);
24760 * Ext JS Library 1.1.1
24761 * Copyright(c) 2006-2007, Ext JS, LLC.
24763 * Originally Released Under LGPL - original licence link has changed is not relivant.
24766 * <script type="text/javascript">
24770 * @class Roo.bootstrap.PagingToolbar
24771 * @extends Roo.bootstrap.NavSimplebar
24772 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24774 * Create a new PagingToolbar
24775 * @param {Object} config The config object
24776 * @param {Roo.data.Store} store
24778 Roo.bootstrap.PagingToolbar = function(config)
24780 // old args format still supported... - xtype is prefered..
24781 // created from xtype...
24783 this.ds = config.dataSource;
24785 if (config.store && !this.ds) {
24786 this.store= Roo.factory(config.store, Roo.data);
24787 this.ds = this.store;
24788 this.ds.xmodule = this.xmodule || false;
24791 this.toolbarItems = [];
24792 if (config.items) {
24793 this.toolbarItems = config.items;
24796 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24801 this.bind(this.ds);
24804 if (Roo.bootstrap.version == 4) {
24805 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24807 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24812 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24814 * @cfg {Roo.data.Store} dataSource
24815 * The underlying data store providing the paged data
24818 * @cfg {String/HTMLElement/Element} container
24819 * container The id or element that will contain the toolbar
24822 * @cfg {Boolean} displayInfo
24823 * True to display the displayMsg (defaults to false)
24826 * @cfg {Number} pageSize
24827 * The number of records to display per page (defaults to 20)
24831 * @cfg {String} displayMsg
24832 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24834 displayMsg : 'Displaying {0} - {1} of {2}',
24836 * @cfg {String} emptyMsg
24837 * The message to display when no records are found (defaults to "No data to display")
24839 emptyMsg : 'No data to display',
24841 * Customizable piece of the default paging text (defaults to "Page")
24844 beforePageText : "Page",
24846 * Customizable piece of the default paging text (defaults to "of %0")
24849 afterPageText : "of {0}",
24851 * Customizable piece of the default paging text (defaults to "First Page")
24854 firstText : "First Page",
24856 * Customizable piece of the default paging text (defaults to "Previous Page")
24859 prevText : "Previous Page",
24861 * Customizable piece of the default paging text (defaults to "Next Page")
24864 nextText : "Next Page",
24866 * Customizable piece of the default paging text (defaults to "Last Page")
24869 lastText : "Last Page",
24871 * Customizable piece of the default paging text (defaults to "Refresh")
24874 refreshText : "Refresh",
24878 onRender : function(ct, position)
24880 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24881 this.navgroup.parentId = this.id;
24882 this.navgroup.onRender(this.el, null);
24883 // add the buttons to the navgroup
24885 if(this.displayInfo){
24886 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24887 this.displayEl = this.el.select('.x-paging-info', true).first();
24888 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24889 // this.displayEl = navel.el.select('span',true).first();
24895 Roo.each(_this.buttons, function(e){ // this might need to use render????
24896 Roo.factory(e).render(_this.el);
24900 Roo.each(_this.toolbarItems, function(e) {
24901 _this.navgroup.addItem(e);
24905 this.first = this.navgroup.addItem({
24906 tooltip: this.firstText,
24907 cls: "prev btn-outline-secondary",
24908 html : ' <i class="fa fa-step-backward"></i>',
24910 preventDefault: true,
24911 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24914 this.prev = this.navgroup.addItem({
24915 tooltip: this.prevText,
24916 cls: "prev btn-outline-secondary",
24917 html : ' <i class="fa fa-backward"></i>',
24919 preventDefault: true,
24920 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24922 //this.addSeparator();
24925 var field = this.navgroup.addItem( {
24927 cls : 'x-paging-position btn-outline-secondary',
24929 html : this.beforePageText +
24930 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24931 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24934 this.field = field.el.select('input', true).first();
24935 this.field.on("keydown", this.onPagingKeydown, this);
24936 this.field.on("focus", function(){this.dom.select();});
24939 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24940 //this.field.setHeight(18);
24941 //this.addSeparator();
24942 this.next = this.navgroup.addItem({
24943 tooltip: this.nextText,
24944 cls: "next btn-outline-secondary",
24945 html : ' <i class="fa fa-forward"></i>',
24947 preventDefault: true,
24948 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24950 this.last = this.navgroup.addItem({
24951 tooltip: this.lastText,
24952 html : ' <i class="fa fa-step-forward"></i>',
24953 cls: "next btn-outline-secondary",
24955 preventDefault: true,
24956 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24958 //this.addSeparator();
24959 this.loading = this.navgroup.addItem({
24960 tooltip: this.refreshText,
24961 cls: "btn-outline-secondary",
24962 html : ' <i class="fa fa-refresh"></i>',
24963 preventDefault: true,
24964 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24970 updateInfo : function(){
24971 if(this.displayEl){
24972 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24973 var msg = count == 0 ?
24977 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24979 this.displayEl.update(msg);
24984 onLoad : function(ds, r, o)
24986 this.cursor = o.params.start ? o.params.start : 0;
24988 var d = this.getPageData(),
24993 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24994 this.field.dom.value = ap;
24995 this.first.setDisabled(ap == 1);
24996 this.prev.setDisabled(ap == 1);
24997 this.next.setDisabled(ap == ps);
24998 this.last.setDisabled(ap == ps);
24999 this.loading.enable();
25004 getPageData : function(){
25005 var total = this.ds.getTotalCount();
25008 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25009 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25014 onLoadError : function(){
25015 this.loading.enable();
25019 onPagingKeydown : function(e){
25020 var k = e.getKey();
25021 var d = this.getPageData();
25023 var v = this.field.dom.value, pageNum;
25024 if(!v || isNaN(pageNum = parseInt(v, 10))){
25025 this.field.dom.value = d.activePage;
25028 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25029 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25032 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))
25034 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25035 this.field.dom.value = pageNum;
25036 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25039 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25041 var v = this.field.dom.value, pageNum;
25042 var increment = (e.shiftKey) ? 10 : 1;
25043 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25046 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25047 this.field.dom.value = d.activePage;
25050 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25052 this.field.dom.value = parseInt(v, 10) + increment;
25053 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25054 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25061 beforeLoad : function(){
25063 this.loading.disable();
25068 onClick : function(which){
25077 ds.load({params:{start: 0, limit: this.pageSize}});
25080 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25083 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25086 var total = ds.getTotalCount();
25087 var extra = total % this.pageSize;
25088 var lastStart = extra ? (total - extra) : total-this.pageSize;
25089 ds.load({params:{start: lastStart, limit: this.pageSize}});
25092 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25098 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25099 * @param {Roo.data.Store} store The data store to unbind
25101 unbind : function(ds){
25102 ds.un("beforeload", this.beforeLoad, this);
25103 ds.un("load", this.onLoad, this);
25104 ds.un("loadexception", this.onLoadError, this);
25105 ds.un("remove", this.updateInfo, this);
25106 ds.un("add", this.updateInfo, this);
25107 this.ds = undefined;
25111 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25112 * @param {Roo.data.Store} store The data store to bind
25114 bind : function(ds){
25115 ds.on("beforeload", this.beforeLoad, this);
25116 ds.on("load", this.onLoad, this);
25117 ds.on("loadexception", this.onLoadError, this);
25118 ds.on("remove", this.updateInfo, this);
25119 ds.on("add", this.updateInfo, this);
25130 * @class Roo.bootstrap.MessageBar
25131 * @extends Roo.bootstrap.Component
25132 * Bootstrap MessageBar class
25133 * @cfg {String} html contents of the MessageBar
25134 * @cfg {String} weight (info | success | warning | danger) default info
25135 * @cfg {String} beforeClass insert the bar before the given class
25136 * @cfg {Boolean} closable (true | false) default false
25137 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25140 * Create a new Element
25141 * @param {Object} config The config object
25144 Roo.bootstrap.MessageBar = function(config){
25145 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25148 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25154 beforeClass: 'bootstrap-sticky-wrap',
25156 getAutoCreate : function(){
25160 cls: 'alert alert-dismissable alert-' + this.weight,
25165 html: this.html || ''
25171 cfg.cls += ' alert-messages-fixed';
25185 onRender : function(ct, position)
25187 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25190 var cfg = Roo.apply({}, this.getAutoCreate());
25194 cfg.cls += ' ' + this.cls;
25197 cfg.style = this.style;
25199 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25201 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25204 this.el.select('>button.close').on('click', this.hide, this);
25210 if (!this.rendered) {
25216 this.fireEvent('show', this);
25222 if (!this.rendered) {
25228 this.fireEvent('hide', this);
25231 update : function()
25233 // var e = this.el.dom.firstChild;
25235 // if(this.closable){
25236 // e = e.nextSibling;
25239 // e.data = this.html || '';
25241 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25257 * @class Roo.bootstrap.Graph
25258 * @extends Roo.bootstrap.Component
25259 * Bootstrap Graph class
25263 @cfg {String} graphtype bar | vbar | pie
25264 @cfg {number} g_x coodinator | centre x (pie)
25265 @cfg {number} g_y coodinator | centre y (pie)
25266 @cfg {number} g_r radius (pie)
25267 @cfg {number} g_height height of the chart (respected by all elements in the set)
25268 @cfg {number} g_width width of the chart (respected by all elements in the set)
25269 @cfg {Object} title The title of the chart
25272 -opts (object) options for the chart
25274 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25275 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25277 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.
25278 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25280 o stretch (boolean)
25282 -opts (object) options for the pie
25285 o startAngle (number)
25286 o endAngle (number)
25290 * Create a new Input
25291 * @param {Object} config The config object
25294 Roo.bootstrap.Graph = function(config){
25295 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25301 * The img click event for the img.
25302 * @param {Roo.EventObject} e
25308 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25319 //g_colors: this.colors,
25326 getAutoCreate : function(){
25337 onRender : function(ct,position){
25340 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25342 if (typeof(Raphael) == 'undefined') {
25343 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25347 this.raphael = Raphael(this.el.dom);
25349 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25350 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25351 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25352 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25354 r.text(160, 10, "Single Series Chart").attr(txtattr);
25355 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25356 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25357 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25359 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25360 r.barchart(330, 10, 300, 220, data1);
25361 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25362 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25365 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25366 // r.barchart(30, 30, 560, 250, xdata, {
25367 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25368 // axis : "0 0 1 1",
25369 // axisxlabels : xdata
25370 // //yvalues : cols,
25373 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25375 // this.load(null,xdata,{
25376 // axis : "0 0 1 1",
25377 // axisxlabels : xdata
25382 load : function(graphtype,xdata,opts)
25384 this.raphael.clear();
25386 graphtype = this.graphtype;
25391 var r = this.raphael,
25392 fin = function () {
25393 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25395 fout = function () {
25396 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25398 pfin = function() {
25399 this.sector.stop();
25400 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25403 this.label[0].stop();
25404 this.label[0].attr({ r: 7.5 });
25405 this.label[1].attr({ "font-weight": 800 });
25408 pfout = function() {
25409 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25412 this.label[0].animate({ r: 5 }, 500, "bounce");
25413 this.label[1].attr({ "font-weight": 400 });
25419 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25422 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25425 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25426 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25428 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25435 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25440 setTitle: function(o)
25445 initEvents: function() {
25448 this.el.on('click', this.onClick, this);
25452 onClick : function(e)
25454 Roo.log('img onclick');
25455 this.fireEvent('click', this, e);
25467 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25470 * @class Roo.bootstrap.dash.NumberBox
25471 * @extends Roo.bootstrap.Component
25472 * Bootstrap NumberBox class
25473 * @cfg {String} headline Box headline
25474 * @cfg {String} content Box content
25475 * @cfg {String} icon Box icon
25476 * @cfg {String} footer Footer text
25477 * @cfg {String} fhref Footer href
25480 * Create a new NumberBox
25481 * @param {Object} config The config object
25485 Roo.bootstrap.dash.NumberBox = function(config){
25486 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25490 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25499 getAutoCreate : function(){
25503 cls : 'small-box ',
25511 cls : 'roo-headline',
25512 html : this.headline
25516 cls : 'roo-content',
25517 html : this.content
25531 cls : 'ion ' + this.icon
25540 cls : 'small-box-footer',
25541 href : this.fhref || '#',
25545 cfg.cn.push(footer);
25552 onRender : function(ct,position){
25553 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25560 setHeadline: function (value)
25562 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25565 setFooter: function (value, href)
25567 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25570 this.el.select('a.small-box-footer',true).first().attr('href', href);
25575 setContent: function (value)
25577 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25580 initEvents: function()
25594 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25597 * @class Roo.bootstrap.dash.TabBox
25598 * @extends Roo.bootstrap.Component
25599 * Bootstrap TabBox class
25600 * @cfg {String} title Title of the TabBox
25601 * @cfg {String} icon Icon of the TabBox
25602 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25603 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25606 * Create a new TabBox
25607 * @param {Object} config The config object
25611 Roo.bootstrap.dash.TabBox = function(config){
25612 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25617 * When a pane is added
25618 * @param {Roo.bootstrap.dash.TabPane} pane
25622 * @event activatepane
25623 * When a pane is activated
25624 * @param {Roo.bootstrap.dash.TabPane} pane
25626 "activatepane" : true
25634 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25639 tabScrollable : false,
25641 getChildContainer : function()
25643 return this.el.select('.tab-content', true).first();
25646 getAutoCreate : function(){
25650 cls: 'pull-left header',
25658 cls: 'fa ' + this.icon
25664 cls: 'nav nav-tabs pull-right',
25670 if(this.tabScrollable){
25677 cls: 'nav nav-tabs pull-right',
25688 cls: 'nav-tabs-custom',
25693 cls: 'tab-content no-padding',
25701 initEvents : function()
25703 //Roo.log('add add pane handler');
25704 this.on('addpane', this.onAddPane, this);
25707 * Updates the box title
25708 * @param {String} html to set the title to.
25710 setTitle : function(value)
25712 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25714 onAddPane : function(pane)
25716 this.panes.push(pane);
25717 //Roo.log('addpane');
25719 // tabs are rendere left to right..
25720 if(!this.showtabs){
25724 var ctr = this.el.select('.nav-tabs', true).first();
25727 var existing = ctr.select('.nav-tab',true);
25728 var qty = existing.getCount();;
25731 var tab = ctr.createChild({
25733 cls : 'nav-tab' + (qty ? '' : ' active'),
25741 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25744 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25746 pane.el.addClass('active');
25751 onTabClick : function(ev,un,ob,pane)
25753 //Roo.log('tab - prev default');
25754 ev.preventDefault();
25757 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25758 pane.tab.addClass('active');
25759 //Roo.log(pane.title);
25760 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25761 // technically we should have a deactivate event.. but maybe add later.
25762 // and it should not de-activate the selected tab...
25763 this.fireEvent('activatepane', pane);
25764 pane.el.addClass('active');
25765 pane.fireEvent('activate');
25770 getActivePane : function()
25773 Roo.each(this.panes, function(p) {
25774 if(p.el.hasClass('active')){
25795 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25797 * @class Roo.bootstrap.TabPane
25798 * @extends Roo.bootstrap.Component
25799 * Bootstrap TabPane class
25800 * @cfg {Boolean} active (false | true) Default false
25801 * @cfg {String} title title of panel
25805 * Create a new TabPane
25806 * @param {Object} config The config object
25809 Roo.bootstrap.dash.TabPane = function(config){
25810 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25816 * When a pane is activated
25817 * @param {Roo.bootstrap.dash.TabPane} pane
25824 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25829 // the tabBox that this is attached to.
25832 getAutoCreate : function()
25840 cfg.cls += ' active';
25845 initEvents : function()
25847 //Roo.log('trigger add pane handler');
25848 this.parent().fireEvent('addpane', this)
25852 * Updates the tab title
25853 * @param {String} html to set the title to.
25855 setTitle: function(str)
25861 this.tab.select('a', true).first().dom.innerHTML = str;
25878 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25881 * @class Roo.bootstrap.menu.Menu
25882 * @extends Roo.bootstrap.Component
25883 * Bootstrap Menu class - container for Menu
25884 * @cfg {String} html Text of the menu
25885 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25886 * @cfg {String} icon Font awesome icon
25887 * @cfg {String} pos Menu align to (top | bottom) default bottom
25891 * Create a new Menu
25892 * @param {Object} config The config object
25896 Roo.bootstrap.menu.Menu = function(config){
25897 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25901 * @event beforeshow
25902 * Fires before this menu is displayed
25903 * @param {Roo.bootstrap.menu.Menu} this
25907 * @event beforehide
25908 * Fires before this menu is hidden
25909 * @param {Roo.bootstrap.menu.Menu} this
25914 * Fires after this menu is displayed
25915 * @param {Roo.bootstrap.menu.Menu} this
25920 * Fires after this menu is hidden
25921 * @param {Roo.bootstrap.menu.Menu} this
25926 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25927 * @param {Roo.bootstrap.menu.Menu} this
25928 * @param {Roo.EventObject} e
25935 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25939 weight : 'default',
25944 getChildContainer : function() {
25945 if(this.isSubMenu){
25949 return this.el.select('ul.dropdown-menu', true).first();
25952 getAutoCreate : function()
25957 cls : 'roo-menu-text',
25965 cls : 'fa ' + this.icon
25976 cls : 'dropdown-button btn btn-' + this.weight,
25981 cls : 'dropdown-toggle btn btn-' + this.weight,
25991 cls : 'dropdown-menu'
25997 if(this.pos == 'top'){
25998 cfg.cls += ' dropup';
26001 if(this.isSubMenu){
26004 cls : 'dropdown-menu'
26011 onRender : function(ct, position)
26013 this.isSubMenu = ct.hasClass('dropdown-submenu');
26015 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26018 initEvents : function()
26020 if(this.isSubMenu){
26024 this.hidden = true;
26026 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26027 this.triggerEl.on('click', this.onTriggerPress, this);
26029 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26030 this.buttonEl.on('click', this.onClick, this);
26036 if(this.isSubMenu){
26040 return this.el.select('ul.dropdown-menu', true).first();
26043 onClick : function(e)
26045 this.fireEvent("click", this, e);
26048 onTriggerPress : function(e)
26050 if (this.isVisible()) {
26057 isVisible : function(){
26058 return !this.hidden;
26063 this.fireEvent("beforeshow", this);
26065 this.hidden = false;
26066 this.el.addClass('open');
26068 Roo.get(document).on("mouseup", this.onMouseUp, this);
26070 this.fireEvent("show", this);
26077 this.fireEvent("beforehide", this);
26079 this.hidden = true;
26080 this.el.removeClass('open');
26082 Roo.get(document).un("mouseup", this.onMouseUp);
26084 this.fireEvent("hide", this);
26087 onMouseUp : function()
26101 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26104 * @class Roo.bootstrap.menu.Item
26105 * @extends Roo.bootstrap.Component
26106 * Bootstrap MenuItem class
26107 * @cfg {Boolean} submenu (true | false) default false
26108 * @cfg {String} html text of the item
26109 * @cfg {String} href the link
26110 * @cfg {Boolean} disable (true | false) default false
26111 * @cfg {Boolean} preventDefault (true | false) default true
26112 * @cfg {String} icon Font awesome icon
26113 * @cfg {String} pos Submenu align to (left | right) default right
26117 * Create a new Item
26118 * @param {Object} config The config object
26122 Roo.bootstrap.menu.Item = function(config){
26123 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26127 * Fires when the mouse is hovering over this menu
26128 * @param {Roo.bootstrap.menu.Item} this
26129 * @param {Roo.EventObject} e
26134 * Fires when the mouse exits this menu
26135 * @param {Roo.bootstrap.menu.Item} this
26136 * @param {Roo.EventObject} e
26142 * The raw click event for the entire grid.
26143 * @param {Roo.EventObject} e
26149 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26154 preventDefault: true,
26159 getAutoCreate : function()
26164 cls : 'roo-menu-item-text',
26172 cls : 'fa ' + this.icon
26181 href : this.href || '#',
26188 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26192 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26194 if(this.pos == 'left'){
26195 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26202 initEvents : function()
26204 this.el.on('mouseover', this.onMouseOver, this);
26205 this.el.on('mouseout', this.onMouseOut, this);
26207 this.el.select('a', true).first().on('click', this.onClick, this);
26211 onClick : function(e)
26213 if(this.preventDefault){
26214 e.preventDefault();
26217 this.fireEvent("click", this, e);
26220 onMouseOver : function(e)
26222 if(this.submenu && this.pos == 'left'){
26223 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26226 this.fireEvent("mouseover", this, e);
26229 onMouseOut : function(e)
26231 this.fireEvent("mouseout", this, e);
26243 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26246 * @class Roo.bootstrap.menu.Separator
26247 * @extends Roo.bootstrap.Component
26248 * Bootstrap Separator class
26251 * Create a new Separator
26252 * @param {Object} config The config object
26256 Roo.bootstrap.menu.Separator = function(config){
26257 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26260 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26262 getAutoCreate : function(){
26283 * @class Roo.bootstrap.Tooltip
26284 * Bootstrap Tooltip class
26285 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26286 * to determine which dom element triggers the tooltip.
26288 * It needs to add support for additional attributes like tooltip-position
26291 * Create a new Toolti
26292 * @param {Object} config The config object
26295 Roo.bootstrap.Tooltip = function(config){
26296 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26298 this.alignment = Roo.bootstrap.Tooltip.alignment;
26300 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26301 this.alignment = config.alignment;
26306 Roo.apply(Roo.bootstrap.Tooltip, {
26308 * @function init initialize tooltip monitoring.
26312 currentTip : false,
26313 currentRegion : false,
26319 Roo.get(document).on('mouseover', this.enter ,this);
26320 Roo.get(document).on('mouseout', this.leave, this);
26323 this.currentTip = new Roo.bootstrap.Tooltip();
26326 enter : function(ev)
26328 var dom = ev.getTarget();
26330 //Roo.log(['enter',dom]);
26331 var el = Roo.fly(dom);
26332 if (this.currentEl) {
26334 //Roo.log(this.currentEl);
26335 //Roo.log(this.currentEl.contains(dom));
26336 if (this.currentEl == el) {
26339 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26345 if (this.currentTip.el) {
26346 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26350 if(!el || el.dom == document){
26356 // you can not look for children, as if el is the body.. then everythign is the child..
26357 if (!el.attr('tooltip')) { //
26358 if (!el.select("[tooltip]").elements.length) {
26361 // is the mouse over this child...?
26362 bindEl = el.select("[tooltip]").first();
26363 var xy = ev.getXY();
26364 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26365 //Roo.log("not in region.");
26368 //Roo.log("child element over..");
26371 this.currentEl = bindEl;
26372 this.currentTip.bind(bindEl);
26373 this.currentRegion = Roo.lib.Region.getRegion(dom);
26374 this.currentTip.enter();
26377 leave : function(ev)
26379 var dom = ev.getTarget();
26380 //Roo.log(['leave',dom]);
26381 if (!this.currentEl) {
26386 if (dom != this.currentEl.dom) {
26389 var xy = ev.getXY();
26390 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26393 // only activate leave if mouse cursor is outside... bounding box..
26398 if (this.currentTip) {
26399 this.currentTip.leave();
26401 //Roo.log('clear currentEl');
26402 this.currentEl = false;
26407 'left' : ['r-l', [-2,0], 'right'],
26408 'right' : ['l-r', [2,0], 'left'],
26409 'bottom' : ['t-b', [0,2], 'top'],
26410 'top' : [ 'b-t', [0,-2], 'bottom']
26416 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26421 delay : null, // can be { show : 300 , hide: 500}
26425 hoverState : null, //???
26427 placement : 'bottom',
26431 getAutoCreate : function(){
26438 cls : 'tooltip-arrow'
26441 cls : 'tooltip-inner'
26448 bind : function(el)
26454 enter : function () {
26456 if (this.timeout != null) {
26457 clearTimeout(this.timeout);
26460 this.hoverState = 'in';
26461 //Roo.log("enter - show");
26462 if (!this.delay || !this.delay.show) {
26467 this.timeout = setTimeout(function () {
26468 if (_t.hoverState == 'in') {
26471 }, this.delay.show);
26475 clearTimeout(this.timeout);
26477 this.hoverState = 'out';
26478 if (!this.delay || !this.delay.hide) {
26484 this.timeout = setTimeout(function () {
26485 //Roo.log("leave - timeout");
26487 if (_t.hoverState == 'out') {
26489 Roo.bootstrap.Tooltip.currentEl = false;
26494 show : function (msg)
26497 this.render(document.body);
26500 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26502 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26504 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26506 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26508 var placement = typeof this.placement == 'function' ?
26509 this.placement.call(this, this.el, on_el) :
26512 var autoToken = /\s?auto?\s?/i;
26513 var autoPlace = autoToken.test(placement);
26515 placement = placement.replace(autoToken, '') || 'top';
26519 //this.el.setXY([0,0]);
26521 //this.el.dom.style.display='block';
26523 //this.el.appendTo(on_el);
26525 var p = this.getPosition();
26526 var box = this.el.getBox();
26532 var align = this.alignment[placement];
26534 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26536 if(placement == 'top' || placement == 'bottom'){
26538 placement = 'right';
26541 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26542 placement = 'left';
26545 var scroll = Roo.select('body', true).first().getScroll();
26547 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26551 align = this.alignment[placement];
26554 this.el.alignTo(this.bindEl, align[0],align[1]);
26555 //var arrow = this.el.select('.arrow',true).first();
26556 //arrow.set(align[2],
26558 this.el.addClass(placement);
26560 this.el.addClass('in fade');
26562 this.hoverState = null;
26564 if (this.el.hasClass('fade')) {
26575 //this.el.setXY([0,0]);
26576 this.el.removeClass('in');
26592 * @class Roo.bootstrap.LocationPicker
26593 * @extends Roo.bootstrap.Component
26594 * Bootstrap LocationPicker class
26595 * @cfg {Number} latitude Position when init default 0
26596 * @cfg {Number} longitude Position when init default 0
26597 * @cfg {Number} zoom default 15
26598 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26599 * @cfg {Boolean} mapTypeControl default false
26600 * @cfg {Boolean} disableDoubleClickZoom default false
26601 * @cfg {Boolean} scrollwheel default true
26602 * @cfg {Boolean} streetViewControl default false
26603 * @cfg {Number} radius default 0
26604 * @cfg {String} locationName
26605 * @cfg {Boolean} draggable default true
26606 * @cfg {Boolean} enableAutocomplete default false
26607 * @cfg {Boolean} enableReverseGeocode default true
26608 * @cfg {String} markerTitle
26611 * Create a new LocationPicker
26612 * @param {Object} config The config object
26616 Roo.bootstrap.LocationPicker = function(config){
26618 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26623 * Fires when the picker initialized.
26624 * @param {Roo.bootstrap.LocationPicker} this
26625 * @param {Google Location} location
26629 * @event positionchanged
26630 * Fires when the picker position changed.
26631 * @param {Roo.bootstrap.LocationPicker} this
26632 * @param {Google Location} location
26634 positionchanged : true,
26637 * Fires when the map resize.
26638 * @param {Roo.bootstrap.LocationPicker} this
26643 * Fires when the map show.
26644 * @param {Roo.bootstrap.LocationPicker} this
26649 * Fires when the map hide.
26650 * @param {Roo.bootstrap.LocationPicker} this
26655 * Fires when click the map.
26656 * @param {Roo.bootstrap.LocationPicker} this
26657 * @param {Map event} e
26661 * @event mapRightClick
26662 * Fires when right click the map.
26663 * @param {Roo.bootstrap.LocationPicker} this
26664 * @param {Map event} e
26666 mapRightClick : true,
26668 * @event markerClick
26669 * Fires when click the marker.
26670 * @param {Roo.bootstrap.LocationPicker} this
26671 * @param {Map event} e
26673 markerClick : true,
26675 * @event markerRightClick
26676 * Fires when right click the marker.
26677 * @param {Roo.bootstrap.LocationPicker} this
26678 * @param {Map event} e
26680 markerRightClick : true,
26682 * @event OverlayViewDraw
26683 * Fires when OverlayView Draw
26684 * @param {Roo.bootstrap.LocationPicker} this
26686 OverlayViewDraw : true,
26688 * @event OverlayViewOnAdd
26689 * Fires when OverlayView Draw
26690 * @param {Roo.bootstrap.LocationPicker} this
26692 OverlayViewOnAdd : true,
26694 * @event OverlayViewOnRemove
26695 * Fires when OverlayView Draw
26696 * @param {Roo.bootstrap.LocationPicker} this
26698 OverlayViewOnRemove : true,
26700 * @event OverlayViewShow
26701 * Fires when OverlayView Draw
26702 * @param {Roo.bootstrap.LocationPicker} this
26703 * @param {Pixel} cpx
26705 OverlayViewShow : true,
26707 * @event OverlayViewHide
26708 * Fires when OverlayView Draw
26709 * @param {Roo.bootstrap.LocationPicker} this
26711 OverlayViewHide : true,
26713 * @event loadexception
26714 * Fires when load google lib failed.
26715 * @param {Roo.bootstrap.LocationPicker} this
26717 loadexception : true
26722 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26724 gMapContext: false,
26730 mapTypeControl: false,
26731 disableDoubleClickZoom: false,
26733 streetViewControl: false,
26737 enableAutocomplete: false,
26738 enableReverseGeocode: true,
26741 getAutoCreate: function()
26746 cls: 'roo-location-picker'
26752 initEvents: function(ct, position)
26754 if(!this.el.getWidth() || this.isApplied()){
26758 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26763 initial: function()
26765 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26766 this.fireEvent('loadexception', this);
26770 if(!this.mapTypeId){
26771 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26774 this.gMapContext = this.GMapContext();
26776 this.initOverlayView();
26778 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26782 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26783 _this.setPosition(_this.gMapContext.marker.position);
26786 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26787 _this.fireEvent('mapClick', this, event);
26791 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26792 _this.fireEvent('mapRightClick', this, event);
26796 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26797 _this.fireEvent('markerClick', this, event);
26801 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26802 _this.fireEvent('markerRightClick', this, event);
26806 this.setPosition(this.gMapContext.location);
26808 this.fireEvent('initial', this, this.gMapContext.location);
26811 initOverlayView: function()
26815 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26819 _this.fireEvent('OverlayViewDraw', _this);
26824 _this.fireEvent('OverlayViewOnAdd', _this);
26827 onRemove: function()
26829 _this.fireEvent('OverlayViewOnRemove', _this);
26832 show: function(cpx)
26834 _this.fireEvent('OverlayViewShow', _this, cpx);
26839 _this.fireEvent('OverlayViewHide', _this);
26845 fromLatLngToContainerPixel: function(event)
26847 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26850 isApplied: function()
26852 return this.getGmapContext() == false ? false : true;
26855 getGmapContext: function()
26857 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26860 GMapContext: function()
26862 var position = new google.maps.LatLng(this.latitude, this.longitude);
26864 var _map = new google.maps.Map(this.el.dom, {
26867 mapTypeId: this.mapTypeId,
26868 mapTypeControl: this.mapTypeControl,
26869 disableDoubleClickZoom: this.disableDoubleClickZoom,
26870 scrollwheel: this.scrollwheel,
26871 streetViewControl: this.streetViewControl,
26872 locationName: this.locationName,
26873 draggable: this.draggable,
26874 enableAutocomplete: this.enableAutocomplete,
26875 enableReverseGeocode: this.enableReverseGeocode
26878 var _marker = new google.maps.Marker({
26879 position: position,
26881 title: this.markerTitle,
26882 draggable: this.draggable
26889 location: position,
26890 radius: this.radius,
26891 locationName: this.locationName,
26892 addressComponents: {
26893 formatted_address: null,
26894 addressLine1: null,
26895 addressLine2: null,
26897 streetNumber: null,
26901 stateOrProvince: null
26904 domContainer: this.el.dom,
26905 geodecoder: new google.maps.Geocoder()
26909 drawCircle: function(center, radius, options)
26911 if (this.gMapContext.circle != null) {
26912 this.gMapContext.circle.setMap(null);
26916 options = Roo.apply({}, options, {
26917 strokeColor: "#0000FF",
26918 strokeOpacity: .35,
26920 fillColor: "#0000FF",
26924 options.map = this.gMapContext.map;
26925 options.radius = radius;
26926 options.center = center;
26927 this.gMapContext.circle = new google.maps.Circle(options);
26928 return this.gMapContext.circle;
26934 setPosition: function(location)
26936 this.gMapContext.location = location;
26937 this.gMapContext.marker.setPosition(location);
26938 this.gMapContext.map.panTo(location);
26939 this.drawCircle(location, this.gMapContext.radius, {});
26943 if (this.gMapContext.settings.enableReverseGeocode) {
26944 this.gMapContext.geodecoder.geocode({
26945 latLng: this.gMapContext.location
26946 }, function(results, status) {
26948 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26949 _this.gMapContext.locationName = results[0].formatted_address;
26950 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26952 _this.fireEvent('positionchanged', this, location);
26959 this.fireEvent('positionchanged', this, location);
26964 google.maps.event.trigger(this.gMapContext.map, "resize");
26966 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26968 this.fireEvent('resize', this);
26971 setPositionByLatLng: function(latitude, longitude)
26973 this.setPosition(new google.maps.LatLng(latitude, longitude));
26976 getCurrentPosition: function()
26979 latitude: this.gMapContext.location.lat(),
26980 longitude: this.gMapContext.location.lng()
26984 getAddressName: function()
26986 return this.gMapContext.locationName;
26989 getAddressComponents: function()
26991 return this.gMapContext.addressComponents;
26994 address_component_from_google_geocode: function(address_components)
26998 for (var i = 0; i < address_components.length; i++) {
26999 var component = address_components[i];
27000 if (component.types.indexOf("postal_code") >= 0) {
27001 result.postalCode = component.short_name;
27002 } else if (component.types.indexOf("street_number") >= 0) {
27003 result.streetNumber = component.short_name;
27004 } else if (component.types.indexOf("route") >= 0) {
27005 result.streetName = component.short_name;
27006 } else if (component.types.indexOf("neighborhood") >= 0) {
27007 result.city = component.short_name;
27008 } else if (component.types.indexOf("locality") >= 0) {
27009 result.city = component.short_name;
27010 } else if (component.types.indexOf("sublocality") >= 0) {
27011 result.district = component.short_name;
27012 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27013 result.stateOrProvince = component.short_name;
27014 } else if (component.types.indexOf("country") >= 0) {
27015 result.country = component.short_name;
27019 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27020 result.addressLine2 = "";
27024 setZoomLevel: function(zoom)
27026 this.gMapContext.map.setZoom(zoom);
27039 this.fireEvent('show', this);
27050 this.fireEvent('hide', this);
27055 Roo.apply(Roo.bootstrap.LocationPicker, {
27057 OverlayView : function(map, options)
27059 options = options || {};
27073 * @class Roo.bootstrap.Alert
27074 * @extends Roo.bootstrap.Component
27075 * Bootstrap Alert class
27076 * @cfg {String} title The title of alert
27077 * @cfg {String} html The content of alert
27078 * @cfg {String} weight ( success | info | warning | danger )
27079 * @cfg {String} faicon font-awesomeicon
27082 * Create a new alert
27083 * @param {Object} config The config object
27087 Roo.bootstrap.Alert = function(config){
27088 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27092 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27099 getAutoCreate : function()
27108 cls : 'roo-alert-icon'
27113 cls : 'roo-alert-title',
27118 cls : 'roo-alert-text',
27125 cfg.cn[0].cls += ' fa ' + this.faicon;
27129 cfg.cls += ' alert-' + this.weight;
27135 initEvents: function()
27137 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27140 setTitle : function(str)
27142 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27145 setText : function(str)
27147 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27150 setWeight : function(weight)
27153 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27156 this.weight = weight;
27158 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27161 setIcon : function(icon)
27164 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27167 this.faicon = icon;
27169 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27190 * @class Roo.bootstrap.UploadCropbox
27191 * @extends Roo.bootstrap.Component
27192 * Bootstrap UploadCropbox class
27193 * @cfg {String} emptyText show when image has been loaded
27194 * @cfg {String} rotateNotify show when image too small to rotate
27195 * @cfg {Number} errorTimeout default 3000
27196 * @cfg {Number} minWidth default 300
27197 * @cfg {Number} minHeight default 300
27198 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27199 * @cfg {Boolean} isDocument (true|false) default false
27200 * @cfg {String} url action url
27201 * @cfg {String} paramName default 'imageUpload'
27202 * @cfg {String} method default POST
27203 * @cfg {Boolean} loadMask (true|false) default true
27204 * @cfg {Boolean} loadingText default 'Loading...'
27207 * Create a new UploadCropbox
27208 * @param {Object} config The config object
27211 Roo.bootstrap.UploadCropbox = function(config){
27212 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27216 * @event beforeselectfile
27217 * Fire before select file
27218 * @param {Roo.bootstrap.UploadCropbox} this
27220 "beforeselectfile" : true,
27223 * Fire after initEvent
27224 * @param {Roo.bootstrap.UploadCropbox} this
27229 * Fire after initEvent
27230 * @param {Roo.bootstrap.UploadCropbox} this
27231 * @param {String} data
27236 * Fire when preparing the file data
27237 * @param {Roo.bootstrap.UploadCropbox} this
27238 * @param {Object} file
27243 * Fire when get exception
27244 * @param {Roo.bootstrap.UploadCropbox} this
27245 * @param {XMLHttpRequest} xhr
27247 "exception" : true,
27249 * @event beforeloadcanvas
27250 * Fire before load the canvas
27251 * @param {Roo.bootstrap.UploadCropbox} this
27252 * @param {String} src
27254 "beforeloadcanvas" : true,
27257 * Fire when trash image
27258 * @param {Roo.bootstrap.UploadCropbox} this
27263 * Fire when download the image
27264 * @param {Roo.bootstrap.UploadCropbox} this
27268 * @event footerbuttonclick
27269 * Fire when footerbuttonclick
27270 * @param {Roo.bootstrap.UploadCropbox} this
27271 * @param {String} type
27273 "footerbuttonclick" : true,
27277 * @param {Roo.bootstrap.UploadCropbox} this
27282 * Fire when rotate the image
27283 * @param {Roo.bootstrap.UploadCropbox} this
27284 * @param {String} pos
27289 * Fire when inspect the file
27290 * @param {Roo.bootstrap.UploadCropbox} this
27291 * @param {Object} file
27296 * Fire when xhr upload the file
27297 * @param {Roo.bootstrap.UploadCropbox} this
27298 * @param {Object} data
27303 * Fire when arrange the file data
27304 * @param {Roo.bootstrap.UploadCropbox} this
27305 * @param {Object} formData
27310 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27313 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27315 emptyText : 'Click to upload image',
27316 rotateNotify : 'Image is too small to rotate',
27317 errorTimeout : 3000,
27331 cropType : 'image/jpeg',
27333 canvasLoaded : false,
27334 isDocument : false,
27336 paramName : 'imageUpload',
27338 loadingText : 'Loading...',
27341 getAutoCreate : function()
27345 cls : 'roo-upload-cropbox',
27349 cls : 'roo-upload-cropbox-selector',
27354 cls : 'roo-upload-cropbox-body',
27355 style : 'cursor:pointer',
27359 cls : 'roo-upload-cropbox-preview'
27363 cls : 'roo-upload-cropbox-thumb'
27367 cls : 'roo-upload-cropbox-empty-notify',
27368 html : this.emptyText
27372 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27373 html : this.rotateNotify
27379 cls : 'roo-upload-cropbox-footer',
27382 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27392 onRender : function(ct, position)
27394 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27396 if (this.buttons.length) {
27398 Roo.each(this.buttons, function(bb) {
27400 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27402 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27408 this.maskEl = this.el;
27412 initEvents : function()
27414 this.urlAPI = (window.createObjectURL && window) ||
27415 (window.URL && URL.revokeObjectURL && URL) ||
27416 (window.webkitURL && webkitURL);
27418 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27419 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27421 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27422 this.selectorEl.hide();
27424 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27425 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27427 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27428 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27429 this.thumbEl.hide();
27431 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27432 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27434 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27435 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27436 this.errorEl.hide();
27438 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27439 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27440 this.footerEl.hide();
27442 this.setThumbBoxSize();
27448 this.fireEvent('initial', this);
27455 window.addEventListener("resize", function() { _this.resize(); } );
27457 this.bodyEl.on('click', this.beforeSelectFile, this);
27460 this.bodyEl.on('touchstart', this.onTouchStart, this);
27461 this.bodyEl.on('touchmove', this.onTouchMove, this);
27462 this.bodyEl.on('touchend', this.onTouchEnd, this);
27466 this.bodyEl.on('mousedown', this.onMouseDown, this);
27467 this.bodyEl.on('mousemove', this.onMouseMove, this);
27468 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27469 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27470 Roo.get(document).on('mouseup', this.onMouseUp, this);
27473 this.selectorEl.on('change', this.onFileSelected, this);
27479 this.baseScale = 1;
27481 this.baseRotate = 1;
27482 this.dragable = false;
27483 this.pinching = false;
27486 this.cropData = false;
27487 this.notifyEl.dom.innerHTML = this.emptyText;
27489 this.selectorEl.dom.value = '';
27493 resize : function()
27495 if(this.fireEvent('resize', this) != false){
27496 this.setThumbBoxPosition();
27497 this.setCanvasPosition();
27501 onFooterButtonClick : function(e, el, o, type)
27504 case 'rotate-left' :
27505 this.onRotateLeft(e);
27507 case 'rotate-right' :
27508 this.onRotateRight(e);
27511 this.beforeSelectFile(e);
27526 this.fireEvent('footerbuttonclick', this, type);
27529 beforeSelectFile : function(e)
27531 e.preventDefault();
27533 if(this.fireEvent('beforeselectfile', this) != false){
27534 this.selectorEl.dom.click();
27538 onFileSelected : function(e)
27540 e.preventDefault();
27542 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27546 var file = this.selectorEl.dom.files[0];
27548 if(this.fireEvent('inspect', this, file) != false){
27549 this.prepare(file);
27554 trash : function(e)
27556 this.fireEvent('trash', this);
27559 download : function(e)
27561 this.fireEvent('download', this);
27564 loadCanvas : function(src)
27566 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27570 this.imageEl = document.createElement('img');
27574 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27576 this.imageEl.src = src;
27580 onLoadCanvas : function()
27582 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27583 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27585 this.bodyEl.un('click', this.beforeSelectFile, this);
27587 this.notifyEl.hide();
27588 this.thumbEl.show();
27589 this.footerEl.show();
27591 this.baseRotateLevel();
27593 if(this.isDocument){
27594 this.setThumbBoxSize();
27597 this.setThumbBoxPosition();
27599 this.baseScaleLevel();
27605 this.canvasLoaded = true;
27608 this.maskEl.unmask();
27613 setCanvasPosition : function()
27615 if(!this.canvasEl){
27619 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27620 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27622 this.previewEl.setLeft(pw);
27623 this.previewEl.setTop(ph);
27627 onMouseDown : function(e)
27631 this.dragable = true;
27632 this.pinching = false;
27634 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27635 this.dragable = false;
27639 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27640 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27644 onMouseMove : function(e)
27648 if(!this.canvasLoaded){
27652 if (!this.dragable){
27656 var minX = Math.ceil(this.thumbEl.getLeft(true));
27657 var minY = Math.ceil(this.thumbEl.getTop(true));
27659 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27660 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27662 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27663 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27665 x = x - this.mouseX;
27666 y = y - this.mouseY;
27668 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27669 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27671 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27672 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27674 this.previewEl.setLeft(bgX);
27675 this.previewEl.setTop(bgY);
27677 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27678 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27681 onMouseUp : function(e)
27685 this.dragable = false;
27688 onMouseWheel : function(e)
27692 this.startScale = this.scale;
27694 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27696 if(!this.zoomable()){
27697 this.scale = this.startScale;
27706 zoomable : function()
27708 var minScale = this.thumbEl.getWidth() / this.minWidth;
27710 if(this.minWidth < this.minHeight){
27711 minScale = this.thumbEl.getHeight() / this.minHeight;
27714 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27715 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27719 (this.rotate == 0 || this.rotate == 180) &&
27721 width > this.imageEl.OriginWidth ||
27722 height > this.imageEl.OriginHeight ||
27723 (width < this.minWidth && height < this.minHeight)
27731 (this.rotate == 90 || this.rotate == 270) &&
27733 width > this.imageEl.OriginWidth ||
27734 height > this.imageEl.OriginHeight ||
27735 (width < this.minHeight && height < this.minWidth)
27742 !this.isDocument &&
27743 (this.rotate == 0 || this.rotate == 180) &&
27745 width < this.minWidth ||
27746 width > this.imageEl.OriginWidth ||
27747 height < this.minHeight ||
27748 height > this.imageEl.OriginHeight
27755 !this.isDocument &&
27756 (this.rotate == 90 || this.rotate == 270) &&
27758 width < this.minHeight ||
27759 width > this.imageEl.OriginWidth ||
27760 height < this.minWidth ||
27761 height > this.imageEl.OriginHeight
27771 onRotateLeft : function(e)
27773 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27775 var minScale = this.thumbEl.getWidth() / this.minWidth;
27777 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27778 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27780 this.startScale = this.scale;
27782 while (this.getScaleLevel() < minScale){
27784 this.scale = this.scale + 1;
27786 if(!this.zoomable()){
27791 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27792 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27797 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27804 this.scale = this.startScale;
27806 this.onRotateFail();
27811 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27813 if(this.isDocument){
27814 this.setThumbBoxSize();
27815 this.setThumbBoxPosition();
27816 this.setCanvasPosition();
27821 this.fireEvent('rotate', this, 'left');
27825 onRotateRight : function(e)
27827 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27829 var minScale = this.thumbEl.getWidth() / this.minWidth;
27831 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27832 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27834 this.startScale = this.scale;
27836 while (this.getScaleLevel() < minScale){
27838 this.scale = this.scale + 1;
27840 if(!this.zoomable()){
27845 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27846 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27851 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27858 this.scale = this.startScale;
27860 this.onRotateFail();
27865 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27867 if(this.isDocument){
27868 this.setThumbBoxSize();
27869 this.setThumbBoxPosition();
27870 this.setCanvasPosition();
27875 this.fireEvent('rotate', this, 'right');
27878 onRotateFail : function()
27880 this.errorEl.show(true);
27884 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27889 this.previewEl.dom.innerHTML = '';
27891 var canvasEl = document.createElement("canvas");
27893 var contextEl = canvasEl.getContext("2d");
27895 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27896 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27897 var center = this.imageEl.OriginWidth / 2;
27899 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27900 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27901 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27902 center = this.imageEl.OriginHeight / 2;
27905 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27907 contextEl.translate(center, center);
27908 contextEl.rotate(this.rotate * Math.PI / 180);
27910 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27912 this.canvasEl = document.createElement("canvas");
27914 this.contextEl = this.canvasEl.getContext("2d");
27916 switch (this.rotate) {
27919 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27920 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27922 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27927 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27928 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27930 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27931 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);
27935 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27940 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27941 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27943 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27944 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);
27948 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);
27953 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27954 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27956 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27957 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27961 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);
27968 this.previewEl.appendChild(this.canvasEl);
27970 this.setCanvasPosition();
27975 if(!this.canvasLoaded){
27979 var imageCanvas = document.createElement("canvas");
27981 var imageContext = imageCanvas.getContext("2d");
27983 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27984 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27986 var center = imageCanvas.width / 2;
27988 imageContext.translate(center, center);
27990 imageContext.rotate(this.rotate * Math.PI / 180);
27992 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27994 var canvas = document.createElement("canvas");
27996 var context = canvas.getContext("2d");
27998 canvas.width = this.minWidth;
27999 canvas.height = this.minHeight;
28001 switch (this.rotate) {
28004 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28005 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28007 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28008 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28010 var targetWidth = this.minWidth - 2 * x;
28011 var targetHeight = this.minHeight - 2 * y;
28015 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28016 scale = targetWidth / width;
28019 if(x > 0 && y == 0){
28020 scale = targetHeight / height;
28023 if(x > 0 && y > 0){
28024 scale = targetWidth / width;
28026 if(width < height){
28027 scale = targetHeight / height;
28031 context.scale(scale, scale);
28033 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28034 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28036 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28037 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28039 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28044 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28045 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28047 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28048 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28050 var targetWidth = this.minWidth - 2 * x;
28051 var targetHeight = this.minHeight - 2 * y;
28055 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28056 scale = targetWidth / width;
28059 if(x > 0 && y == 0){
28060 scale = targetHeight / height;
28063 if(x > 0 && y > 0){
28064 scale = targetWidth / width;
28066 if(width < height){
28067 scale = targetHeight / height;
28071 context.scale(scale, scale);
28073 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28074 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28076 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28077 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28079 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28081 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28086 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28087 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28089 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28090 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28092 var targetWidth = this.minWidth - 2 * x;
28093 var targetHeight = this.minHeight - 2 * y;
28097 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28098 scale = targetWidth / width;
28101 if(x > 0 && y == 0){
28102 scale = targetHeight / height;
28105 if(x > 0 && y > 0){
28106 scale = targetWidth / width;
28108 if(width < height){
28109 scale = targetHeight / height;
28113 context.scale(scale, scale);
28115 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28116 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28118 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28119 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28121 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28122 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28124 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28129 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28130 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28132 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28133 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28135 var targetWidth = this.minWidth - 2 * x;
28136 var targetHeight = this.minHeight - 2 * y;
28140 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28141 scale = targetWidth / width;
28144 if(x > 0 && y == 0){
28145 scale = targetHeight / height;
28148 if(x > 0 && y > 0){
28149 scale = targetWidth / width;
28151 if(width < height){
28152 scale = targetHeight / height;
28156 context.scale(scale, scale);
28158 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28159 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28161 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28162 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28164 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28166 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28173 this.cropData = canvas.toDataURL(this.cropType);
28175 if(this.fireEvent('crop', this, this.cropData) !== false){
28176 this.process(this.file, this.cropData);
28183 setThumbBoxSize : function()
28187 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28188 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28189 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28191 this.minWidth = width;
28192 this.minHeight = height;
28194 if(this.rotate == 90 || this.rotate == 270){
28195 this.minWidth = height;
28196 this.minHeight = width;
28201 width = Math.ceil(this.minWidth * height / this.minHeight);
28203 if(this.minWidth > this.minHeight){
28205 height = Math.ceil(this.minHeight * width / this.minWidth);
28208 this.thumbEl.setStyle({
28209 width : width + 'px',
28210 height : height + 'px'
28217 setThumbBoxPosition : function()
28219 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28220 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28222 this.thumbEl.setLeft(x);
28223 this.thumbEl.setTop(y);
28227 baseRotateLevel : function()
28229 this.baseRotate = 1;
28232 typeof(this.exif) != 'undefined' &&
28233 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28234 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28236 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28239 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28243 baseScaleLevel : function()
28247 if(this.isDocument){
28249 if(this.baseRotate == 6 || this.baseRotate == 8){
28251 height = this.thumbEl.getHeight();
28252 this.baseScale = height / this.imageEl.OriginWidth;
28254 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28255 width = this.thumbEl.getWidth();
28256 this.baseScale = width / this.imageEl.OriginHeight;
28262 height = this.thumbEl.getHeight();
28263 this.baseScale = height / this.imageEl.OriginHeight;
28265 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28266 width = this.thumbEl.getWidth();
28267 this.baseScale = width / this.imageEl.OriginWidth;
28273 if(this.baseRotate == 6 || this.baseRotate == 8){
28275 width = this.thumbEl.getHeight();
28276 this.baseScale = width / this.imageEl.OriginHeight;
28278 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28279 height = this.thumbEl.getWidth();
28280 this.baseScale = height / this.imageEl.OriginHeight;
28283 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28284 height = this.thumbEl.getWidth();
28285 this.baseScale = height / this.imageEl.OriginHeight;
28287 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28288 width = this.thumbEl.getHeight();
28289 this.baseScale = width / this.imageEl.OriginWidth;
28296 width = this.thumbEl.getWidth();
28297 this.baseScale = width / this.imageEl.OriginWidth;
28299 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28300 height = this.thumbEl.getHeight();
28301 this.baseScale = height / this.imageEl.OriginHeight;
28304 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28306 height = this.thumbEl.getHeight();
28307 this.baseScale = height / this.imageEl.OriginHeight;
28309 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28310 width = this.thumbEl.getWidth();
28311 this.baseScale = width / this.imageEl.OriginWidth;
28319 getScaleLevel : function()
28321 return this.baseScale * Math.pow(1.1, this.scale);
28324 onTouchStart : function(e)
28326 if(!this.canvasLoaded){
28327 this.beforeSelectFile(e);
28331 var touches = e.browserEvent.touches;
28337 if(touches.length == 1){
28338 this.onMouseDown(e);
28342 if(touches.length != 2){
28348 for(var i = 0, finger; finger = touches[i]; i++){
28349 coords.push(finger.pageX, finger.pageY);
28352 var x = Math.pow(coords[0] - coords[2], 2);
28353 var y = Math.pow(coords[1] - coords[3], 2);
28355 this.startDistance = Math.sqrt(x + y);
28357 this.startScale = this.scale;
28359 this.pinching = true;
28360 this.dragable = false;
28364 onTouchMove : function(e)
28366 if(!this.pinching && !this.dragable){
28370 var touches = e.browserEvent.touches;
28377 this.onMouseMove(e);
28383 for(var i = 0, finger; finger = touches[i]; i++){
28384 coords.push(finger.pageX, finger.pageY);
28387 var x = Math.pow(coords[0] - coords[2], 2);
28388 var y = Math.pow(coords[1] - coords[3], 2);
28390 this.endDistance = Math.sqrt(x + y);
28392 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28394 if(!this.zoomable()){
28395 this.scale = this.startScale;
28403 onTouchEnd : function(e)
28405 this.pinching = false;
28406 this.dragable = false;
28410 process : function(file, crop)
28413 this.maskEl.mask(this.loadingText);
28416 this.xhr = new XMLHttpRequest();
28418 file.xhr = this.xhr;
28420 this.xhr.open(this.method, this.url, true);
28423 "Accept": "application/json",
28424 "Cache-Control": "no-cache",
28425 "X-Requested-With": "XMLHttpRequest"
28428 for (var headerName in headers) {
28429 var headerValue = headers[headerName];
28431 this.xhr.setRequestHeader(headerName, headerValue);
28437 this.xhr.onload = function()
28439 _this.xhrOnLoad(_this.xhr);
28442 this.xhr.onerror = function()
28444 _this.xhrOnError(_this.xhr);
28447 var formData = new FormData();
28449 formData.append('returnHTML', 'NO');
28452 formData.append('crop', crop);
28455 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28456 formData.append(this.paramName, file, file.name);
28459 if(typeof(file.filename) != 'undefined'){
28460 formData.append('filename', file.filename);
28463 if(typeof(file.mimetype) != 'undefined'){
28464 formData.append('mimetype', file.mimetype);
28467 if(this.fireEvent('arrange', this, formData) != false){
28468 this.xhr.send(formData);
28472 xhrOnLoad : function(xhr)
28475 this.maskEl.unmask();
28478 if (xhr.readyState !== 4) {
28479 this.fireEvent('exception', this, xhr);
28483 var response = Roo.decode(xhr.responseText);
28485 if(!response.success){
28486 this.fireEvent('exception', this, xhr);
28490 var response = Roo.decode(xhr.responseText);
28492 this.fireEvent('upload', this, response);
28496 xhrOnError : function()
28499 this.maskEl.unmask();
28502 Roo.log('xhr on error');
28504 var response = Roo.decode(xhr.responseText);
28510 prepare : function(file)
28513 this.maskEl.mask(this.loadingText);
28519 if(typeof(file) === 'string'){
28520 this.loadCanvas(file);
28524 if(!file || !this.urlAPI){
28529 this.cropType = file.type;
28533 if(this.fireEvent('prepare', this, this.file) != false){
28535 var reader = new FileReader();
28537 reader.onload = function (e) {
28538 if (e.target.error) {
28539 Roo.log(e.target.error);
28543 var buffer = e.target.result,
28544 dataView = new DataView(buffer),
28546 maxOffset = dataView.byteLength - 4,
28550 if (dataView.getUint16(0) === 0xffd8) {
28551 while (offset < maxOffset) {
28552 markerBytes = dataView.getUint16(offset);
28554 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28555 markerLength = dataView.getUint16(offset + 2) + 2;
28556 if (offset + markerLength > dataView.byteLength) {
28557 Roo.log('Invalid meta data: Invalid segment size.');
28561 if(markerBytes == 0xffe1){
28562 _this.parseExifData(
28569 offset += markerLength;
28579 var url = _this.urlAPI.createObjectURL(_this.file);
28581 _this.loadCanvas(url);
28586 reader.readAsArrayBuffer(this.file);
28592 parseExifData : function(dataView, offset, length)
28594 var tiffOffset = offset + 10,
28598 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28599 // No Exif data, might be XMP data instead
28603 // Check for the ASCII code for "Exif" (0x45786966):
28604 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28605 // No Exif data, might be XMP data instead
28608 if (tiffOffset + 8 > dataView.byteLength) {
28609 Roo.log('Invalid Exif data: Invalid segment size.');
28612 // Check for the two null bytes:
28613 if (dataView.getUint16(offset + 8) !== 0x0000) {
28614 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28617 // Check the byte alignment:
28618 switch (dataView.getUint16(tiffOffset)) {
28620 littleEndian = true;
28623 littleEndian = false;
28626 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28629 // Check for the TIFF tag marker (0x002A):
28630 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28631 Roo.log('Invalid Exif data: Missing TIFF marker.');
28634 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28635 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28637 this.parseExifTags(
28640 tiffOffset + dirOffset,
28645 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28650 if (dirOffset + 6 > dataView.byteLength) {
28651 Roo.log('Invalid Exif data: Invalid directory offset.');
28654 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28655 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28656 if (dirEndOffset + 4 > dataView.byteLength) {
28657 Roo.log('Invalid Exif data: Invalid directory size.');
28660 for (i = 0; i < tagsNumber; i += 1) {
28664 dirOffset + 2 + 12 * i, // tag offset
28668 // Return the offset to the next directory:
28669 return dataView.getUint32(dirEndOffset, littleEndian);
28672 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28674 var tag = dataView.getUint16(offset, littleEndian);
28676 this.exif[tag] = this.getExifValue(
28680 dataView.getUint16(offset + 2, littleEndian), // tag type
28681 dataView.getUint32(offset + 4, littleEndian), // tag length
28686 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28688 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28697 Roo.log('Invalid Exif data: Invalid tag type.');
28701 tagSize = tagType.size * length;
28702 // Determine if the value is contained in the dataOffset bytes,
28703 // or if the value at the dataOffset is a pointer to the actual data:
28704 dataOffset = tagSize > 4 ?
28705 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28706 if (dataOffset + tagSize > dataView.byteLength) {
28707 Roo.log('Invalid Exif data: Invalid data offset.');
28710 if (length === 1) {
28711 return tagType.getValue(dataView, dataOffset, littleEndian);
28714 for (i = 0; i < length; i += 1) {
28715 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28718 if (tagType.ascii) {
28720 // Concatenate the chars:
28721 for (i = 0; i < values.length; i += 1) {
28723 // Ignore the terminating NULL byte(s):
28724 if (c === '\u0000') {
28736 Roo.apply(Roo.bootstrap.UploadCropbox, {
28738 'Orientation': 0x0112
28742 1: 0, //'top-left',
28744 3: 180, //'bottom-right',
28745 // 4: 'bottom-left',
28747 6: 90, //'right-top',
28748 // 7: 'right-bottom',
28749 8: 270 //'left-bottom'
28753 // byte, 8-bit unsigned int:
28755 getValue: function (dataView, dataOffset) {
28756 return dataView.getUint8(dataOffset);
28760 // ascii, 8-bit byte:
28762 getValue: function (dataView, dataOffset) {
28763 return String.fromCharCode(dataView.getUint8(dataOffset));
28768 // short, 16 bit int:
28770 getValue: function (dataView, dataOffset, littleEndian) {
28771 return dataView.getUint16(dataOffset, littleEndian);
28775 // long, 32 bit int:
28777 getValue: function (dataView, dataOffset, littleEndian) {
28778 return dataView.getUint32(dataOffset, littleEndian);
28782 // rational = two long values, first is numerator, second is denominator:
28784 getValue: function (dataView, dataOffset, littleEndian) {
28785 return dataView.getUint32(dataOffset, littleEndian) /
28786 dataView.getUint32(dataOffset + 4, littleEndian);
28790 // slong, 32 bit signed int:
28792 getValue: function (dataView, dataOffset, littleEndian) {
28793 return dataView.getInt32(dataOffset, littleEndian);
28797 // srational, two slongs, first is numerator, second is denominator:
28799 getValue: function (dataView, dataOffset, littleEndian) {
28800 return dataView.getInt32(dataOffset, littleEndian) /
28801 dataView.getInt32(dataOffset + 4, littleEndian);
28811 cls : 'btn-group roo-upload-cropbox-rotate-left',
28812 action : 'rotate-left',
28816 cls : 'btn btn-default',
28817 html : '<i class="fa fa-undo"></i>'
28823 cls : 'btn-group roo-upload-cropbox-picture',
28824 action : 'picture',
28828 cls : 'btn btn-default',
28829 html : '<i class="fa fa-picture-o"></i>'
28835 cls : 'btn-group roo-upload-cropbox-rotate-right',
28836 action : 'rotate-right',
28840 cls : 'btn btn-default',
28841 html : '<i class="fa fa-repeat"></i>'
28849 cls : 'btn-group roo-upload-cropbox-rotate-left',
28850 action : 'rotate-left',
28854 cls : 'btn btn-default',
28855 html : '<i class="fa fa-undo"></i>'
28861 cls : 'btn-group roo-upload-cropbox-download',
28862 action : 'download',
28866 cls : 'btn btn-default',
28867 html : '<i class="fa fa-download"></i>'
28873 cls : 'btn-group roo-upload-cropbox-crop',
28878 cls : 'btn btn-default',
28879 html : '<i class="fa fa-crop"></i>'
28885 cls : 'btn-group roo-upload-cropbox-trash',
28890 cls : 'btn btn-default',
28891 html : '<i class="fa fa-trash"></i>'
28897 cls : 'btn-group roo-upload-cropbox-rotate-right',
28898 action : 'rotate-right',
28902 cls : 'btn btn-default',
28903 html : '<i class="fa fa-repeat"></i>'
28911 cls : 'btn-group roo-upload-cropbox-rotate-left',
28912 action : 'rotate-left',
28916 cls : 'btn btn-default',
28917 html : '<i class="fa fa-undo"></i>'
28923 cls : 'btn-group roo-upload-cropbox-rotate-right',
28924 action : 'rotate-right',
28928 cls : 'btn btn-default',
28929 html : '<i class="fa fa-repeat"></i>'
28942 * @class Roo.bootstrap.DocumentManager
28943 * @extends Roo.bootstrap.Component
28944 * Bootstrap DocumentManager class
28945 * @cfg {String} paramName default 'imageUpload'
28946 * @cfg {String} toolTipName default 'filename'
28947 * @cfg {String} method default POST
28948 * @cfg {String} url action url
28949 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28950 * @cfg {Boolean} multiple multiple upload default true
28951 * @cfg {Number} thumbSize default 300
28952 * @cfg {String} fieldLabel
28953 * @cfg {Number} labelWidth default 4
28954 * @cfg {String} labelAlign (left|top) default left
28955 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28956 * @cfg {Number} labellg set the width of label (1-12)
28957 * @cfg {Number} labelmd set the width of label (1-12)
28958 * @cfg {Number} labelsm set the width of label (1-12)
28959 * @cfg {Number} labelxs set the width of label (1-12)
28962 * Create a new DocumentManager
28963 * @param {Object} config The config object
28966 Roo.bootstrap.DocumentManager = function(config){
28967 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28970 this.delegates = [];
28975 * Fire when initial the DocumentManager
28976 * @param {Roo.bootstrap.DocumentManager} this
28981 * inspect selected file
28982 * @param {Roo.bootstrap.DocumentManager} this
28983 * @param {File} file
28988 * Fire when xhr load exception
28989 * @param {Roo.bootstrap.DocumentManager} this
28990 * @param {XMLHttpRequest} xhr
28992 "exception" : true,
28994 * @event afterupload
28995 * Fire when xhr load exception
28996 * @param {Roo.bootstrap.DocumentManager} this
28997 * @param {XMLHttpRequest} xhr
28999 "afterupload" : true,
29002 * prepare the form data
29003 * @param {Roo.bootstrap.DocumentManager} this
29004 * @param {Object} formData
29009 * Fire when remove the file
29010 * @param {Roo.bootstrap.DocumentManager} this
29011 * @param {Object} file
29016 * Fire after refresh the file
29017 * @param {Roo.bootstrap.DocumentManager} this
29022 * Fire after click the image
29023 * @param {Roo.bootstrap.DocumentManager} this
29024 * @param {Object} file
29029 * Fire when upload a image and editable set to true
29030 * @param {Roo.bootstrap.DocumentManager} this
29031 * @param {Object} file
29035 * @event beforeselectfile
29036 * Fire before select file
29037 * @param {Roo.bootstrap.DocumentManager} this
29039 "beforeselectfile" : true,
29042 * Fire before process file
29043 * @param {Roo.bootstrap.DocumentManager} this
29044 * @param {Object} file
29048 * @event previewrendered
29049 * Fire when preview rendered
29050 * @param {Roo.bootstrap.DocumentManager} this
29051 * @param {Object} file
29053 "previewrendered" : true,
29056 "previewResize" : true
29061 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29070 paramName : 'imageUpload',
29071 toolTipName : 'filename',
29074 labelAlign : 'left',
29084 getAutoCreate : function()
29086 var managerWidget = {
29088 cls : 'roo-document-manager',
29092 cls : 'roo-document-manager-selector',
29097 cls : 'roo-document-manager-uploader',
29101 cls : 'roo-document-manager-upload-btn',
29102 html : '<i class="fa fa-plus"></i>'
29113 cls : 'column col-md-12',
29118 if(this.fieldLabel.length){
29123 cls : 'column col-md-12',
29124 html : this.fieldLabel
29128 cls : 'column col-md-12',
29133 if(this.labelAlign == 'left'){
29138 html : this.fieldLabel
29147 if(this.labelWidth > 12){
29148 content[0].style = "width: " + this.labelWidth + 'px';
29151 if(this.labelWidth < 13 && this.labelmd == 0){
29152 this.labelmd = this.labelWidth;
29155 if(this.labellg > 0){
29156 content[0].cls += ' col-lg-' + this.labellg;
29157 content[1].cls += ' col-lg-' + (12 - this.labellg);
29160 if(this.labelmd > 0){
29161 content[0].cls += ' col-md-' + this.labelmd;
29162 content[1].cls += ' col-md-' + (12 - this.labelmd);
29165 if(this.labelsm > 0){
29166 content[0].cls += ' col-sm-' + this.labelsm;
29167 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29170 if(this.labelxs > 0){
29171 content[0].cls += ' col-xs-' + this.labelxs;
29172 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29180 cls : 'row clearfix',
29188 initEvents : function()
29190 this.managerEl = this.el.select('.roo-document-manager', true).first();
29191 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29193 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29194 this.selectorEl.hide();
29197 this.selectorEl.attr('multiple', 'multiple');
29200 this.selectorEl.on('change', this.onFileSelected, this);
29202 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29203 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29205 this.uploader.on('click', this.onUploaderClick, this);
29207 this.renderProgressDialog();
29211 window.addEventListener("resize", function() { _this.refresh(); } );
29213 this.fireEvent('initial', this);
29216 renderProgressDialog : function()
29220 this.progressDialog = new Roo.bootstrap.Modal({
29221 cls : 'roo-document-manager-progress-dialog',
29222 allow_close : false,
29233 btnclick : function() {
29234 _this.uploadCancel();
29240 this.progressDialog.render(Roo.get(document.body));
29242 this.progress = new Roo.bootstrap.Progress({
29243 cls : 'roo-document-manager-progress',
29248 this.progress.render(this.progressDialog.getChildContainer());
29250 this.progressBar = new Roo.bootstrap.ProgressBar({
29251 cls : 'roo-document-manager-progress-bar',
29254 aria_valuemax : 12,
29258 this.progressBar.render(this.progress.getChildContainer());
29261 onUploaderClick : function(e)
29263 e.preventDefault();
29265 if(this.fireEvent('beforeselectfile', this) != false){
29266 this.selectorEl.dom.click();
29271 onFileSelected : function(e)
29273 e.preventDefault();
29275 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29279 Roo.each(this.selectorEl.dom.files, function(file){
29280 if(this.fireEvent('inspect', this, file) != false){
29281 this.files.push(file);
29291 this.selectorEl.dom.value = '';
29293 if(!this.files || !this.files.length){
29297 if(this.boxes > 0 && this.files.length > this.boxes){
29298 this.files = this.files.slice(0, this.boxes);
29301 this.uploader.show();
29303 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29304 this.uploader.hide();
29313 Roo.each(this.files, function(file){
29315 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29316 var f = this.renderPreview(file);
29321 if(file.type.indexOf('image') != -1){
29322 this.delegates.push(
29324 _this.process(file);
29325 }).createDelegate(this)
29333 _this.process(file);
29334 }).createDelegate(this)
29339 this.files = files;
29341 this.delegates = this.delegates.concat(docs);
29343 if(!this.delegates.length){
29348 this.progressBar.aria_valuemax = this.delegates.length;
29355 arrange : function()
29357 if(!this.delegates.length){
29358 this.progressDialog.hide();
29363 var delegate = this.delegates.shift();
29365 this.progressDialog.show();
29367 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29369 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29374 refresh : function()
29376 this.uploader.show();
29378 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29379 this.uploader.hide();
29382 Roo.isTouch ? this.closable(false) : this.closable(true);
29384 this.fireEvent('refresh', this);
29387 onRemove : function(e, el, o)
29389 e.preventDefault();
29391 this.fireEvent('remove', this, o);
29395 remove : function(o)
29399 Roo.each(this.files, function(file){
29400 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29409 this.files = files;
29416 Roo.each(this.files, function(file){
29421 file.target.remove();
29430 onClick : function(e, el, o)
29432 e.preventDefault();
29434 this.fireEvent('click', this, o);
29438 closable : function(closable)
29440 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29442 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29454 xhrOnLoad : function(xhr)
29456 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29460 if (xhr.readyState !== 4) {
29462 this.fireEvent('exception', this, xhr);
29466 var response = Roo.decode(xhr.responseText);
29468 if(!response.success){
29470 this.fireEvent('exception', this, xhr);
29474 var file = this.renderPreview(response.data);
29476 this.files.push(file);
29480 this.fireEvent('afterupload', this, xhr);
29484 xhrOnError : function(xhr)
29486 Roo.log('xhr on error');
29488 var response = Roo.decode(xhr.responseText);
29495 process : function(file)
29497 if(this.fireEvent('process', this, file) !== false){
29498 if(this.editable && file.type.indexOf('image') != -1){
29499 this.fireEvent('edit', this, file);
29503 this.uploadStart(file, false);
29510 uploadStart : function(file, crop)
29512 this.xhr = new XMLHttpRequest();
29514 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29519 file.xhr = this.xhr;
29521 this.managerEl.createChild({
29523 cls : 'roo-document-manager-loading',
29527 tooltip : file.name,
29528 cls : 'roo-document-manager-thumb',
29529 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29535 this.xhr.open(this.method, this.url, true);
29538 "Accept": "application/json",
29539 "Cache-Control": "no-cache",
29540 "X-Requested-With": "XMLHttpRequest"
29543 for (var headerName in headers) {
29544 var headerValue = headers[headerName];
29546 this.xhr.setRequestHeader(headerName, headerValue);
29552 this.xhr.onload = function()
29554 _this.xhrOnLoad(_this.xhr);
29557 this.xhr.onerror = function()
29559 _this.xhrOnError(_this.xhr);
29562 var formData = new FormData();
29564 formData.append('returnHTML', 'NO');
29567 formData.append('crop', crop);
29570 formData.append(this.paramName, file, file.name);
29577 if(this.fireEvent('prepare', this, formData, options) != false){
29579 if(options.manually){
29583 this.xhr.send(formData);
29587 this.uploadCancel();
29590 uploadCancel : function()
29596 this.delegates = [];
29598 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29605 renderPreview : function(file)
29607 if(typeof(file.target) != 'undefined' && file.target){
29611 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29613 var previewEl = this.managerEl.createChild({
29615 cls : 'roo-document-manager-preview',
29619 tooltip : file[this.toolTipName],
29620 cls : 'roo-document-manager-thumb',
29621 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29626 html : '<i class="fa fa-times-circle"></i>'
29631 var close = previewEl.select('button.close', true).first();
29633 close.on('click', this.onRemove, this, file);
29635 file.target = previewEl;
29637 var image = previewEl.select('img', true).first();
29641 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29643 image.on('click', this.onClick, this, file);
29645 this.fireEvent('previewrendered', this, file);
29651 onPreviewLoad : function(file, image)
29653 if(typeof(file.target) == 'undefined' || !file.target){
29657 var width = image.dom.naturalWidth || image.dom.width;
29658 var height = image.dom.naturalHeight || image.dom.height;
29660 if(!this.previewResize) {
29664 if(width > height){
29665 file.target.addClass('wide');
29669 file.target.addClass('tall');
29674 uploadFromSource : function(file, crop)
29676 this.xhr = new XMLHttpRequest();
29678 this.managerEl.createChild({
29680 cls : 'roo-document-manager-loading',
29684 tooltip : file.name,
29685 cls : 'roo-document-manager-thumb',
29686 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29692 this.xhr.open(this.method, this.url, true);
29695 "Accept": "application/json",
29696 "Cache-Control": "no-cache",
29697 "X-Requested-With": "XMLHttpRequest"
29700 for (var headerName in headers) {
29701 var headerValue = headers[headerName];
29703 this.xhr.setRequestHeader(headerName, headerValue);
29709 this.xhr.onload = function()
29711 _this.xhrOnLoad(_this.xhr);
29714 this.xhr.onerror = function()
29716 _this.xhrOnError(_this.xhr);
29719 var formData = new FormData();
29721 formData.append('returnHTML', 'NO');
29723 formData.append('crop', crop);
29725 if(typeof(file.filename) != 'undefined'){
29726 formData.append('filename', file.filename);
29729 if(typeof(file.mimetype) != 'undefined'){
29730 formData.append('mimetype', file.mimetype);
29735 if(this.fireEvent('prepare', this, formData) != false){
29736 this.xhr.send(formData);
29746 * @class Roo.bootstrap.DocumentViewer
29747 * @extends Roo.bootstrap.Component
29748 * Bootstrap DocumentViewer class
29749 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29750 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29753 * Create a new DocumentViewer
29754 * @param {Object} config The config object
29757 Roo.bootstrap.DocumentViewer = function(config){
29758 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29763 * Fire after initEvent
29764 * @param {Roo.bootstrap.DocumentViewer} this
29770 * @param {Roo.bootstrap.DocumentViewer} this
29775 * Fire after download button
29776 * @param {Roo.bootstrap.DocumentViewer} this
29781 * Fire after trash button
29782 * @param {Roo.bootstrap.DocumentViewer} this
29789 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29791 showDownload : true,
29795 getAutoCreate : function()
29799 cls : 'roo-document-viewer',
29803 cls : 'roo-document-viewer-body',
29807 cls : 'roo-document-viewer-thumb',
29811 cls : 'roo-document-viewer-image'
29819 cls : 'roo-document-viewer-footer',
29822 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29826 cls : 'btn-group roo-document-viewer-download',
29830 cls : 'btn btn-default',
29831 html : '<i class="fa fa-download"></i>'
29837 cls : 'btn-group roo-document-viewer-trash',
29841 cls : 'btn btn-default',
29842 html : '<i class="fa fa-trash"></i>'
29855 initEvents : function()
29857 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29858 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29860 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29861 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29863 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29864 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29866 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29867 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29869 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29870 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29872 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29873 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29875 this.bodyEl.on('click', this.onClick, this);
29876 this.downloadBtn.on('click', this.onDownload, this);
29877 this.trashBtn.on('click', this.onTrash, this);
29879 this.downloadBtn.hide();
29880 this.trashBtn.hide();
29882 if(this.showDownload){
29883 this.downloadBtn.show();
29886 if(this.showTrash){
29887 this.trashBtn.show();
29890 if(!this.showDownload && !this.showTrash) {
29891 this.footerEl.hide();
29896 initial : function()
29898 this.fireEvent('initial', this);
29902 onClick : function(e)
29904 e.preventDefault();
29906 this.fireEvent('click', this);
29909 onDownload : function(e)
29911 e.preventDefault();
29913 this.fireEvent('download', this);
29916 onTrash : function(e)
29918 e.preventDefault();
29920 this.fireEvent('trash', this);
29932 * @class Roo.bootstrap.NavProgressBar
29933 * @extends Roo.bootstrap.Component
29934 * Bootstrap NavProgressBar class
29937 * Create a new nav progress bar
29938 * @param {Object} config The config object
29941 Roo.bootstrap.NavProgressBar = function(config){
29942 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29944 this.bullets = this.bullets || [];
29946 // Roo.bootstrap.NavProgressBar.register(this);
29950 * Fires when the active item changes
29951 * @param {Roo.bootstrap.NavProgressBar} this
29952 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29953 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29960 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29965 getAutoCreate : function()
29967 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29971 cls : 'roo-navigation-bar-group',
29975 cls : 'roo-navigation-top-bar'
29979 cls : 'roo-navigation-bullets-bar',
29983 cls : 'roo-navigation-bar'
29990 cls : 'roo-navigation-bottom-bar'
30000 initEvents: function()
30005 onRender : function(ct, position)
30007 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30009 if(this.bullets.length){
30010 Roo.each(this.bullets, function(b){
30019 addItem : function(cfg)
30021 var item = new Roo.bootstrap.NavProgressItem(cfg);
30023 item.parentId = this.id;
30024 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30027 var top = new Roo.bootstrap.Element({
30029 cls : 'roo-navigation-bar-text'
30032 var bottom = new Roo.bootstrap.Element({
30034 cls : 'roo-navigation-bar-text'
30037 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30038 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30040 var topText = new Roo.bootstrap.Element({
30042 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30045 var bottomText = new Roo.bootstrap.Element({
30047 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30050 topText.onRender(top.el, null);
30051 bottomText.onRender(bottom.el, null);
30054 item.bottomEl = bottom;
30057 this.barItems.push(item);
30062 getActive : function()
30064 var active = false;
30066 Roo.each(this.barItems, function(v){
30068 if (!v.isActive()) {
30080 setActiveItem : function(item)
30084 Roo.each(this.barItems, function(v){
30085 if (v.rid == item.rid) {
30089 if (v.isActive()) {
30090 v.setActive(false);
30095 item.setActive(true);
30097 this.fireEvent('changed', this, item, prev);
30100 getBarItem: function(rid)
30104 Roo.each(this.barItems, function(e) {
30105 if (e.rid != rid) {
30116 indexOfItem : function(item)
30120 Roo.each(this.barItems, function(v, i){
30122 if (v.rid != item.rid) {
30133 setActiveNext : function()
30135 var i = this.indexOfItem(this.getActive());
30137 if (i > this.barItems.length) {
30141 this.setActiveItem(this.barItems[i+1]);
30144 setActivePrev : function()
30146 var i = this.indexOfItem(this.getActive());
30152 this.setActiveItem(this.barItems[i-1]);
30155 format : function()
30157 if(!this.barItems.length){
30161 var width = 100 / this.barItems.length;
30163 Roo.each(this.barItems, function(i){
30164 i.el.setStyle('width', width + '%');
30165 i.topEl.el.setStyle('width', width + '%');
30166 i.bottomEl.el.setStyle('width', width + '%');
30175 * Nav Progress Item
30180 * @class Roo.bootstrap.NavProgressItem
30181 * @extends Roo.bootstrap.Component
30182 * Bootstrap NavProgressItem class
30183 * @cfg {String} rid the reference id
30184 * @cfg {Boolean} active (true|false) Is item active default false
30185 * @cfg {Boolean} disabled (true|false) Is item active default false
30186 * @cfg {String} html
30187 * @cfg {String} position (top|bottom) text position default bottom
30188 * @cfg {String} icon show icon instead of number
30191 * Create a new NavProgressItem
30192 * @param {Object} config The config object
30194 Roo.bootstrap.NavProgressItem = function(config){
30195 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30200 * The raw click event for the entire grid.
30201 * @param {Roo.bootstrap.NavProgressItem} this
30202 * @param {Roo.EventObject} e
30209 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30215 position : 'bottom',
30218 getAutoCreate : function()
30220 var iconCls = 'roo-navigation-bar-item-icon';
30222 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30226 cls: 'roo-navigation-bar-item',
30236 cfg.cls += ' active';
30239 cfg.cls += ' disabled';
30245 disable : function()
30247 this.setDisabled(true);
30250 enable : function()
30252 this.setDisabled(false);
30255 initEvents: function()
30257 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30259 this.iconEl.on('click', this.onClick, this);
30262 onClick : function(e)
30264 e.preventDefault();
30270 if(this.fireEvent('click', this, e) === false){
30274 this.parent().setActiveItem(this);
30277 isActive: function ()
30279 return this.active;
30282 setActive : function(state)
30284 if(this.active == state){
30288 this.active = state;
30291 this.el.addClass('active');
30295 this.el.removeClass('active');
30300 setDisabled : function(state)
30302 if(this.disabled == state){
30306 this.disabled = state;
30309 this.el.addClass('disabled');
30313 this.el.removeClass('disabled');
30316 tooltipEl : function()
30318 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30331 * @class Roo.bootstrap.FieldLabel
30332 * @extends Roo.bootstrap.Component
30333 * Bootstrap FieldLabel class
30334 * @cfg {String} html contents of the element
30335 * @cfg {String} tag tag of the element default label
30336 * @cfg {String} cls class of the element
30337 * @cfg {String} target label target
30338 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30339 * @cfg {String} invalidClass default "text-warning"
30340 * @cfg {String} validClass default "text-success"
30341 * @cfg {String} iconTooltip default "This field is required"
30342 * @cfg {String} indicatorpos (left|right) default left
30345 * Create a new FieldLabel
30346 * @param {Object} config The config object
30349 Roo.bootstrap.FieldLabel = function(config){
30350 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30355 * Fires after the field has been marked as invalid.
30356 * @param {Roo.form.FieldLabel} this
30357 * @param {String} msg The validation message
30362 * Fires after the field has been validated with no errors.
30363 * @param {Roo.form.FieldLabel} this
30369 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30376 invalidClass : 'has-warning',
30377 validClass : 'has-success',
30378 iconTooltip : 'This field is required',
30379 indicatorpos : 'left',
30381 getAutoCreate : function(){
30384 if (!this.allowBlank) {
30390 cls : 'roo-bootstrap-field-label ' + this.cls,
30395 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30396 tooltip : this.iconTooltip
30405 if(this.indicatorpos == 'right'){
30408 cls : 'roo-bootstrap-field-label ' + this.cls,
30417 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30418 tooltip : this.iconTooltip
30427 initEvents: function()
30429 Roo.bootstrap.Element.superclass.initEvents.call(this);
30431 this.indicator = this.indicatorEl();
30433 if(this.indicator){
30434 this.indicator.removeClass('visible');
30435 this.indicator.addClass('invisible');
30438 Roo.bootstrap.FieldLabel.register(this);
30441 indicatorEl : function()
30443 var indicator = this.el.select('i.roo-required-indicator',true).first();
30454 * Mark this field as valid
30456 markValid : function()
30458 if(this.indicator){
30459 this.indicator.removeClass('visible');
30460 this.indicator.addClass('invisible');
30463 this.el.removeClass(this.invalidClass);
30465 this.el.addClass(this.validClass);
30467 this.fireEvent('valid', this);
30471 * Mark this field as invalid
30472 * @param {String} msg The validation message
30474 markInvalid : function(msg)
30476 if(this.indicator){
30477 this.indicator.removeClass('invisible');
30478 this.indicator.addClass('visible');
30481 this.el.removeClass(this.validClass);
30483 this.el.addClass(this.invalidClass);
30485 this.fireEvent('invalid', this, msg);
30491 Roo.apply(Roo.bootstrap.FieldLabel, {
30496 * register a FieldLabel Group
30497 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30499 register : function(label)
30501 if(this.groups.hasOwnProperty(label.target)){
30505 this.groups[label.target] = label;
30509 * fetch a FieldLabel Group based on the target
30510 * @param {string} target
30511 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30513 get: function(target) {
30514 if (typeof(this.groups[target]) == 'undefined') {
30518 return this.groups[target] ;
30527 * page DateSplitField.
30533 * @class Roo.bootstrap.DateSplitField
30534 * @extends Roo.bootstrap.Component
30535 * Bootstrap DateSplitField class
30536 * @cfg {string} fieldLabel - the label associated
30537 * @cfg {Number} labelWidth set the width of label (0-12)
30538 * @cfg {String} labelAlign (top|left)
30539 * @cfg {Boolean} dayAllowBlank (true|false) default false
30540 * @cfg {Boolean} monthAllowBlank (true|false) default false
30541 * @cfg {Boolean} yearAllowBlank (true|false) default false
30542 * @cfg {string} dayPlaceholder
30543 * @cfg {string} monthPlaceholder
30544 * @cfg {string} yearPlaceholder
30545 * @cfg {string} dayFormat default 'd'
30546 * @cfg {string} monthFormat default 'm'
30547 * @cfg {string} yearFormat default 'Y'
30548 * @cfg {Number} labellg set the width of label (1-12)
30549 * @cfg {Number} labelmd set the width of label (1-12)
30550 * @cfg {Number} labelsm set the width of label (1-12)
30551 * @cfg {Number} labelxs set the width of label (1-12)
30555 * Create a new DateSplitField
30556 * @param {Object} config The config object
30559 Roo.bootstrap.DateSplitField = function(config){
30560 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30566 * getting the data of years
30567 * @param {Roo.bootstrap.DateSplitField} this
30568 * @param {Object} years
30573 * getting the data of days
30574 * @param {Roo.bootstrap.DateSplitField} this
30575 * @param {Object} days
30580 * Fires after the field has been marked as invalid.
30581 * @param {Roo.form.Field} this
30582 * @param {String} msg The validation message
30587 * Fires after the field has been validated with no errors.
30588 * @param {Roo.form.Field} this
30594 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30597 labelAlign : 'top',
30599 dayAllowBlank : false,
30600 monthAllowBlank : false,
30601 yearAllowBlank : false,
30602 dayPlaceholder : '',
30603 monthPlaceholder : '',
30604 yearPlaceholder : '',
30608 isFormField : true,
30614 getAutoCreate : function()
30618 cls : 'row roo-date-split-field-group',
30623 cls : 'form-hidden-field roo-date-split-field-group-value',
30629 var labelCls = 'col-md-12';
30630 var contentCls = 'col-md-4';
30632 if(this.fieldLabel){
30636 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30640 html : this.fieldLabel
30645 if(this.labelAlign == 'left'){
30647 if(this.labelWidth > 12){
30648 label.style = "width: " + this.labelWidth + 'px';
30651 if(this.labelWidth < 13 && this.labelmd == 0){
30652 this.labelmd = this.labelWidth;
30655 if(this.labellg > 0){
30656 labelCls = ' col-lg-' + this.labellg;
30657 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30660 if(this.labelmd > 0){
30661 labelCls = ' col-md-' + this.labelmd;
30662 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30665 if(this.labelsm > 0){
30666 labelCls = ' col-sm-' + this.labelsm;
30667 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30670 if(this.labelxs > 0){
30671 labelCls = ' col-xs-' + this.labelxs;
30672 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30676 label.cls += ' ' + labelCls;
30678 cfg.cn.push(label);
30681 Roo.each(['day', 'month', 'year'], function(t){
30684 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30691 inputEl: function ()
30693 return this.el.select('.roo-date-split-field-group-value', true).first();
30696 onRender : function(ct, position)
30700 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30702 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30704 this.dayField = new Roo.bootstrap.ComboBox({
30705 allowBlank : this.dayAllowBlank,
30706 alwaysQuery : true,
30707 displayField : 'value',
30710 forceSelection : true,
30712 placeholder : this.dayPlaceholder,
30713 selectOnFocus : true,
30714 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30715 triggerAction : 'all',
30717 valueField : 'value',
30718 store : new Roo.data.SimpleStore({
30719 data : (function() {
30721 _this.fireEvent('days', _this, days);
30724 fields : [ 'value' ]
30727 select : function (_self, record, index)
30729 _this.setValue(_this.getValue());
30734 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30736 this.monthField = new Roo.bootstrap.MonthField({
30737 after : '<i class=\"fa fa-calendar\"></i>',
30738 allowBlank : this.monthAllowBlank,
30739 placeholder : this.monthPlaceholder,
30742 render : function (_self)
30744 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30745 e.preventDefault();
30749 select : function (_self, oldvalue, newvalue)
30751 _this.setValue(_this.getValue());
30756 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30758 this.yearField = new Roo.bootstrap.ComboBox({
30759 allowBlank : this.yearAllowBlank,
30760 alwaysQuery : true,
30761 displayField : 'value',
30764 forceSelection : true,
30766 placeholder : this.yearPlaceholder,
30767 selectOnFocus : true,
30768 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30769 triggerAction : 'all',
30771 valueField : 'value',
30772 store : new Roo.data.SimpleStore({
30773 data : (function() {
30775 _this.fireEvent('years', _this, years);
30778 fields : [ 'value' ]
30781 select : function (_self, record, index)
30783 _this.setValue(_this.getValue());
30788 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30791 setValue : function(v, format)
30793 this.inputEl.dom.value = v;
30795 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30797 var d = Date.parseDate(v, f);
30804 this.setDay(d.format(this.dayFormat));
30805 this.setMonth(d.format(this.monthFormat));
30806 this.setYear(d.format(this.yearFormat));
30813 setDay : function(v)
30815 this.dayField.setValue(v);
30816 this.inputEl.dom.value = this.getValue();
30821 setMonth : function(v)
30823 this.monthField.setValue(v, true);
30824 this.inputEl.dom.value = this.getValue();
30829 setYear : function(v)
30831 this.yearField.setValue(v);
30832 this.inputEl.dom.value = this.getValue();
30837 getDay : function()
30839 return this.dayField.getValue();
30842 getMonth : function()
30844 return this.monthField.getValue();
30847 getYear : function()
30849 return this.yearField.getValue();
30852 getValue : function()
30854 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30856 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30866 this.inputEl.dom.value = '';
30871 validate : function()
30873 var d = this.dayField.validate();
30874 var m = this.monthField.validate();
30875 var y = this.yearField.validate();
30880 (!this.dayAllowBlank && !d) ||
30881 (!this.monthAllowBlank && !m) ||
30882 (!this.yearAllowBlank && !y)
30887 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30896 this.markInvalid();
30901 markValid : function()
30904 var label = this.el.select('label', true).first();
30905 var icon = this.el.select('i.fa-star', true).first();
30911 this.fireEvent('valid', this);
30915 * Mark this field as invalid
30916 * @param {String} msg The validation message
30918 markInvalid : function(msg)
30921 var label = this.el.select('label', true).first();
30922 var icon = this.el.select('i.fa-star', true).first();
30924 if(label && !icon){
30925 this.el.select('.roo-date-split-field-label', true).createChild({
30927 cls : 'text-danger fa fa-lg fa-star',
30928 tooltip : 'This field is required',
30929 style : 'margin-right:5px;'
30933 this.fireEvent('invalid', this, msg);
30936 clearInvalid : function()
30938 var label = this.el.select('label', true).first();
30939 var icon = this.el.select('i.fa-star', true).first();
30945 this.fireEvent('valid', this);
30948 getName: function()
30958 * http://masonry.desandro.com
30960 * The idea is to render all the bricks based on vertical width...
30962 * The original code extends 'outlayer' - we might need to use that....
30968 * @class Roo.bootstrap.LayoutMasonry
30969 * @extends Roo.bootstrap.Component
30970 * Bootstrap Layout Masonry class
30973 * Create a new Element
30974 * @param {Object} config The config object
30977 Roo.bootstrap.LayoutMasonry = function(config){
30979 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30983 Roo.bootstrap.LayoutMasonry.register(this);
30989 * Fire after layout the items
30990 * @param {Roo.bootstrap.LayoutMasonry} this
30991 * @param {Roo.EventObject} e
30998 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31001 * @cfg {Boolean} isLayoutInstant = no animation?
31003 isLayoutInstant : false, // needed?
31006 * @cfg {Number} boxWidth width of the columns
31011 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31016 * @cfg {Number} padWidth padding below box..
31021 * @cfg {Number} gutter gutter width..
31026 * @cfg {Number} maxCols maximum number of columns
31032 * @cfg {Boolean} isAutoInitial defalut true
31034 isAutoInitial : true,
31039 * @cfg {Boolean} isHorizontal defalut false
31041 isHorizontal : false,
31043 currentSize : null,
31049 bricks: null, //CompositeElement
31053 _isLayoutInited : false,
31055 // isAlternative : false, // only use for vertical layout...
31058 * @cfg {Number} alternativePadWidth padding below box..
31060 alternativePadWidth : 50,
31062 selectedBrick : [],
31064 getAutoCreate : function(){
31066 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31070 cls: 'blog-masonary-wrapper ' + this.cls,
31072 cls : 'mas-boxes masonary'
31079 getChildContainer: function( )
31081 if (this.boxesEl) {
31082 return this.boxesEl;
31085 this.boxesEl = this.el.select('.mas-boxes').first();
31087 return this.boxesEl;
31091 initEvents : function()
31095 if(this.isAutoInitial){
31096 Roo.log('hook children rendered');
31097 this.on('childrenrendered', function() {
31098 Roo.log('children rendered');
31104 initial : function()
31106 this.selectedBrick = [];
31108 this.currentSize = this.el.getBox(true);
31110 Roo.EventManager.onWindowResize(this.resize, this);
31112 if(!this.isAutoInitial){
31120 //this.layout.defer(500,this);
31124 resize : function()
31126 var cs = this.el.getBox(true);
31129 this.currentSize.width == cs.width &&
31130 this.currentSize.x == cs.x &&
31131 this.currentSize.height == cs.height &&
31132 this.currentSize.y == cs.y
31134 Roo.log("no change in with or X or Y");
31138 this.currentSize = cs;
31144 layout : function()
31146 this._resetLayout();
31148 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31150 this.layoutItems( isInstant );
31152 this._isLayoutInited = true;
31154 this.fireEvent('layout', this);
31158 _resetLayout : function()
31160 if(this.isHorizontal){
31161 this.horizontalMeasureColumns();
31165 this.verticalMeasureColumns();
31169 verticalMeasureColumns : function()
31171 this.getContainerWidth();
31173 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31174 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31178 var boxWidth = this.boxWidth + this.padWidth;
31180 if(this.containerWidth < this.boxWidth){
31181 boxWidth = this.containerWidth
31184 var containerWidth = this.containerWidth;
31186 var cols = Math.floor(containerWidth / boxWidth);
31188 this.cols = Math.max( cols, 1 );
31190 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31192 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31194 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31196 this.colWidth = boxWidth + avail - this.padWidth;
31198 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31199 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31202 horizontalMeasureColumns : function()
31204 this.getContainerWidth();
31206 var boxWidth = this.boxWidth;
31208 if(this.containerWidth < boxWidth){
31209 boxWidth = this.containerWidth;
31212 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31214 this.el.setHeight(boxWidth);
31218 getContainerWidth : function()
31220 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31223 layoutItems : function( isInstant )
31225 Roo.log(this.bricks);
31227 var items = Roo.apply([], this.bricks);
31229 if(this.isHorizontal){
31230 this._horizontalLayoutItems( items , isInstant );
31234 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31235 // this._verticalAlternativeLayoutItems( items , isInstant );
31239 this._verticalLayoutItems( items , isInstant );
31243 _verticalLayoutItems : function ( items , isInstant)
31245 if ( !items || !items.length ) {
31250 ['xs', 'xs', 'xs', 'tall'],
31251 ['xs', 'xs', 'tall'],
31252 ['xs', 'xs', 'sm'],
31253 ['xs', 'xs', 'xs'],
31259 ['sm', 'xs', 'xs'],
31263 ['tall', 'xs', 'xs', 'xs'],
31264 ['tall', 'xs', 'xs'],
31276 Roo.each(items, function(item, k){
31278 switch (item.size) {
31279 // these layouts take up a full box,
31290 boxes.push([item]);
31313 var filterPattern = function(box, length)
31321 var pattern = box.slice(0, length);
31325 Roo.each(pattern, function(i){
31326 format.push(i.size);
31329 Roo.each(standard, function(s){
31331 if(String(s) != String(format)){
31340 if(!match && length == 1){
31345 filterPattern(box, length - 1);
31349 queue.push(pattern);
31351 box = box.slice(length, box.length);
31353 filterPattern(box, 4);
31359 Roo.each(boxes, function(box, k){
31365 if(box.length == 1){
31370 filterPattern(box, 4);
31374 this._processVerticalLayoutQueue( queue, isInstant );
31378 // _verticalAlternativeLayoutItems : function( items , isInstant )
31380 // if ( !items || !items.length ) {
31384 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31388 _horizontalLayoutItems : function ( items , isInstant)
31390 if ( !items || !items.length || items.length < 3) {
31396 var eItems = items.slice(0, 3);
31398 items = items.slice(3, items.length);
31401 ['xs', 'xs', 'xs', 'wide'],
31402 ['xs', 'xs', 'wide'],
31403 ['xs', 'xs', 'sm'],
31404 ['xs', 'xs', 'xs'],
31410 ['sm', 'xs', 'xs'],
31414 ['wide', 'xs', 'xs', 'xs'],
31415 ['wide', 'xs', 'xs'],
31428 Roo.each(items, function(item, k){
31430 switch (item.size) {
31441 boxes.push([item]);
31465 var filterPattern = function(box, length)
31473 var pattern = box.slice(0, length);
31477 Roo.each(pattern, function(i){
31478 format.push(i.size);
31481 Roo.each(standard, function(s){
31483 if(String(s) != String(format)){
31492 if(!match && length == 1){
31497 filterPattern(box, length - 1);
31501 queue.push(pattern);
31503 box = box.slice(length, box.length);
31505 filterPattern(box, 4);
31511 Roo.each(boxes, function(box, k){
31517 if(box.length == 1){
31522 filterPattern(box, 4);
31529 var pos = this.el.getBox(true);
31533 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31535 var hit_end = false;
31537 Roo.each(queue, function(box){
31541 Roo.each(box, function(b){
31543 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31553 Roo.each(box, function(b){
31555 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31558 mx = Math.max(mx, b.x);
31562 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31566 Roo.each(box, function(b){
31568 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31582 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31585 /** Sets position of item in DOM
31586 * @param {Element} item
31587 * @param {Number} x - horizontal position
31588 * @param {Number} y - vertical position
31589 * @param {Boolean} isInstant - disables transitions
31591 _processVerticalLayoutQueue : function( queue, isInstant )
31593 var pos = this.el.getBox(true);
31598 for (var i = 0; i < this.cols; i++){
31602 Roo.each(queue, function(box, k){
31604 var col = k % this.cols;
31606 Roo.each(box, function(b,kk){
31608 b.el.position('absolute');
31610 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31611 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31613 if(b.size == 'md-left' || b.size == 'md-right'){
31614 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31615 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31618 b.el.setWidth(width);
31619 b.el.setHeight(height);
31621 b.el.select('iframe',true).setSize(width,height);
31625 for (var i = 0; i < this.cols; i++){
31627 if(maxY[i] < maxY[col]){
31632 col = Math.min(col, i);
31636 x = pos.x + col * (this.colWidth + this.padWidth);
31640 var positions = [];
31642 switch (box.length){
31644 positions = this.getVerticalOneBoxColPositions(x, y, box);
31647 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31650 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31653 positions = this.getVerticalFourBoxColPositions(x, y, box);
31659 Roo.each(box, function(b,kk){
31661 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31663 var sz = b.el.getSize();
31665 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31673 for (var i = 0; i < this.cols; i++){
31674 mY = Math.max(mY, maxY[i]);
31677 this.el.setHeight(mY - pos.y);
31681 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31683 // var pos = this.el.getBox(true);
31686 // var maxX = pos.right;
31688 // var maxHeight = 0;
31690 // Roo.each(items, function(item, k){
31694 // item.el.position('absolute');
31696 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31698 // item.el.setWidth(width);
31700 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31702 // item.el.setHeight(height);
31705 // item.el.setXY([x, y], isInstant ? false : true);
31707 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31710 // y = y + height + this.alternativePadWidth;
31712 // maxHeight = maxHeight + height + this.alternativePadWidth;
31716 // this.el.setHeight(maxHeight);
31720 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31722 var pos = this.el.getBox(true);
31727 var maxX = pos.right;
31729 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31731 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31733 Roo.each(queue, function(box, k){
31735 Roo.each(box, function(b, kk){
31737 b.el.position('absolute');
31739 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31740 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31742 if(b.size == 'md-left' || b.size == 'md-right'){
31743 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31744 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31747 b.el.setWidth(width);
31748 b.el.setHeight(height);
31756 var positions = [];
31758 switch (box.length){
31760 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31763 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31766 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31769 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31775 Roo.each(box, function(b,kk){
31777 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31779 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31787 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31789 Roo.each(eItems, function(b,k){
31791 b.size = (k == 0) ? 'sm' : 'xs';
31792 b.x = (k == 0) ? 2 : 1;
31793 b.y = (k == 0) ? 2 : 1;
31795 b.el.position('absolute');
31797 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31799 b.el.setWidth(width);
31801 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31803 b.el.setHeight(height);
31807 var positions = [];
31810 x : maxX - this.unitWidth * 2 - this.gutter,
31815 x : maxX - this.unitWidth,
31816 y : minY + (this.unitWidth + this.gutter) * 2
31820 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31824 Roo.each(eItems, function(b,k){
31826 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31832 getVerticalOneBoxColPositions : function(x, y, box)
31836 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31838 if(box[0].size == 'md-left'){
31842 if(box[0].size == 'md-right'){
31847 x : x + (this.unitWidth + this.gutter) * rand,
31854 getVerticalTwoBoxColPositions : function(x, y, box)
31858 if(box[0].size == 'xs'){
31862 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31866 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31880 x : x + (this.unitWidth + this.gutter) * 2,
31881 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31888 getVerticalThreeBoxColPositions : function(x, y, box)
31892 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31900 x : x + (this.unitWidth + this.gutter) * 1,
31905 x : x + (this.unitWidth + this.gutter) * 2,
31913 if(box[0].size == 'xs' && box[1].size == 'xs'){
31922 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31926 x : x + (this.unitWidth + this.gutter) * 1,
31940 x : x + (this.unitWidth + this.gutter) * 2,
31945 x : x + (this.unitWidth + this.gutter) * 2,
31946 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31953 getVerticalFourBoxColPositions : function(x, y, box)
31957 if(box[0].size == 'xs'){
31966 y : y + (this.unitHeight + this.gutter) * 1
31971 y : y + (this.unitHeight + this.gutter) * 2
31975 x : x + (this.unitWidth + this.gutter) * 1,
31989 x : x + (this.unitWidth + this.gutter) * 2,
31994 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31995 y : y + (this.unitHeight + this.gutter) * 1
31999 x : x + (this.unitWidth + this.gutter) * 2,
32000 y : y + (this.unitWidth + this.gutter) * 2
32007 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32011 if(box[0].size == 'md-left'){
32013 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32020 if(box[0].size == 'md-right'){
32022 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32023 y : minY + (this.unitWidth + this.gutter) * 1
32029 var rand = Math.floor(Math.random() * (4 - box[0].y));
32032 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32033 y : minY + (this.unitWidth + this.gutter) * rand
32040 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32044 if(box[0].size == 'xs'){
32047 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32052 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32053 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32061 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32066 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32067 y : minY + (this.unitWidth + this.gutter) * 2
32074 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32078 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32081 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32086 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32087 y : minY + (this.unitWidth + this.gutter) * 1
32091 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32092 y : minY + (this.unitWidth + this.gutter) * 2
32099 if(box[0].size == 'xs' && box[1].size == 'xs'){
32102 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32107 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32112 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32113 y : minY + (this.unitWidth + this.gutter) * 1
32121 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32126 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32127 y : minY + (this.unitWidth + this.gutter) * 2
32131 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32132 y : minY + (this.unitWidth + this.gutter) * 2
32139 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32143 if(box[0].size == 'xs'){
32146 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32151 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32156 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),
32161 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32162 y : minY + (this.unitWidth + this.gutter) * 1
32170 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32175 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32176 y : minY + (this.unitWidth + this.gutter) * 2
32180 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32181 y : minY + (this.unitWidth + this.gutter) * 2
32185 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),
32186 y : minY + (this.unitWidth + this.gutter) * 2
32194 * remove a Masonry Brick
32195 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32197 removeBrick : function(brick_id)
32203 for (var i = 0; i<this.bricks.length; i++) {
32204 if (this.bricks[i].id == brick_id) {
32205 this.bricks.splice(i,1);
32206 this.el.dom.removeChild(Roo.get(brick_id).dom);
32213 * adds a Masonry Brick
32214 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32216 addBrick : function(cfg)
32218 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32219 //this.register(cn);
32220 cn.parentId = this.id;
32221 cn.render(this.el);
32226 * register a Masonry Brick
32227 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32230 register : function(brick)
32232 this.bricks.push(brick);
32233 brick.masonryId = this.id;
32237 * clear all the Masonry Brick
32239 clearAll : function()
32242 //this.getChildContainer().dom.innerHTML = "";
32243 this.el.dom.innerHTML = '';
32246 getSelected : function()
32248 if (!this.selectedBrick) {
32252 return this.selectedBrick;
32256 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32260 * register a Masonry Layout
32261 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32264 register : function(layout)
32266 this.groups[layout.id] = layout;
32269 * fetch a Masonry Layout based on the masonry layout ID
32270 * @param {string} the masonry layout to add
32271 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32274 get: function(layout_id) {
32275 if (typeof(this.groups[layout_id]) == 'undefined') {
32278 return this.groups[layout_id] ;
32290 * http://masonry.desandro.com
32292 * The idea is to render all the bricks based on vertical width...
32294 * The original code extends 'outlayer' - we might need to use that....
32300 * @class Roo.bootstrap.LayoutMasonryAuto
32301 * @extends Roo.bootstrap.Component
32302 * Bootstrap Layout Masonry class
32305 * Create a new Element
32306 * @param {Object} config The config object
32309 Roo.bootstrap.LayoutMasonryAuto = function(config){
32310 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32313 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32316 * @cfg {Boolean} isFitWidth - resize the width..
32318 isFitWidth : false, // options..
32320 * @cfg {Boolean} isOriginLeft = left align?
32322 isOriginLeft : true,
32324 * @cfg {Boolean} isOriginTop = top align?
32326 isOriginTop : false,
32328 * @cfg {Boolean} isLayoutInstant = no animation?
32330 isLayoutInstant : false, // needed?
32332 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32334 isResizingContainer : true,
32336 * @cfg {Number} columnWidth width of the columns
32342 * @cfg {Number} maxCols maximum number of columns
32347 * @cfg {Number} padHeight padding below box..
32353 * @cfg {Boolean} isAutoInitial defalut true
32356 isAutoInitial : true,
32362 initialColumnWidth : 0,
32363 currentSize : null,
32365 colYs : null, // array.
32372 bricks: null, //CompositeElement
32373 cols : 0, // array?
32374 // element : null, // wrapped now this.el
32375 _isLayoutInited : null,
32378 getAutoCreate : function(){
32382 cls: 'blog-masonary-wrapper ' + this.cls,
32384 cls : 'mas-boxes masonary'
32391 getChildContainer: function( )
32393 if (this.boxesEl) {
32394 return this.boxesEl;
32397 this.boxesEl = this.el.select('.mas-boxes').first();
32399 return this.boxesEl;
32403 initEvents : function()
32407 if(this.isAutoInitial){
32408 Roo.log('hook children rendered');
32409 this.on('childrenrendered', function() {
32410 Roo.log('children rendered');
32417 initial : function()
32419 this.reloadItems();
32421 this.currentSize = this.el.getBox(true);
32423 /// was window resize... - let's see if this works..
32424 Roo.EventManager.onWindowResize(this.resize, this);
32426 if(!this.isAutoInitial){
32431 this.layout.defer(500,this);
32434 reloadItems: function()
32436 this.bricks = this.el.select('.masonry-brick', true);
32438 this.bricks.each(function(b) {
32439 //Roo.log(b.getSize());
32440 if (!b.attr('originalwidth')) {
32441 b.attr('originalwidth', b.getSize().width);
32446 Roo.log(this.bricks.elements.length);
32449 resize : function()
32452 var cs = this.el.getBox(true);
32454 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32455 Roo.log("no change in with or X");
32458 this.currentSize = cs;
32462 layout : function()
32465 this._resetLayout();
32466 //this._manageStamps();
32468 // don't animate first layout
32469 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32470 this.layoutItems( isInstant );
32472 // flag for initalized
32473 this._isLayoutInited = true;
32476 layoutItems : function( isInstant )
32478 //var items = this._getItemsForLayout( this.items );
32479 // original code supports filtering layout items.. we just ignore it..
32481 this._layoutItems( this.bricks , isInstant );
32483 this._postLayout();
32485 _layoutItems : function ( items , isInstant)
32487 //this.fireEvent( 'layout', this, items );
32490 if ( !items || !items.elements.length ) {
32491 // no items, emit event with empty array
32496 items.each(function(item) {
32497 Roo.log("layout item");
32499 // get x/y object from method
32500 var position = this._getItemLayoutPosition( item );
32502 position.item = item;
32503 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32504 queue.push( position );
32507 this._processLayoutQueue( queue );
32509 /** Sets position of item in DOM
32510 * @param {Element} item
32511 * @param {Number} x - horizontal position
32512 * @param {Number} y - vertical position
32513 * @param {Boolean} isInstant - disables transitions
32515 _processLayoutQueue : function( queue )
32517 for ( var i=0, len = queue.length; i < len; i++ ) {
32518 var obj = queue[i];
32519 obj.item.position('absolute');
32520 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32526 * Any logic you want to do after each layout,
32527 * i.e. size the container
32529 _postLayout : function()
32531 this.resizeContainer();
32534 resizeContainer : function()
32536 if ( !this.isResizingContainer ) {
32539 var size = this._getContainerSize();
32541 this.el.setSize(size.width,size.height);
32542 this.boxesEl.setSize(size.width,size.height);
32548 _resetLayout : function()
32550 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32551 this.colWidth = this.el.getWidth();
32552 //this.gutter = this.el.getWidth();
32554 this.measureColumns();
32560 this.colYs.push( 0 );
32566 measureColumns : function()
32568 this.getContainerWidth();
32569 // if columnWidth is 0, default to outerWidth of first item
32570 if ( !this.columnWidth ) {
32571 var firstItem = this.bricks.first();
32572 Roo.log(firstItem);
32573 this.columnWidth = this.containerWidth;
32574 if (firstItem && firstItem.attr('originalwidth') ) {
32575 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32577 // columnWidth fall back to item of first element
32578 Roo.log("set column width?");
32579 this.initialColumnWidth = this.columnWidth ;
32581 // if first elem has no width, default to size of container
32586 if (this.initialColumnWidth) {
32587 this.columnWidth = this.initialColumnWidth;
32592 // column width is fixed at the top - however if container width get's smaller we should
32595 // this bit calcs how man columns..
32597 var columnWidth = this.columnWidth += this.gutter;
32599 // calculate columns
32600 var containerWidth = this.containerWidth + this.gutter;
32602 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32603 // fix rounding errors, typically with gutters
32604 var excess = columnWidth - containerWidth % columnWidth;
32607 // if overshoot is less than a pixel, round up, otherwise floor it
32608 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32609 cols = Math[ mathMethod ]( cols );
32610 this.cols = Math.max( cols, 1 );
32611 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32613 // padding positioning..
32614 var totalColWidth = this.cols * this.columnWidth;
32615 var padavail = this.containerWidth - totalColWidth;
32616 // so for 2 columns - we need 3 'pads'
32618 var padNeeded = (1+this.cols) * this.padWidth;
32620 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32622 this.columnWidth += padExtra
32623 //this.padWidth = Math.floor(padavail / ( this.cols));
32625 // adjust colum width so that padding is fixed??
32627 // we have 3 columns ... total = width * 3
32628 // we have X left over... that should be used by
32630 //if (this.expandC) {
32638 getContainerWidth : function()
32640 /* // container is parent if fit width
32641 var container = this.isFitWidth ? this.element.parentNode : this.element;
32642 // check that this.size and size are there
32643 // IE8 triggers resize on body size change, so they might not be
32645 var size = getSize( container ); //FIXME
32646 this.containerWidth = size && size.innerWidth; //FIXME
32649 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32653 _getItemLayoutPosition : function( item ) // what is item?
32655 // we resize the item to our columnWidth..
32657 item.setWidth(this.columnWidth);
32658 item.autoBoxAdjust = false;
32660 var sz = item.getSize();
32662 // how many columns does this brick span
32663 var remainder = this.containerWidth % this.columnWidth;
32665 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32666 // round if off by 1 pixel, otherwise use ceil
32667 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32668 colSpan = Math.min( colSpan, this.cols );
32670 // normally this should be '1' as we dont' currently allow multi width columns..
32672 var colGroup = this._getColGroup( colSpan );
32673 // get the minimum Y value from the columns
32674 var minimumY = Math.min.apply( Math, colGroup );
32675 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32677 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32679 // position the brick
32681 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32682 y: this.currentSize.y + minimumY + this.padHeight
32686 // apply setHeight to necessary columns
32687 var setHeight = minimumY + sz.height + this.padHeight;
32688 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32690 var setSpan = this.cols + 1 - colGroup.length;
32691 for ( var i = 0; i < setSpan; i++ ) {
32692 this.colYs[ shortColIndex + i ] = setHeight ;
32699 * @param {Number} colSpan - number of columns the element spans
32700 * @returns {Array} colGroup
32702 _getColGroup : function( colSpan )
32704 if ( colSpan < 2 ) {
32705 // if brick spans only one column, use all the column Ys
32710 // how many different places could this brick fit horizontally
32711 var groupCount = this.cols + 1 - colSpan;
32712 // for each group potential horizontal position
32713 for ( var i = 0; i < groupCount; i++ ) {
32714 // make an array of colY values for that one group
32715 var groupColYs = this.colYs.slice( i, i + colSpan );
32716 // and get the max value of the array
32717 colGroup[i] = Math.max.apply( Math, groupColYs );
32722 _manageStamp : function( stamp )
32724 var stampSize = stamp.getSize();
32725 var offset = stamp.getBox();
32726 // get the columns that this stamp affects
32727 var firstX = this.isOriginLeft ? offset.x : offset.right;
32728 var lastX = firstX + stampSize.width;
32729 var firstCol = Math.floor( firstX / this.columnWidth );
32730 firstCol = Math.max( 0, firstCol );
32732 var lastCol = Math.floor( lastX / this.columnWidth );
32733 // lastCol should not go over if multiple of columnWidth #425
32734 lastCol -= lastX % this.columnWidth ? 0 : 1;
32735 lastCol = Math.min( this.cols - 1, lastCol );
32737 // set colYs to bottom of the stamp
32738 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32741 for ( var i = firstCol; i <= lastCol; i++ ) {
32742 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32747 _getContainerSize : function()
32749 this.maxY = Math.max.apply( Math, this.colYs );
32754 if ( this.isFitWidth ) {
32755 size.width = this._getContainerFitWidth();
32761 _getContainerFitWidth : function()
32763 var unusedCols = 0;
32764 // count unused columns
32767 if ( this.colYs[i] !== 0 ) {
32772 // fit container to columns that have been used
32773 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32776 needsResizeLayout : function()
32778 var previousWidth = this.containerWidth;
32779 this.getContainerWidth();
32780 return previousWidth !== this.containerWidth;
32795 * @class Roo.bootstrap.MasonryBrick
32796 * @extends Roo.bootstrap.Component
32797 * Bootstrap MasonryBrick class
32800 * Create a new MasonryBrick
32801 * @param {Object} config The config object
32804 Roo.bootstrap.MasonryBrick = function(config){
32806 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32808 Roo.bootstrap.MasonryBrick.register(this);
32814 * When a MasonryBrick is clcik
32815 * @param {Roo.bootstrap.MasonryBrick} this
32816 * @param {Roo.EventObject} e
32822 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32825 * @cfg {String} title
32829 * @cfg {String} html
32833 * @cfg {String} bgimage
32837 * @cfg {String} videourl
32841 * @cfg {String} cls
32845 * @cfg {String} href
32849 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32854 * @cfg {String} placetitle (center|bottom)
32859 * @cfg {Boolean} isFitContainer defalut true
32861 isFitContainer : true,
32864 * @cfg {Boolean} preventDefault defalut false
32866 preventDefault : false,
32869 * @cfg {Boolean} inverse defalut false
32871 maskInverse : false,
32873 getAutoCreate : function()
32875 if(!this.isFitContainer){
32876 return this.getSplitAutoCreate();
32879 var cls = 'masonry-brick masonry-brick-full';
32881 if(this.href.length){
32882 cls += ' masonry-brick-link';
32885 if(this.bgimage.length){
32886 cls += ' masonry-brick-image';
32889 if(this.maskInverse){
32890 cls += ' mask-inverse';
32893 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32894 cls += ' enable-mask';
32898 cls += ' masonry-' + this.size + '-brick';
32901 if(this.placetitle.length){
32903 switch (this.placetitle) {
32905 cls += ' masonry-center-title';
32908 cls += ' masonry-bottom-title';
32915 if(!this.html.length && !this.bgimage.length){
32916 cls += ' masonry-center-title';
32919 if(!this.html.length && this.bgimage.length){
32920 cls += ' masonry-bottom-title';
32925 cls += ' ' + this.cls;
32929 tag: (this.href.length) ? 'a' : 'div',
32934 cls: 'masonry-brick-mask'
32938 cls: 'masonry-brick-paragraph',
32944 if(this.href.length){
32945 cfg.href = this.href;
32948 var cn = cfg.cn[1].cn;
32950 if(this.title.length){
32953 cls: 'masonry-brick-title',
32958 if(this.html.length){
32961 cls: 'masonry-brick-text',
32966 if (!this.title.length && !this.html.length) {
32967 cfg.cn[1].cls += ' hide';
32970 if(this.bgimage.length){
32973 cls: 'masonry-brick-image-view',
32978 if(this.videourl.length){
32979 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32980 // youtube support only?
32983 cls: 'masonry-brick-image-view',
32986 allowfullscreen : true
32994 getSplitAutoCreate : function()
32996 var cls = 'masonry-brick masonry-brick-split';
32998 if(this.href.length){
32999 cls += ' masonry-brick-link';
33002 if(this.bgimage.length){
33003 cls += ' masonry-brick-image';
33007 cls += ' masonry-' + this.size + '-brick';
33010 switch (this.placetitle) {
33012 cls += ' masonry-center-title';
33015 cls += ' masonry-bottom-title';
33018 if(!this.bgimage.length){
33019 cls += ' masonry-center-title';
33022 if(this.bgimage.length){
33023 cls += ' masonry-bottom-title';
33029 cls += ' ' + this.cls;
33033 tag: (this.href.length) ? 'a' : 'div',
33038 cls: 'masonry-brick-split-head',
33042 cls: 'masonry-brick-paragraph',
33049 cls: 'masonry-brick-split-body',
33055 if(this.href.length){
33056 cfg.href = this.href;
33059 if(this.title.length){
33060 cfg.cn[0].cn[0].cn.push({
33062 cls: 'masonry-brick-title',
33067 if(this.html.length){
33068 cfg.cn[1].cn.push({
33070 cls: 'masonry-brick-text',
33075 if(this.bgimage.length){
33076 cfg.cn[0].cn.push({
33078 cls: 'masonry-brick-image-view',
33083 if(this.videourl.length){
33084 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33085 // youtube support only?
33086 cfg.cn[0].cn.cn.push({
33088 cls: 'masonry-brick-image-view',
33091 allowfullscreen : true
33098 initEvents: function()
33100 switch (this.size) {
33133 this.el.on('touchstart', this.onTouchStart, this);
33134 this.el.on('touchmove', this.onTouchMove, this);
33135 this.el.on('touchend', this.onTouchEnd, this);
33136 this.el.on('contextmenu', this.onContextMenu, this);
33138 this.el.on('mouseenter' ,this.enter, this);
33139 this.el.on('mouseleave', this.leave, this);
33140 this.el.on('click', this.onClick, this);
33143 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33144 this.parent().bricks.push(this);
33149 onClick: function(e, el)
33151 var time = this.endTimer - this.startTimer;
33152 // Roo.log(e.preventDefault());
33155 e.preventDefault();
33160 if(!this.preventDefault){
33164 e.preventDefault();
33166 if (this.activeClass != '') {
33167 this.selectBrick();
33170 this.fireEvent('click', this, e);
33173 enter: function(e, el)
33175 e.preventDefault();
33177 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33181 if(this.bgimage.length && this.html.length){
33182 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33186 leave: function(e, el)
33188 e.preventDefault();
33190 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33194 if(this.bgimage.length && this.html.length){
33195 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33199 onTouchStart: function(e, el)
33201 // e.preventDefault();
33203 this.touchmoved = false;
33205 if(!this.isFitContainer){
33209 if(!this.bgimage.length || !this.html.length){
33213 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33215 this.timer = new Date().getTime();
33219 onTouchMove: function(e, el)
33221 this.touchmoved = true;
33224 onContextMenu : function(e,el)
33226 e.preventDefault();
33227 e.stopPropagation();
33231 onTouchEnd: function(e, el)
33233 // e.preventDefault();
33235 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33242 if(!this.bgimage.length || !this.html.length){
33244 if(this.href.length){
33245 window.location.href = this.href;
33251 if(!this.isFitContainer){
33255 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33257 window.location.href = this.href;
33260 //selection on single brick only
33261 selectBrick : function() {
33263 if (!this.parentId) {
33267 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33268 var index = m.selectedBrick.indexOf(this.id);
33271 m.selectedBrick.splice(index,1);
33272 this.el.removeClass(this.activeClass);
33276 for(var i = 0; i < m.selectedBrick.length; i++) {
33277 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33278 b.el.removeClass(b.activeClass);
33281 m.selectedBrick = [];
33283 m.selectedBrick.push(this.id);
33284 this.el.addClass(this.activeClass);
33288 isSelected : function(){
33289 return this.el.hasClass(this.activeClass);
33294 Roo.apply(Roo.bootstrap.MasonryBrick, {
33297 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33299 * register a Masonry Brick
33300 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33303 register : function(brick)
33305 //this.groups[brick.id] = brick;
33306 this.groups.add(brick.id, brick);
33309 * fetch a masonry brick based on the masonry brick ID
33310 * @param {string} the masonry brick to add
33311 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33314 get: function(brick_id)
33316 // if (typeof(this.groups[brick_id]) == 'undefined') {
33319 // return this.groups[brick_id] ;
33321 if(this.groups.key(brick_id)) {
33322 return this.groups.key(brick_id);
33340 * @class Roo.bootstrap.Brick
33341 * @extends Roo.bootstrap.Component
33342 * Bootstrap Brick class
33345 * Create a new Brick
33346 * @param {Object} config The config object
33349 Roo.bootstrap.Brick = function(config){
33350 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33356 * When a Brick is click
33357 * @param {Roo.bootstrap.Brick} this
33358 * @param {Roo.EventObject} e
33364 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33367 * @cfg {String} title
33371 * @cfg {String} html
33375 * @cfg {String} bgimage
33379 * @cfg {String} cls
33383 * @cfg {String} href
33387 * @cfg {String} video
33391 * @cfg {Boolean} square
33395 getAutoCreate : function()
33397 var cls = 'roo-brick';
33399 if(this.href.length){
33400 cls += ' roo-brick-link';
33403 if(this.bgimage.length){
33404 cls += ' roo-brick-image';
33407 if(!this.html.length && !this.bgimage.length){
33408 cls += ' roo-brick-center-title';
33411 if(!this.html.length && this.bgimage.length){
33412 cls += ' roo-brick-bottom-title';
33416 cls += ' ' + this.cls;
33420 tag: (this.href.length) ? 'a' : 'div',
33425 cls: 'roo-brick-paragraph',
33431 if(this.href.length){
33432 cfg.href = this.href;
33435 var cn = cfg.cn[0].cn;
33437 if(this.title.length){
33440 cls: 'roo-brick-title',
33445 if(this.html.length){
33448 cls: 'roo-brick-text',
33455 if(this.bgimage.length){
33458 cls: 'roo-brick-image-view',
33466 initEvents: function()
33468 if(this.title.length || this.html.length){
33469 this.el.on('mouseenter' ,this.enter, this);
33470 this.el.on('mouseleave', this.leave, this);
33473 Roo.EventManager.onWindowResize(this.resize, this);
33475 if(this.bgimage.length){
33476 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33477 this.imageEl.on('load', this.onImageLoad, this);
33484 onImageLoad : function()
33489 resize : function()
33491 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33493 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33495 if(this.bgimage.length){
33496 var image = this.el.select('.roo-brick-image-view', true).first();
33498 image.setWidth(paragraph.getWidth());
33501 image.setHeight(paragraph.getWidth());
33504 this.el.setHeight(image.getHeight());
33505 paragraph.setHeight(image.getHeight());
33511 enter: function(e, el)
33513 e.preventDefault();
33515 if(this.bgimage.length){
33516 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33517 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33521 leave: function(e, el)
33523 e.preventDefault();
33525 if(this.bgimage.length){
33526 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33527 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33542 * @class Roo.bootstrap.NumberField
33543 * @extends Roo.bootstrap.Input
33544 * Bootstrap NumberField class
33550 * Create a new NumberField
33551 * @param {Object} config The config object
33554 Roo.bootstrap.NumberField = function(config){
33555 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33558 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33561 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33563 allowDecimals : true,
33565 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33567 decimalSeparator : ".",
33569 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33571 decimalPrecision : 2,
33573 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33575 allowNegative : true,
33578 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33582 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33584 minValue : Number.NEGATIVE_INFINITY,
33586 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33588 maxValue : Number.MAX_VALUE,
33590 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33592 minText : "The minimum value for this field is {0}",
33594 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33596 maxText : "The maximum value for this field is {0}",
33598 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33599 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33601 nanText : "{0} is not a valid number",
33603 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33605 thousandsDelimiter : false,
33607 * @cfg {String} valueAlign alignment of value
33609 valueAlign : "left",
33611 getAutoCreate : function()
33613 var hiddenInput = {
33617 cls: 'hidden-number-input'
33621 hiddenInput.name = this.name;
33626 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33628 this.name = hiddenInput.name;
33630 if(cfg.cn.length > 0) {
33631 cfg.cn.push(hiddenInput);
33638 initEvents : function()
33640 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33642 var allowed = "0123456789";
33644 if(this.allowDecimals){
33645 allowed += this.decimalSeparator;
33648 if(this.allowNegative){
33652 if(this.thousandsDelimiter) {
33656 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33658 var keyPress = function(e){
33660 var k = e.getKey();
33662 var c = e.getCharCode();
33665 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33666 allowed.indexOf(String.fromCharCode(c)) === -1
33672 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33676 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33681 this.el.on("keypress", keyPress, this);
33684 validateValue : function(value)
33687 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33691 var num = this.parseValue(value);
33694 this.markInvalid(String.format(this.nanText, value));
33698 if(num < this.minValue){
33699 this.markInvalid(String.format(this.minText, this.minValue));
33703 if(num > this.maxValue){
33704 this.markInvalid(String.format(this.maxText, this.maxValue));
33711 getValue : function()
33713 var v = this.hiddenEl().getValue();
33715 return this.fixPrecision(this.parseValue(v));
33718 parseValue : function(value)
33720 if(this.thousandsDelimiter) {
33722 r = new RegExp(",", "g");
33723 value = value.replace(r, "");
33726 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33727 return isNaN(value) ? '' : value;
33730 fixPrecision : function(value)
33732 if(this.thousandsDelimiter) {
33734 r = new RegExp(",", "g");
33735 value = value.replace(r, "");
33738 var nan = isNaN(value);
33740 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33741 return nan ? '' : value;
33743 return parseFloat(value).toFixed(this.decimalPrecision);
33746 setValue : function(v)
33748 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33754 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33756 this.inputEl().dom.value = (v == '') ? '' :
33757 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33759 if(!this.allowZero && v === '0') {
33760 this.hiddenEl().dom.value = '';
33761 this.inputEl().dom.value = '';
33768 decimalPrecisionFcn : function(v)
33770 return Math.floor(v);
33773 beforeBlur : function()
33775 var v = this.parseValue(this.getRawValue());
33777 if(v || v === 0 || v === ''){
33782 hiddenEl : function()
33784 return this.el.select('input.hidden-number-input',true).first();
33796 * @class Roo.bootstrap.DocumentSlider
33797 * @extends Roo.bootstrap.Component
33798 * Bootstrap DocumentSlider class
33801 * Create a new DocumentViewer
33802 * @param {Object} config The config object
33805 Roo.bootstrap.DocumentSlider = function(config){
33806 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33813 * Fire after initEvent
33814 * @param {Roo.bootstrap.DocumentSlider} this
33819 * Fire after update
33820 * @param {Roo.bootstrap.DocumentSlider} this
33826 * @param {Roo.bootstrap.DocumentSlider} this
33832 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33838 getAutoCreate : function()
33842 cls : 'roo-document-slider',
33846 cls : 'roo-document-slider-header',
33850 cls : 'roo-document-slider-header-title'
33856 cls : 'roo-document-slider-body',
33860 cls : 'roo-document-slider-prev',
33864 cls : 'fa fa-chevron-left'
33870 cls : 'roo-document-slider-thumb',
33874 cls : 'roo-document-slider-image'
33880 cls : 'roo-document-slider-next',
33884 cls : 'fa fa-chevron-right'
33896 initEvents : function()
33898 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33899 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33901 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33902 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33904 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33905 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33907 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33908 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33910 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33911 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33913 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33914 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33916 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33917 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33919 this.thumbEl.on('click', this.onClick, this);
33921 this.prevIndicator.on('click', this.prev, this);
33923 this.nextIndicator.on('click', this.next, this);
33927 initial : function()
33929 if(this.files.length){
33930 this.indicator = 1;
33934 this.fireEvent('initial', this);
33937 update : function()
33939 this.imageEl.attr('src', this.files[this.indicator - 1]);
33941 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33943 this.prevIndicator.show();
33945 if(this.indicator == 1){
33946 this.prevIndicator.hide();
33949 this.nextIndicator.show();
33951 if(this.indicator == this.files.length){
33952 this.nextIndicator.hide();
33955 this.thumbEl.scrollTo('top');
33957 this.fireEvent('update', this);
33960 onClick : function(e)
33962 e.preventDefault();
33964 this.fireEvent('click', this);
33969 e.preventDefault();
33971 this.indicator = Math.max(1, this.indicator - 1);
33978 e.preventDefault();
33980 this.indicator = Math.min(this.files.length, this.indicator + 1);
33994 * @class Roo.bootstrap.RadioSet
33995 * @extends Roo.bootstrap.Input
33996 * Bootstrap RadioSet class
33997 * @cfg {String} indicatorpos (left|right) default left
33998 * @cfg {Boolean} inline (true|false) inline the element (default true)
33999 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34001 * Create a new RadioSet
34002 * @param {Object} config The config object
34005 Roo.bootstrap.RadioSet = function(config){
34007 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34011 Roo.bootstrap.RadioSet.register(this);
34016 * Fires when the element is checked or unchecked.
34017 * @param {Roo.bootstrap.RadioSet} this This radio
34018 * @param {Roo.bootstrap.Radio} item The checked item
34023 * Fires when the element is click.
34024 * @param {Roo.bootstrap.RadioSet} this This radio set
34025 * @param {Roo.bootstrap.Radio} item The checked item
34026 * @param {Roo.EventObject} e The event object
34033 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34041 indicatorpos : 'left',
34043 getAutoCreate : function()
34047 cls : 'roo-radio-set-label',
34051 html : this.fieldLabel
34056 if(this.indicatorpos == 'left'){
34059 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34060 tooltip : 'This field is required'
34065 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34066 tooltip : 'This field is required'
34072 cls : 'roo-radio-set-items'
34075 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34077 if (align === 'left' && this.fieldLabel.length) {
34080 cls : "roo-radio-set-right",
34086 if(this.labelWidth > 12){
34087 label.style = "width: " + this.labelWidth + 'px';
34090 if(this.labelWidth < 13 && this.labelmd == 0){
34091 this.labelmd = this.labelWidth;
34094 if(this.labellg > 0){
34095 label.cls += ' col-lg-' + this.labellg;
34096 items.cls += ' col-lg-' + (12 - this.labellg);
34099 if(this.labelmd > 0){
34100 label.cls += ' col-md-' + this.labelmd;
34101 items.cls += ' col-md-' + (12 - this.labelmd);
34104 if(this.labelsm > 0){
34105 label.cls += ' col-sm-' + this.labelsm;
34106 items.cls += ' col-sm-' + (12 - this.labelsm);
34109 if(this.labelxs > 0){
34110 label.cls += ' col-xs-' + this.labelxs;
34111 items.cls += ' col-xs-' + (12 - this.labelxs);
34117 cls : 'roo-radio-set',
34121 cls : 'roo-radio-set-input',
34124 value : this.value ? this.value : ''
34131 if(this.weight.length){
34132 cfg.cls += ' roo-radio-' + this.weight;
34136 cfg.cls += ' roo-radio-set-inline';
34140 ['xs','sm','md','lg'].map(function(size){
34141 if (settings[size]) {
34142 cfg.cls += ' col-' + size + '-' + settings[size];
34150 initEvents : function()
34152 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34153 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34155 if(!this.fieldLabel.length){
34156 this.labelEl.hide();
34159 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34160 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34162 this.indicator = this.indicatorEl();
34164 if(this.indicator){
34165 this.indicator.addClass('invisible');
34168 this.originalValue = this.getValue();
34172 inputEl: function ()
34174 return this.el.select('.roo-radio-set-input', true).first();
34177 getChildContainer : function()
34179 return this.itemsEl;
34182 register : function(item)
34184 this.radioes.push(item);
34188 validate : function()
34190 if(this.getVisibilityEl().hasClass('hidden')){
34196 Roo.each(this.radioes, function(i){
34205 if(this.allowBlank) {
34209 if(this.disabled || valid){
34214 this.markInvalid();
34219 markValid : function()
34221 if(this.labelEl.isVisible(true)){
34222 this.indicatorEl().removeClass('visible');
34223 this.indicatorEl().addClass('invisible');
34226 this.el.removeClass([this.invalidClass, this.validClass]);
34227 this.el.addClass(this.validClass);
34229 this.fireEvent('valid', this);
34232 markInvalid : function(msg)
34234 if(this.allowBlank || this.disabled){
34238 if(this.labelEl.isVisible(true)){
34239 this.indicatorEl().removeClass('invisible');
34240 this.indicatorEl().addClass('visible');
34243 this.el.removeClass([this.invalidClass, this.validClass]);
34244 this.el.addClass(this.invalidClass);
34246 this.fireEvent('invalid', this, msg);
34250 setValue : function(v, suppressEvent)
34252 if(this.value === v){
34259 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34262 Roo.each(this.radioes, function(i){
34264 i.el.removeClass('checked');
34267 Roo.each(this.radioes, function(i){
34269 if(i.value === v || i.value.toString() === v.toString()){
34271 i.el.addClass('checked');
34273 if(suppressEvent !== true){
34274 this.fireEvent('check', this, i);
34285 clearInvalid : function(){
34287 if(!this.el || this.preventMark){
34291 this.el.removeClass([this.invalidClass]);
34293 this.fireEvent('valid', this);
34298 Roo.apply(Roo.bootstrap.RadioSet, {
34302 register : function(set)
34304 this.groups[set.name] = set;
34307 get: function(name)
34309 if (typeof(this.groups[name]) == 'undefined') {
34313 return this.groups[name] ;
34319 * Ext JS Library 1.1.1
34320 * Copyright(c) 2006-2007, Ext JS, LLC.
34322 * Originally Released Under LGPL - original licence link has changed is not relivant.
34325 * <script type="text/javascript">
34330 * @class Roo.bootstrap.SplitBar
34331 * @extends Roo.util.Observable
34332 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34336 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34337 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34338 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34339 split.minSize = 100;
34340 split.maxSize = 600;
34341 split.animate = true;
34342 split.on('moved', splitterMoved);
34345 * Create a new SplitBar
34346 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34347 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34348 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34349 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34350 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34351 position of the SplitBar).
34353 Roo.bootstrap.SplitBar = function(cfg){
34358 // dragElement : elm
34359 // resizingElement: el,
34361 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34362 // placement : Roo.bootstrap.SplitBar.LEFT ,
34363 // existingProxy ???
34366 this.el = Roo.get(cfg.dragElement, true);
34367 this.el.dom.unselectable = "on";
34369 this.resizingEl = Roo.get(cfg.resizingElement, true);
34373 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34374 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34377 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34380 * The minimum size of the resizing element. (Defaults to 0)
34386 * The maximum size of the resizing element. (Defaults to 2000)
34389 this.maxSize = 2000;
34392 * Whether to animate the transition to the new size
34395 this.animate = false;
34398 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34401 this.useShim = false;
34406 if(!cfg.existingProxy){
34408 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34410 this.proxy = Roo.get(cfg.existingProxy).dom;
34413 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34416 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34419 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34422 this.dragSpecs = {};
34425 * @private The adapter to use to positon and resize elements
34427 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34428 this.adapter.init(this);
34430 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34432 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34433 this.el.addClass("roo-splitbar-h");
34436 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34437 this.el.addClass("roo-splitbar-v");
34443 * Fires when the splitter is moved (alias for {@link #event-moved})
34444 * @param {Roo.bootstrap.SplitBar} this
34445 * @param {Number} newSize the new width or height
34450 * Fires when the splitter is moved
34451 * @param {Roo.bootstrap.SplitBar} this
34452 * @param {Number} newSize the new width or height
34456 * @event beforeresize
34457 * Fires before the splitter is dragged
34458 * @param {Roo.bootstrap.SplitBar} this
34460 "beforeresize" : true,
34462 "beforeapply" : true
34465 Roo.util.Observable.call(this);
34468 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34469 onStartProxyDrag : function(x, y){
34470 this.fireEvent("beforeresize", this);
34472 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34474 o.enableDisplayMode("block");
34475 // all splitbars share the same overlay
34476 Roo.bootstrap.SplitBar.prototype.overlay = o;
34478 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34479 this.overlay.show();
34480 Roo.get(this.proxy).setDisplayed("block");
34481 var size = this.adapter.getElementSize(this);
34482 this.activeMinSize = this.getMinimumSize();;
34483 this.activeMaxSize = this.getMaximumSize();;
34484 var c1 = size - this.activeMinSize;
34485 var c2 = Math.max(this.activeMaxSize - size, 0);
34486 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34487 this.dd.resetConstraints();
34488 this.dd.setXConstraint(
34489 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34490 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34492 this.dd.setYConstraint(0, 0);
34494 this.dd.resetConstraints();
34495 this.dd.setXConstraint(0, 0);
34496 this.dd.setYConstraint(
34497 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34498 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34501 this.dragSpecs.startSize = size;
34502 this.dragSpecs.startPoint = [x, y];
34503 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34507 * @private Called after the drag operation by the DDProxy
34509 onEndProxyDrag : function(e){
34510 Roo.get(this.proxy).setDisplayed(false);
34511 var endPoint = Roo.lib.Event.getXY(e);
34513 this.overlay.hide();
34516 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34517 newSize = this.dragSpecs.startSize +
34518 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34519 endPoint[0] - this.dragSpecs.startPoint[0] :
34520 this.dragSpecs.startPoint[0] - endPoint[0]
34523 newSize = this.dragSpecs.startSize +
34524 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34525 endPoint[1] - this.dragSpecs.startPoint[1] :
34526 this.dragSpecs.startPoint[1] - endPoint[1]
34529 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34530 if(newSize != this.dragSpecs.startSize){
34531 if(this.fireEvent('beforeapply', this, newSize) !== false){
34532 this.adapter.setElementSize(this, newSize);
34533 this.fireEvent("moved", this, newSize);
34534 this.fireEvent("resize", this, newSize);
34540 * Get the adapter this SplitBar uses
34541 * @return The adapter object
34543 getAdapter : function(){
34544 return this.adapter;
34548 * Set the adapter this SplitBar uses
34549 * @param {Object} adapter A SplitBar adapter object
34551 setAdapter : function(adapter){
34552 this.adapter = adapter;
34553 this.adapter.init(this);
34557 * Gets the minimum size for the resizing element
34558 * @return {Number} The minimum size
34560 getMinimumSize : function(){
34561 return this.minSize;
34565 * Sets the minimum size for the resizing element
34566 * @param {Number} minSize The minimum size
34568 setMinimumSize : function(minSize){
34569 this.minSize = minSize;
34573 * Gets the maximum size for the resizing element
34574 * @return {Number} The maximum size
34576 getMaximumSize : function(){
34577 return this.maxSize;
34581 * Sets the maximum size for the resizing element
34582 * @param {Number} maxSize The maximum size
34584 setMaximumSize : function(maxSize){
34585 this.maxSize = maxSize;
34589 * Sets the initialize size for the resizing element
34590 * @param {Number} size The initial size
34592 setCurrentSize : function(size){
34593 var oldAnimate = this.animate;
34594 this.animate = false;
34595 this.adapter.setElementSize(this, size);
34596 this.animate = oldAnimate;
34600 * Destroy this splitbar.
34601 * @param {Boolean} removeEl True to remove the element
34603 destroy : function(removeEl){
34605 this.shim.remove();
34608 this.proxy.parentNode.removeChild(this.proxy);
34616 * @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.
34618 Roo.bootstrap.SplitBar.createProxy = function(dir){
34619 var proxy = new Roo.Element(document.createElement("div"));
34620 proxy.unselectable();
34621 var cls = 'roo-splitbar-proxy';
34622 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34623 document.body.appendChild(proxy.dom);
34628 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34629 * Default Adapter. It assumes the splitter and resizing element are not positioned
34630 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34632 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34635 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34636 // do nothing for now
34637 init : function(s){
34641 * Called before drag operations to get the current size of the resizing element.
34642 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34644 getElementSize : function(s){
34645 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34646 return s.resizingEl.getWidth();
34648 return s.resizingEl.getHeight();
34653 * Called after drag operations to set the size of the resizing element.
34654 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34655 * @param {Number} newSize The new size to set
34656 * @param {Function} onComplete A function to be invoked when resizing is complete
34658 setElementSize : function(s, newSize, onComplete){
34659 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34661 s.resizingEl.setWidth(newSize);
34663 onComplete(s, newSize);
34666 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34671 s.resizingEl.setHeight(newSize);
34673 onComplete(s, newSize);
34676 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34683 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34684 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34685 * Adapter that moves the splitter element to align with the resized sizing element.
34686 * Used with an absolute positioned SplitBar.
34687 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34688 * document.body, make sure you assign an id to the body element.
34690 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34691 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34692 this.container = Roo.get(container);
34695 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34696 init : function(s){
34697 this.basic.init(s);
34700 getElementSize : function(s){
34701 return this.basic.getElementSize(s);
34704 setElementSize : function(s, newSize, onComplete){
34705 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34708 moveSplitter : function(s){
34709 var yes = Roo.bootstrap.SplitBar;
34710 switch(s.placement){
34712 s.el.setX(s.resizingEl.getRight());
34715 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34718 s.el.setY(s.resizingEl.getBottom());
34721 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34728 * Orientation constant - Create a vertical SplitBar
34732 Roo.bootstrap.SplitBar.VERTICAL = 1;
34735 * Orientation constant - Create a horizontal SplitBar
34739 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34742 * Placement constant - The resizing element is to the left of the splitter element
34746 Roo.bootstrap.SplitBar.LEFT = 1;
34749 * Placement constant - The resizing element is to the right of the splitter element
34753 Roo.bootstrap.SplitBar.RIGHT = 2;
34756 * Placement constant - The resizing element is positioned above the splitter element
34760 Roo.bootstrap.SplitBar.TOP = 3;
34763 * Placement constant - The resizing element is positioned under splitter element
34767 Roo.bootstrap.SplitBar.BOTTOM = 4;
34768 Roo.namespace("Roo.bootstrap.layout");/*
34770 * Ext JS Library 1.1.1
34771 * Copyright(c) 2006-2007, Ext JS, LLC.
34773 * Originally Released Under LGPL - original licence link has changed is not relivant.
34776 * <script type="text/javascript">
34780 * @class Roo.bootstrap.layout.Manager
34781 * @extends Roo.bootstrap.Component
34782 * Base class for layout managers.
34784 Roo.bootstrap.layout.Manager = function(config)
34786 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34792 /** false to disable window resize monitoring @type Boolean */
34793 this.monitorWindowResize = true;
34798 * Fires when a layout is performed.
34799 * @param {Roo.LayoutManager} this
34803 * @event regionresized
34804 * Fires when the user resizes a region.
34805 * @param {Roo.LayoutRegion} region The resized region
34806 * @param {Number} newSize The new size (width for east/west, height for north/south)
34808 "regionresized" : true,
34810 * @event regioncollapsed
34811 * Fires when a region is collapsed.
34812 * @param {Roo.LayoutRegion} region The collapsed region
34814 "regioncollapsed" : true,
34816 * @event regionexpanded
34817 * Fires when a region is expanded.
34818 * @param {Roo.LayoutRegion} region The expanded region
34820 "regionexpanded" : true
34822 this.updating = false;
34825 this.el = Roo.get(config.el);
34831 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34836 monitorWindowResize : true,
34842 onRender : function(ct, position)
34845 this.el = Roo.get(ct);
34848 //this.fireEvent('render',this);
34852 initEvents: function()
34856 // ie scrollbar fix
34857 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34858 document.body.scroll = "no";
34859 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34860 this.el.position('relative');
34862 this.id = this.el.id;
34863 this.el.addClass("roo-layout-container");
34864 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34865 if(this.el.dom != document.body ) {
34866 this.el.on('resize', this.layout,this);
34867 this.el.on('show', this.layout,this);
34873 * Returns true if this layout is currently being updated
34874 * @return {Boolean}
34876 isUpdating : function(){
34877 return this.updating;
34881 * Suspend the LayoutManager from doing auto-layouts while
34882 * making multiple add or remove calls
34884 beginUpdate : function(){
34885 this.updating = true;
34889 * Restore auto-layouts and optionally disable the manager from performing a layout
34890 * @param {Boolean} noLayout true to disable a layout update
34892 endUpdate : function(noLayout){
34893 this.updating = false;
34899 layout: function(){
34903 onRegionResized : function(region, newSize){
34904 this.fireEvent("regionresized", region, newSize);
34908 onRegionCollapsed : function(region){
34909 this.fireEvent("regioncollapsed", region);
34912 onRegionExpanded : function(region){
34913 this.fireEvent("regionexpanded", region);
34917 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34918 * performs box-model adjustments.
34919 * @return {Object} The size as an object {width: (the width), height: (the height)}
34921 getViewSize : function()
34924 if(this.el.dom != document.body){
34925 size = this.el.getSize();
34927 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34929 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34930 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34935 * Returns the Element this layout is bound to.
34936 * @return {Roo.Element}
34938 getEl : function(){
34943 * Returns the specified region.
34944 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34945 * @return {Roo.LayoutRegion}
34947 getRegion : function(target){
34948 return this.regions[target.toLowerCase()];
34951 onWindowResize : function(){
34952 if(this.monitorWindowResize){
34959 * Ext JS Library 1.1.1
34960 * Copyright(c) 2006-2007, Ext JS, LLC.
34962 * Originally Released Under LGPL - original licence link has changed is not relivant.
34965 * <script type="text/javascript">
34968 * @class Roo.bootstrap.layout.Border
34969 * @extends Roo.bootstrap.layout.Manager
34970 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34971 * please see: examples/bootstrap/nested.html<br><br>
34973 <b>The container the layout is rendered into can be either the body element or any other element.
34974 If it is not the body element, the container needs to either be an absolute positioned element,
34975 or you will need to add "position:relative" to the css of the container. You will also need to specify
34976 the container size if it is not the body element.</b>
34979 * Create a new Border
34980 * @param {Object} config Configuration options
34982 Roo.bootstrap.layout.Border = function(config){
34983 config = config || {};
34984 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34988 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34989 if(config[region]){
34990 config[region].region = region;
34991 this.addRegion(config[region]);
34997 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34999 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35001 * Creates and adds a new region if it doesn't already exist.
35002 * @param {String} target The target region key (north, south, east, west or center).
35003 * @param {Object} config The regions config object
35004 * @return {BorderLayoutRegion} The new region
35006 addRegion : function(config)
35008 if(!this.regions[config.region]){
35009 var r = this.factory(config);
35010 this.bindRegion(r);
35012 return this.regions[config.region];
35016 bindRegion : function(r){
35017 this.regions[r.config.region] = r;
35019 r.on("visibilitychange", this.layout, this);
35020 r.on("paneladded", this.layout, this);
35021 r.on("panelremoved", this.layout, this);
35022 r.on("invalidated", this.layout, this);
35023 r.on("resized", this.onRegionResized, this);
35024 r.on("collapsed", this.onRegionCollapsed, this);
35025 r.on("expanded", this.onRegionExpanded, this);
35029 * Performs a layout update.
35031 layout : function()
35033 if(this.updating) {
35037 // render all the rebions if they have not been done alreayd?
35038 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35039 if(this.regions[region] && !this.regions[region].bodyEl){
35040 this.regions[region].onRender(this.el)
35044 var size = this.getViewSize();
35045 var w = size.width;
35046 var h = size.height;
35051 //var x = 0, y = 0;
35053 var rs = this.regions;
35054 var north = rs["north"];
35055 var south = rs["south"];
35056 var west = rs["west"];
35057 var east = rs["east"];
35058 var center = rs["center"];
35059 //if(this.hideOnLayout){ // not supported anymore
35060 //c.el.setStyle("display", "none");
35062 if(north && north.isVisible()){
35063 var b = north.getBox();
35064 var m = north.getMargins();
35065 b.width = w - (m.left+m.right);
35068 centerY = b.height + b.y + m.bottom;
35069 centerH -= centerY;
35070 north.updateBox(this.safeBox(b));
35072 if(south && south.isVisible()){
35073 var b = south.getBox();
35074 var m = south.getMargins();
35075 b.width = w - (m.left+m.right);
35077 var totalHeight = (b.height + m.top + m.bottom);
35078 b.y = h - totalHeight + m.top;
35079 centerH -= totalHeight;
35080 south.updateBox(this.safeBox(b));
35082 if(west && west.isVisible()){
35083 var b = west.getBox();
35084 var m = west.getMargins();
35085 b.height = centerH - (m.top+m.bottom);
35087 b.y = centerY + m.top;
35088 var totalWidth = (b.width + m.left + m.right);
35089 centerX += totalWidth;
35090 centerW -= totalWidth;
35091 west.updateBox(this.safeBox(b));
35093 if(east && east.isVisible()){
35094 var b = east.getBox();
35095 var m = east.getMargins();
35096 b.height = centerH - (m.top+m.bottom);
35097 var totalWidth = (b.width + m.left + m.right);
35098 b.x = w - totalWidth + m.left;
35099 b.y = centerY + m.top;
35100 centerW -= totalWidth;
35101 east.updateBox(this.safeBox(b));
35104 var m = center.getMargins();
35106 x: centerX + m.left,
35107 y: centerY + m.top,
35108 width: centerW - (m.left+m.right),
35109 height: centerH - (m.top+m.bottom)
35111 //if(this.hideOnLayout){
35112 //center.el.setStyle("display", "block");
35114 center.updateBox(this.safeBox(centerBox));
35117 this.fireEvent("layout", this);
35121 safeBox : function(box){
35122 box.width = Math.max(0, box.width);
35123 box.height = Math.max(0, box.height);
35128 * Adds a ContentPanel (or subclass) to this layout.
35129 * @param {String} target The target region key (north, south, east, west or center).
35130 * @param {Roo.ContentPanel} panel The panel to add
35131 * @return {Roo.ContentPanel} The added panel
35133 add : function(target, panel){
35135 target = target.toLowerCase();
35136 return this.regions[target].add(panel);
35140 * Remove a ContentPanel (or subclass) to this layout.
35141 * @param {String} target The target region key (north, south, east, west or center).
35142 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35143 * @return {Roo.ContentPanel} The removed panel
35145 remove : function(target, panel){
35146 target = target.toLowerCase();
35147 return this.regions[target].remove(panel);
35151 * Searches all regions for a panel with the specified id
35152 * @param {String} panelId
35153 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35155 findPanel : function(panelId){
35156 var rs = this.regions;
35157 for(var target in rs){
35158 if(typeof rs[target] != "function"){
35159 var p = rs[target].getPanel(panelId);
35169 * Searches all regions for a panel with the specified id and activates (shows) it.
35170 * @param {String/ContentPanel} panelId The panels id or the panel itself
35171 * @return {Roo.ContentPanel} The shown panel or null
35173 showPanel : function(panelId) {
35174 var rs = this.regions;
35175 for(var target in rs){
35176 var r = rs[target];
35177 if(typeof r != "function"){
35178 if(r.hasPanel(panelId)){
35179 return r.showPanel(panelId);
35187 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35188 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35191 restoreState : function(provider){
35193 provider = Roo.state.Manager;
35195 var sm = new Roo.LayoutStateManager();
35196 sm.init(this, provider);
35202 * Adds a xtype elements to the layout.
35206 xtype : 'ContentPanel',
35213 xtype : 'NestedLayoutPanel',
35219 items : [ ... list of content panels or nested layout panels.. ]
35223 * @param {Object} cfg Xtype definition of item to add.
35225 addxtype : function(cfg)
35227 // basically accepts a pannel...
35228 // can accept a layout region..!?!?
35229 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35232 // theory? children can only be panels??
35234 //if (!cfg.xtype.match(/Panel$/)) {
35239 if (typeof(cfg.region) == 'undefined') {
35240 Roo.log("Failed to add Panel, region was not set");
35244 var region = cfg.region;
35250 xitems = cfg.items;
35257 case 'Content': // ContentPanel (el, cfg)
35258 case 'Scroll': // ContentPanel (el, cfg)
35260 cfg.autoCreate = true;
35261 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35263 // var el = this.el.createChild();
35264 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35267 this.add(region, ret);
35271 case 'TreePanel': // our new panel!
35272 cfg.el = this.el.createChild();
35273 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35274 this.add(region, ret);
35279 // create a new Layout (which is a Border Layout...
35281 var clayout = cfg.layout;
35282 clayout.el = this.el.createChild();
35283 clayout.items = clayout.items || [];
35287 // replace this exitems with the clayout ones..
35288 xitems = clayout.items;
35290 // force background off if it's in center...
35291 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35292 cfg.background = false;
35294 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35297 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35298 //console.log('adding nested layout panel ' + cfg.toSource());
35299 this.add(region, ret);
35300 nb = {}; /// find first...
35305 // needs grid and region
35307 //var el = this.getRegion(region).el.createChild();
35309 *var el = this.el.createChild();
35310 // create the grid first...
35311 cfg.grid.container = el;
35312 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35315 if (region == 'center' && this.active ) {
35316 cfg.background = false;
35319 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35321 this.add(region, ret);
35323 if (cfg.background) {
35324 // render grid on panel activation (if panel background)
35325 ret.on('activate', function(gp) {
35326 if (!gp.grid.rendered) {
35327 // gp.grid.render(el);
35331 // cfg.grid.render(el);
35337 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35338 // it was the old xcomponent building that caused this before.
35339 // espeically if border is the top element in the tree.
35349 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35351 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35352 this.add(region, ret);
35356 throw "Can not add '" + cfg.xtype + "' to Border";
35362 this.beginUpdate();
35366 Roo.each(xitems, function(i) {
35367 region = nb && i.region ? i.region : false;
35369 var add = ret.addxtype(i);
35372 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35373 if (!i.background) {
35374 abn[region] = nb[region] ;
35381 // make the last non-background panel active..
35382 //if (nb) { Roo.log(abn); }
35385 for(var r in abn) {
35386 region = this.getRegion(r);
35388 // tried using nb[r], but it does not work..
35390 region.showPanel(abn[r]);
35401 factory : function(cfg)
35404 var validRegions = Roo.bootstrap.layout.Border.regions;
35406 var target = cfg.region;
35409 var r = Roo.bootstrap.layout;
35413 return new r.North(cfg);
35415 return new r.South(cfg);
35417 return new r.East(cfg);
35419 return new r.West(cfg);
35421 return new r.Center(cfg);
35423 throw 'Layout region "'+target+'" not supported.';
35430 * Ext JS Library 1.1.1
35431 * Copyright(c) 2006-2007, Ext JS, LLC.
35433 * Originally Released Under LGPL - original licence link has changed is not relivant.
35436 * <script type="text/javascript">
35440 * @class Roo.bootstrap.layout.Basic
35441 * @extends Roo.util.Observable
35442 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35443 * and does not have a titlebar, tabs or any other features. All it does is size and position
35444 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35445 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35446 * @cfg {string} region the region that it inhabits..
35447 * @cfg {bool} skipConfig skip config?
35451 Roo.bootstrap.layout.Basic = function(config){
35453 this.mgr = config.mgr;
35455 this.position = config.region;
35457 var skipConfig = config.skipConfig;
35461 * @scope Roo.BasicLayoutRegion
35465 * @event beforeremove
35466 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35467 * @param {Roo.LayoutRegion} this
35468 * @param {Roo.ContentPanel} panel The panel
35469 * @param {Object} e The cancel event object
35471 "beforeremove" : true,
35473 * @event invalidated
35474 * Fires when the layout for this region is changed.
35475 * @param {Roo.LayoutRegion} this
35477 "invalidated" : true,
35479 * @event visibilitychange
35480 * Fires when this region is shown or hidden
35481 * @param {Roo.LayoutRegion} this
35482 * @param {Boolean} visibility true or false
35484 "visibilitychange" : true,
35486 * @event paneladded
35487 * Fires when a panel is added.
35488 * @param {Roo.LayoutRegion} this
35489 * @param {Roo.ContentPanel} panel The panel
35491 "paneladded" : true,
35493 * @event panelremoved
35494 * Fires when a panel is removed.
35495 * @param {Roo.LayoutRegion} this
35496 * @param {Roo.ContentPanel} panel The panel
35498 "panelremoved" : true,
35500 * @event beforecollapse
35501 * Fires when this region before collapse.
35502 * @param {Roo.LayoutRegion} this
35504 "beforecollapse" : true,
35507 * Fires when this region is collapsed.
35508 * @param {Roo.LayoutRegion} this
35510 "collapsed" : true,
35513 * Fires when this region is expanded.
35514 * @param {Roo.LayoutRegion} this
35519 * Fires when this region is slid into view.
35520 * @param {Roo.LayoutRegion} this
35522 "slideshow" : true,
35525 * Fires when this region slides out of view.
35526 * @param {Roo.LayoutRegion} this
35528 "slidehide" : true,
35530 * @event panelactivated
35531 * Fires when a panel is activated.
35532 * @param {Roo.LayoutRegion} this
35533 * @param {Roo.ContentPanel} panel The activated panel
35535 "panelactivated" : true,
35538 * Fires when the user resizes this region.
35539 * @param {Roo.LayoutRegion} this
35540 * @param {Number} newSize The new size (width for east/west, height for north/south)
35544 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35545 this.panels = new Roo.util.MixedCollection();
35546 this.panels.getKey = this.getPanelId.createDelegate(this);
35548 this.activePanel = null;
35549 // ensure listeners are added...
35551 if (config.listeners || config.events) {
35552 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35553 listeners : config.listeners || {},
35554 events : config.events || {}
35558 if(skipConfig !== true){
35559 this.applyConfig(config);
35563 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35565 getPanelId : function(p){
35569 applyConfig : function(config){
35570 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35571 this.config = config;
35576 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35577 * the width, for horizontal (north, south) the height.
35578 * @param {Number} newSize The new width or height
35580 resizeTo : function(newSize){
35581 var el = this.el ? this.el :
35582 (this.activePanel ? this.activePanel.getEl() : null);
35584 switch(this.position){
35587 el.setWidth(newSize);
35588 this.fireEvent("resized", this, newSize);
35592 el.setHeight(newSize);
35593 this.fireEvent("resized", this, newSize);
35599 getBox : function(){
35600 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35603 getMargins : function(){
35604 return this.margins;
35607 updateBox : function(box){
35609 var el = this.activePanel.getEl();
35610 el.dom.style.left = box.x + "px";
35611 el.dom.style.top = box.y + "px";
35612 this.activePanel.setSize(box.width, box.height);
35616 * Returns the container element for this region.
35617 * @return {Roo.Element}
35619 getEl : function(){
35620 return this.activePanel;
35624 * Returns true if this region is currently visible.
35625 * @return {Boolean}
35627 isVisible : function(){
35628 return this.activePanel ? true : false;
35631 setActivePanel : function(panel){
35632 panel = this.getPanel(panel);
35633 if(this.activePanel && this.activePanel != panel){
35634 this.activePanel.setActiveState(false);
35635 this.activePanel.getEl().setLeftTop(-10000,-10000);
35637 this.activePanel = panel;
35638 panel.setActiveState(true);
35640 panel.setSize(this.box.width, this.box.height);
35642 this.fireEvent("panelactivated", this, panel);
35643 this.fireEvent("invalidated");
35647 * Show the specified panel.
35648 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35649 * @return {Roo.ContentPanel} The shown panel or null
35651 showPanel : function(panel){
35652 panel = this.getPanel(panel);
35654 this.setActivePanel(panel);
35660 * Get the active panel for this region.
35661 * @return {Roo.ContentPanel} The active panel or null
35663 getActivePanel : function(){
35664 return this.activePanel;
35668 * Add the passed ContentPanel(s)
35669 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35670 * @return {Roo.ContentPanel} The panel added (if only one was added)
35672 add : function(panel){
35673 if(arguments.length > 1){
35674 for(var i = 0, len = arguments.length; i < len; i++) {
35675 this.add(arguments[i]);
35679 if(this.hasPanel(panel)){
35680 this.showPanel(panel);
35683 var el = panel.getEl();
35684 if(el.dom.parentNode != this.mgr.el.dom){
35685 this.mgr.el.dom.appendChild(el.dom);
35687 if(panel.setRegion){
35688 panel.setRegion(this);
35690 this.panels.add(panel);
35691 el.setStyle("position", "absolute");
35692 if(!panel.background){
35693 this.setActivePanel(panel);
35694 if(this.config.initialSize && this.panels.getCount()==1){
35695 this.resizeTo(this.config.initialSize);
35698 this.fireEvent("paneladded", this, panel);
35703 * Returns true if the panel is in this region.
35704 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35705 * @return {Boolean}
35707 hasPanel : function(panel){
35708 if(typeof panel == "object"){ // must be panel obj
35709 panel = panel.getId();
35711 return this.getPanel(panel) ? true : false;
35715 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35716 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35717 * @param {Boolean} preservePanel Overrides the config preservePanel option
35718 * @return {Roo.ContentPanel} The panel that was removed
35720 remove : function(panel, preservePanel){
35721 panel = this.getPanel(panel);
35726 this.fireEvent("beforeremove", this, panel, e);
35727 if(e.cancel === true){
35730 var panelId = panel.getId();
35731 this.panels.removeKey(panelId);
35736 * Returns the panel specified or null if it's not in this region.
35737 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35738 * @return {Roo.ContentPanel}
35740 getPanel : function(id){
35741 if(typeof id == "object"){ // must be panel obj
35744 return this.panels.get(id);
35748 * Returns this regions position (north/south/east/west/center).
35751 getPosition: function(){
35752 return this.position;
35756 * Ext JS Library 1.1.1
35757 * Copyright(c) 2006-2007, Ext JS, LLC.
35759 * Originally Released Under LGPL - original licence link has changed is not relivant.
35762 * <script type="text/javascript">
35766 * @class Roo.bootstrap.layout.Region
35767 * @extends Roo.bootstrap.layout.Basic
35768 * This class represents a region in a layout manager.
35770 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35771 * @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})
35772 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35773 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35774 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35775 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35776 * @cfg {String} title The title for the region (overrides panel titles)
35777 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35778 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35779 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35780 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35781 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35782 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35783 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35784 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35785 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35786 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35788 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35789 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35790 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35791 * @cfg {Number} width For East/West panels
35792 * @cfg {Number} height For North/South panels
35793 * @cfg {Boolean} split To show the splitter
35794 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35796 * @cfg {string} cls Extra CSS classes to add to region
35798 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35799 * @cfg {string} region the region that it inhabits..
35802 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35803 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35805 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35806 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35807 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35809 Roo.bootstrap.layout.Region = function(config)
35811 this.applyConfig(config);
35813 var mgr = config.mgr;
35814 var pos = config.region;
35815 config.skipConfig = true;
35816 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35819 this.onRender(mgr.el);
35822 this.visible = true;
35823 this.collapsed = false;
35824 this.unrendered_panels = [];
35827 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35829 position: '', // set by wrapper (eg. north/south etc..)
35830 unrendered_panels : null, // unrendered panels.
35831 createBody : function(){
35832 /** This region's body element
35833 * @type Roo.Element */
35834 this.bodyEl = this.el.createChild({
35836 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35840 onRender: function(ctr, pos)
35842 var dh = Roo.DomHelper;
35843 /** This region's container element
35844 * @type Roo.Element */
35845 this.el = dh.append(ctr.dom, {
35847 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35849 /** This region's title element
35850 * @type Roo.Element */
35852 this.titleEl = dh.append(this.el.dom,
35855 unselectable: "on",
35856 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35858 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35859 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35862 this.titleEl.enableDisplayMode();
35863 /** This region's title text element
35864 * @type HTMLElement */
35865 this.titleTextEl = this.titleEl.dom.firstChild;
35866 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35868 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35869 this.closeBtn.enableDisplayMode();
35870 this.closeBtn.on("click", this.closeClicked, this);
35871 this.closeBtn.hide();
35873 this.createBody(this.config);
35874 if(this.config.hideWhenEmpty){
35876 this.on("paneladded", this.validateVisibility, this);
35877 this.on("panelremoved", this.validateVisibility, this);
35879 if(this.autoScroll){
35880 this.bodyEl.setStyle("overflow", "auto");
35882 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35884 //if(c.titlebar !== false){
35885 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35886 this.titleEl.hide();
35888 this.titleEl.show();
35889 if(this.config.title){
35890 this.titleTextEl.innerHTML = this.config.title;
35894 if(this.config.collapsed){
35895 this.collapse(true);
35897 if(this.config.hidden){
35901 if (this.unrendered_panels && this.unrendered_panels.length) {
35902 for (var i =0;i< this.unrendered_panels.length; i++) {
35903 this.add(this.unrendered_panels[i]);
35905 this.unrendered_panels = null;
35911 applyConfig : function(c)
35914 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35915 var dh = Roo.DomHelper;
35916 if(c.titlebar !== false){
35917 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35918 this.collapseBtn.on("click", this.collapse, this);
35919 this.collapseBtn.enableDisplayMode();
35921 if(c.showPin === true || this.showPin){
35922 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35923 this.stickBtn.enableDisplayMode();
35924 this.stickBtn.on("click", this.expand, this);
35925 this.stickBtn.hide();
35930 /** This region's collapsed element
35931 * @type Roo.Element */
35934 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35935 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35938 if(c.floatable !== false){
35939 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35940 this.collapsedEl.on("click", this.collapseClick, this);
35943 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35944 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35945 id: "message", unselectable: "on", style:{"float":"left"}});
35946 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35948 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35949 this.expandBtn.on("click", this.expand, this);
35953 if(this.collapseBtn){
35954 this.collapseBtn.setVisible(c.collapsible == true);
35957 this.cmargins = c.cmargins || this.cmargins ||
35958 (this.position == "west" || this.position == "east" ?
35959 {top: 0, left: 2, right:2, bottom: 0} :
35960 {top: 2, left: 0, right:0, bottom: 2});
35962 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35965 this.bottomTabs = c.tabPosition != "top";
35967 this.autoScroll = c.autoScroll || false;
35972 this.duration = c.duration || .30;
35973 this.slideDuration = c.slideDuration || .45;
35978 * Returns true if this region is currently visible.
35979 * @return {Boolean}
35981 isVisible : function(){
35982 return this.visible;
35986 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35987 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35989 //setCollapsedTitle : function(title){
35990 // title = title || " ";
35991 // if(this.collapsedTitleTextEl){
35992 // this.collapsedTitleTextEl.innerHTML = title;
35996 getBox : function(){
35998 // if(!this.collapsed){
35999 b = this.el.getBox(false, true);
36001 // b = this.collapsedEl.getBox(false, true);
36006 getMargins : function(){
36007 return this.margins;
36008 //return this.collapsed ? this.cmargins : this.margins;
36011 highlight : function(){
36012 this.el.addClass("x-layout-panel-dragover");
36015 unhighlight : function(){
36016 this.el.removeClass("x-layout-panel-dragover");
36019 updateBox : function(box)
36021 if (!this.bodyEl) {
36022 return; // not rendered yet..
36026 if(!this.collapsed){
36027 this.el.dom.style.left = box.x + "px";
36028 this.el.dom.style.top = box.y + "px";
36029 this.updateBody(box.width, box.height);
36031 this.collapsedEl.dom.style.left = box.x + "px";
36032 this.collapsedEl.dom.style.top = box.y + "px";
36033 this.collapsedEl.setSize(box.width, box.height);
36036 this.tabs.autoSizeTabs();
36040 updateBody : function(w, h)
36043 this.el.setWidth(w);
36044 w -= this.el.getBorderWidth("rl");
36045 if(this.config.adjustments){
36046 w += this.config.adjustments[0];
36049 if(h !== null && h > 0){
36050 this.el.setHeight(h);
36051 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36052 h -= this.el.getBorderWidth("tb");
36053 if(this.config.adjustments){
36054 h += this.config.adjustments[1];
36056 this.bodyEl.setHeight(h);
36058 h = this.tabs.syncHeight(h);
36061 if(this.panelSize){
36062 w = w !== null ? w : this.panelSize.width;
36063 h = h !== null ? h : this.panelSize.height;
36065 if(this.activePanel){
36066 var el = this.activePanel.getEl();
36067 w = w !== null ? w : el.getWidth();
36068 h = h !== null ? h : el.getHeight();
36069 this.panelSize = {width: w, height: h};
36070 this.activePanel.setSize(w, h);
36072 if(Roo.isIE && this.tabs){
36073 this.tabs.el.repaint();
36078 * Returns the container element for this region.
36079 * @return {Roo.Element}
36081 getEl : function(){
36086 * Hides this region.
36089 //if(!this.collapsed){
36090 this.el.dom.style.left = "-2000px";
36093 // this.collapsedEl.dom.style.left = "-2000px";
36094 // this.collapsedEl.hide();
36096 this.visible = false;
36097 this.fireEvent("visibilitychange", this, false);
36101 * Shows this region if it was previously hidden.
36104 //if(!this.collapsed){
36107 // this.collapsedEl.show();
36109 this.visible = true;
36110 this.fireEvent("visibilitychange", this, true);
36113 closeClicked : function(){
36114 if(this.activePanel){
36115 this.remove(this.activePanel);
36119 collapseClick : function(e){
36121 e.stopPropagation();
36124 e.stopPropagation();
36130 * Collapses this region.
36131 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36134 collapse : function(skipAnim, skipCheck = false){
36135 if(this.collapsed) {
36139 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36141 this.collapsed = true;
36143 this.split.el.hide();
36145 if(this.config.animate && skipAnim !== true){
36146 this.fireEvent("invalidated", this);
36147 this.animateCollapse();
36149 this.el.setLocation(-20000,-20000);
36151 this.collapsedEl.show();
36152 this.fireEvent("collapsed", this);
36153 this.fireEvent("invalidated", this);
36159 animateCollapse : function(){
36164 * Expands this region if it was previously collapsed.
36165 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36166 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36169 expand : function(e, skipAnim){
36171 e.stopPropagation();
36173 if(!this.collapsed || this.el.hasActiveFx()) {
36177 this.afterSlideIn();
36180 this.collapsed = false;
36181 if(this.config.animate && skipAnim !== true){
36182 this.animateExpand();
36186 this.split.el.show();
36188 this.collapsedEl.setLocation(-2000,-2000);
36189 this.collapsedEl.hide();
36190 this.fireEvent("invalidated", this);
36191 this.fireEvent("expanded", this);
36195 animateExpand : function(){
36199 initTabs : function()
36201 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36203 var ts = new Roo.bootstrap.panel.Tabs({
36204 el: this.bodyEl.dom,
36205 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36206 disableTooltips: this.config.disableTabTips,
36207 toolbar : this.config.toolbar
36210 if(this.config.hideTabs){
36211 ts.stripWrap.setDisplayed(false);
36214 ts.resizeTabs = this.config.resizeTabs === true;
36215 ts.minTabWidth = this.config.minTabWidth || 40;
36216 ts.maxTabWidth = this.config.maxTabWidth || 250;
36217 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36218 ts.monitorResize = false;
36219 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36220 ts.bodyEl.addClass('roo-layout-tabs-body');
36221 this.panels.each(this.initPanelAsTab, this);
36224 initPanelAsTab : function(panel){
36225 var ti = this.tabs.addTab(
36229 this.config.closeOnTab && panel.isClosable(),
36232 if(panel.tabTip !== undefined){
36233 ti.setTooltip(panel.tabTip);
36235 ti.on("activate", function(){
36236 this.setActivePanel(panel);
36239 if(this.config.closeOnTab){
36240 ti.on("beforeclose", function(t, e){
36242 this.remove(panel);
36246 panel.tabItem = ti;
36251 updatePanelTitle : function(panel, title)
36253 if(this.activePanel == panel){
36254 this.updateTitle(title);
36257 var ti = this.tabs.getTab(panel.getEl().id);
36259 if(panel.tabTip !== undefined){
36260 ti.setTooltip(panel.tabTip);
36265 updateTitle : function(title){
36266 if(this.titleTextEl && !this.config.title){
36267 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36271 setActivePanel : function(panel)
36273 panel = this.getPanel(panel);
36274 if(this.activePanel && this.activePanel != panel){
36275 if(this.activePanel.setActiveState(false) === false){
36279 this.activePanel = panel;
36280 panel.setActiveState(true);
36281 if(this.panelSize){
36282 panel.setSize(this.panelSize.width, this.panelSize.height);
36285 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36287 this.updateTitle(panel.getTitle());
36289 this.fireEvent("invalidated", this);
36291 this.fireEvent("panelactivated", this, panel);
36295 * Shows the specified panel.
36296 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36297 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36299 showPanel : function(panel)
36301 panel = this.getPanel(panel);
36304 var tab = this.tabs.getTab(panel.getEl().id);
36305 if(tab.isHidden()){
36306 this.tabs.unhideTab(tab.id);
36310 this.setActivePanel(panel);
36317 * Get the active panel for this region.
36318 * @return {Roo.ContentPanel} The active panel or null
36320 getActivePanel : function(){
36321 return this.activePanel;
36324 validateVisibility : function(){
36325 if(this.panels.getCount() < 1){
36326 this.updateTitle(" ");
36327 this.closeBtn.hide();
36330 if(!this.isVisible()){
36337 * Adds the passed ContentPanel(s) to this region.
36338 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36339 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36341 add : function(panel)
36343 if(arguments.length > 1){
36344 for(var i = 0, len = arguments.length; i < len; i++) {
36345 this.add(arguments[i]);
36350 // if we have not been rendered yet, then we can not really do much of this..
36351 if (!this.bodyEl) {
36352 this.unrendered_panels.push(panel);
36359 if(this.hasPanel(panel)){
36360 this.showPanel(panel);
36363 panel.setRegion(this);
36364 this.panels.add(panel);
36365 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36366 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36367 // and hide them... ???
36368 this.bodyEl.dom.appendChild(panel.getEl().dom);
36369 if(panel.background !== true){
36370 this.setActivePanel(panel);
36372 this.fireEvent("paneladded", this, panel);
36379 this.initPanelAsTab(panel);
36383 if(panel.background !== true){
36384 this.tabs.activate(panel.getEl().id);
36386 this.fireEvent("paneladded", this, panel);
36391 * Hides the tab for the specified panel.
36392 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36394 hidePanel : function(panel){
36395 if(this.tabs && (panel = this.getPanel(panel))){
36396 this.tabs.hideTab(panel.getEl().id);
36401 * Unhides the tab for a previously hidden panel.
36402 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36404 unhidePanel : function(panel){
36405 if(this.tabs && (panel = this.getPanel(panel))){
36406 this.tabs.unhideTab(panel.getEl().id);
36410 clearPanels : function(){
36411 while(this.panels.getCount() > 0){
36412 this.remove(this.panels.first());
36417 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36418 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36419 * @param {Boolean} preservePanel Overrides the config preservePanel option
36420 * @return {Roo.ContentPanel} The panel that was removed
36422 remove : function(panel, preservePanel)
36424 panel = this.getPanel(panel);
36429 this.fireEvent("beforeremove", this, panel, e);
36430 if(e.cancel === true){
36433 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36434 var panelId = panel.getId();
36435 this.panels.removeKey(panelId);
36437 document.body.appendChild(panel.getEl().dom);
36440 this.tabs.removeTab(panel.getEl().id);
36441 }else if (!preservePanel){
36442 this.bodyEl.dom.removeChild(panel.getEl().dom);
36444 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36445 var p = this.panels.first();
36446 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36447 tempEl.appendChild(p.getEl().dom);
36448 this.bodyEl.update("");
36449 this.bodyEl.dom.appendChild(p.getEl().dom);
36451 this.updateTitle(p.getTitle());
36453 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36454 this.setActivePanel(p);
36456 panel.setRegion(null);
36457 if(this.activePanel == panel){
36458 this.activePanel = null;
36460 if(this.config.autoDestroy !== false && preservePanel !== true){
36461 try{panel.destroy();}catch(e){}
36463 this.fireEvent("panelremoved", this, panel);
36468 * Returns the TabPanel component used by this region
36469 * @return {Roo.TabPanel}
36471 getTabs : function(){
36475 createTool : function(parentEl, className){
36476 var btn = Roo.DomHelper.append(parentEl, {
36478 cls: "x-layout-tools-button",
36481 cls: "roo-layout-tools-button-inner " + className,
36485 btn.addClassOnOver("roo-layout-tools-button-over");
36490 * Ext JS Library 1.1.1
36491 * Copyright(c) 2006-2007, Ext JS, LLC.
36493 * Originally Released Under LGPL - original licence link has changed is not relivant.
36496 * <script type="text/javascript">
36502 * @class Roo.SplitLayoutRegion
36503 * @extends Roo.LayoutRegion
36504 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36506 Roo.bootstrap.layout.Split = function(config){
36507 this.cursor = config.cursor;
36508 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36511 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36513 splitTip : "Drag to resize.",
36514 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36515 useSplitTips : false,
36517 applyConfig : function(config){
36518 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36521 onRender : function(ctr,pos) {
36523 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36524 if(!this.config.split){
36529 var splitEl = Roo.DomHelper.append(ctr.dom, {
36531 id: this.el.id + "-split",
36532 cls: "roo-layout-split roo-layout-split-"+this.position,
36535 /** The SplitBar for this region
36536 * @type Roo.SplitBar */
36537 // does not exist yet...
36538 Roo.log([this.position, this.orientation]);
36540 this.split = new Roo.bootstrap.SplitBar({
36541 dragElement : splitEl,
36542 resizingElement: this.el,
36543 orientation : this.orientation
36546 this.split.on("moved", this.onSplitMove, this);
36547 this.split.useShim = this.config.useShim === true;
36548 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36549 if(this.useSplitTips){
36550 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36552 //if(config.collapsible){
36553 // this.split.el.on("dblclick", this.collapse, this);
36556 if(typeof this.config.minSize != "undefined"){
36557 this.split.minSize = this.config.minSize;
36559 if(typeof this.config.maxSize != "undefined"){
36560 this.split.maxSize = this.config.maxSize;
36562 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36563 this.hideSplitter();
36568 getHMaxSize : function(){
36569 var cmax = this.config.maxSize || 10000;
36570 var center = this.mgr.getRegion("center");
36571 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36574 getVMaxSize : function(){
36575 var cmax = this.config.maxSize || 10000;
36576 var center = this.mgr.getRegion("center");
36577 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36580 onSplitMove : function(split, newSize){
36581 this.fireEvent("resized", this, newSize);
36585 * Returns the {@link Roo.SplitBar} for this region.
36586 * @return {Roo.SplitBar}
36588 getSplitBar : function(){
36593 this.hideSplitter();
36594 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36597 hideSplitter : function(){
36599 this.split.el.setLocation(-2000,-2000);
36600 this.split.el.hide();
36606 this.split.el.show();
36608 Roo.bootstrap.layout.Split.superclass.show.call(this);
36611 beforeSlide: function(){
36612 if(Roo.isGecko){// firefox overflow auto bug workaround
36613 this.bodyEl.clip();
36615 this.tabs.bodyEl.clip();
36617 if(this.activePanel){
36618 this.activePanel.getEl().clip();
36620 if(this.activePanel.beforeSlide){
36621 this.activePanel.beforeSlide();
36627 afterSlide : function(){
36628 if(Roo.isGecko){// firefox overflow auto bug workaround
36629 this.bodyEl.unclip();
36631 this.tabs.bodyEl.unclip();
36633 if(this.activePanel){
36634 this.activePanel.getEl().unclip();
36635 if(this.activePanel.afterSlide){
36636 this.activePanel.afterSlide();
36642 initAutoHide : function(){
36643 if(this.autoHide !== false){
36644 if(!this.autoHideHd){
36645 var st = new Roo.util.DelayedTask(this.slideIn, this);
36646 this.autoHideHd = {
36647 "mouseout": function(e){
36648 if(!e.within(this.el, true)){
36652 "mouseover" : function(e){
36658 this.el.on(this.autoHideHd);
36662 clearAutoHide : function(){
36663 if(this.autoHide !== false){
36664 this.el.un("mouseout", this.autoHideHd.mouseout);
36665 this.el.un("mouseover", this.autoHideHd.mouseover);
36669 clearMonitor : function(){
36670 Roo.get(document).un("click", this.slideInIf, this);
36673 // these names are backwards but not changed for compat
36674 slideOut : function(){
36675 if(this.isSlid || this.el.hasActiveFx()){
36678 this.isSlid = true;
36679 if(this.collapseBtn){
36680 this.collapseBtn.hide();
36682 this.closeBtnState = this.closeBtn.getStyle('display');
36683 this.closeBtn.hide();
36685 this.stickBtn.show();
36688 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36689 this.beforeSlide();
36690 this.el.setStyle("z-index", 10001);
36691 this.el.slideIn(this.getSlideAnchor(), {
36692 callback: function(){
36694 this.initAutoHide();
36695 Roo.get(document).on("click", this.slideInIf, this);
36696 this.fireEvent("slideshow", this);
36703 afterSlideIn : function(){
36704 this.clearAutoHide();
36705 this.isSlid = false;
36706 this.clearMonitor();
36707 this.el.setStyle("z-index", "");
36708 if(this.collapseBtn){
36709 this.collapseBtn.show();
36711 this.closeBtn.setStyle('display', this.closeBtnState);
36713 this.stickBtn.hide();
36715 this.fireEvent("slidehide", this);
36718 slideIn : function(cb){
36719 if(!this.isSlid || this.el.hasActiveFx()){
36723 this.isSlid = false;
36724 this.beforeSlide();
36725 this.el.slideOut(this.getSlideAnchor(), {
36726 callback: function(){
36727 this.el.setLeftTop(-10000, -10000);
36729 this.afterSlideIn();
36737 slideInIf : function(e){
36738 if(!e.within(this.el)){
36743 animateCollapse : function(){
36744 this.beforeSlide();
36745 this.el.setStyle("z-index", 20000);
36746 var anchor = this.getSlideAnchor();
36747 this.el.slideOut(anchor, {
36748 callback : function(){
36749 this.el.setStyle("z-index", "");
36750 this.collapsedEl.slideIn(anchor, {duration:.3});
36752 this.el.setLocation(-10000,-10000);
36754 this.fireEvent("collapsed", this);
36761 animateExpand : function(){
36762 this.beforeSlide();
36763 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36764 this.el.setStyle("z-index", 20000);
36765 this.collapsedEl.hide({
36768 this.el.slideIn(this.getSlideAnchor(), {
36769 callback : function(){
36770 this.el.setStyle("z-index", "");
36773 this.split.el.show();
36775 this.fireEvent("invalidated", this);
36776 this.fireEvent("expanded", this);
36804 getAnchor : function(){
36805 return this.anchors[this.position];
36808 getCollapseAnchor : function(){
36809 return this.canchors[this.position];
36812 getSlideAnchor : function(){
36813 return this.sanchors[this.position];
36816 getAlignAdj : function(){
36817 var cm = this.cmargins;
36818 switch(this.position){
36834 getExpandAdj : function(){
36835 var c = this.collapsedEl, cm = this.cmargins;
36836 switch(this.position){
36838 return [-(cm.right+c.getWidth()+cm.left), 0];
36841 return [cm.right+c.getWidth()+cm.left, 0];
36844 return [0, -(cm.top+cm.bottom+c.getHeight())];
36847 return [0, cm.top+cm.bottom+c.getHeight()];
36853 * Ext JS Library 1.1.1
36854 * Copyright(c) 2006-2007, Ext JS, LLC.
36856 * Originally Released Under LGPL - original licence link has changed is not relivant.
36859 * <script type="text/javascript">
36862 * These classes are private internal classes
36864 Roo.bootstrap.layout.Center = function(config){
36865 config.region = "center";
36866 Roo.bootstrap.layout.Region.call(this, config);
36867 this.visible = true;
36868 this.minWidth = config.minWidth || 20;
36869 this.minHeight = config.minHeight || 20;
36872 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36874 // center panel can't be hidden
36878 // center panel can't be hidden
36881 getMinWidth: function(){
36882 return this.minWidth;
36885 getMinHeight: function(){
36886 return this.minHeight;
36899 Roo.bootstrap.layout.North = function(config)
36901 config.region = 'north';
36902 config.cursor = 'n-resize';
36904 Roo.bootstrap.layout.Split.call(this, config);
36908 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36909 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36910 this.split.el.addClass("roo-layout-split-v");
36912 var size = config.initialSize || config.height;
36913 if(typeof size != "undefined"){
36914 this.el.setHeight(size);
36917 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36919 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36923 getBox : function(){
36924 if(this.collapsed){
36925 return this.collapsedEl.getBox();
36927 var box = this.el.getBox();
36929 box.height += this.split.el.getHeight();
36934 updateBox : function(box){
36935 if(this.split && !this.collapsed){
36936 box.height -= this.split.el.getHeight();
36937 this.split.el.setLeft(box.x);
36938 this.split.el.setTop(box.y+box.height);
36939 this.split.el.setWidth(box.width);
36941 if(this.collapsed){
36942 this.updateBody(box.width, null);
36944 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36952 Roo.bootstrap.layout.South = function(config){
36953 config.region = 'south';
36954 config.cursor = 's-resize';
36955 Roo.bootstrap.layout.Split.call(this, config);
36957 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36958 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36959 this.split.el.addClass("roo-layout-split-v");
36961 var size = config.initialSize || config.height;
36962 if(typeof size != "undefined"){
36963 this.el.setHeight(size);
36967 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36968 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36969 getBox : function(){
36970 if(this.collapsed){
36971 return this.collapsedEl.getBox();
36973 var box = this.el.getBox();
36975 var sh = this.split.el.getHeight();
36982 updateBox : function(box){
36983 if(this.split && !this.collapsed){
36984 var sh = this.split.el.getHeight();
36987 this.split.el.setLeft(box.x);
36988 this.split.el.setTop(box.y-sh);
36989 this.split.el.setWidth(box.width);
36991 if(this.collapsed){
36992 this.updateBody(box.width, null);
36994 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36998 Roo.bootstrap.layout.East = function(config){
36999 config.region = "east";
37000 config.cursor = "e-resize";
37001 Roo.bootstrap.layout.Split.call(this, config);
37003 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37004 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37005 this.split.el.addClass("roo-layout-split-h");
37007 var size = config.initialSize || config.width;
37008 if(typeof size != "undefined"){
37009 this.el.setWidth(size);
37012 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37013 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37014 getBox : function(){
37015 if(this.collapsed){
37016 return this.collapsedEl.getBox();
37018 var box = this.el.getBox();
37020 var sw = this.split.el.getWidth();
37027 updateBox : function(box){
37028 if(this.split && !this.collapsed){
37029 var sw = this.split.el.getWidth();
37031 this.split.el.setLeft(box.x);
37032 this.split.el.setTop(box.y);
37033 this.split.el.setHeight(box.height);
37036 if(this.collapsed){
37037 this.updateBody(null, box.height);
37039 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37043 Roo.bootstrap.layout.West = function(config){
37044 config.region = "west";
37045 config.cursor = "w-resize";
37047 Roo.bootstrap.layout.Split.call(this, config);
37049 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37050 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37051 this.split.el.addClass("roo-layout-split-h");
37055 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37056 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37058 onRender: function(ctr, pos)
37060 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37061 var size = this.config.initialSize || this.config.width;
37062 if(typeof size != "undefined"){
37063 this.el.setWidth(size);
37067 getBox : function(){
37068 if(this.collapsed){
37069 return this.collapsedEl.getBox();
37071 var box = this.el.getBox();
37073 box.width += this.split.el.getWidth();
37078 updateBox : function(box){
37079 if(this.split && !this.collapsed){
37080 var sw = this.split.el.getWidth();
37082 this.split.el.setLeft(box.x+box.width);
37083 this.split.el.setTop(box.y);
37084 this.split.el.setHeight(box.height);
37086 if(this.collapsed){
37087 this.updateBody(null, box.height);
37089 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37092 Roo.namespace("Roo.bootstrap.panel");/*
37094 * Ext JS Library 1.1.1
37095 * Copyright(c) 2006-2007, Ext JS, LLC.
37097 * Originally Released Under LGPL - original licence link has changed is not relivant.
37100 * <script type="text/javascript">
37103 * @class Roo.ContentPanel
37104 * @extends Roo.util.Observable
37105 * A basic ContentPanel element.
37106 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37107 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37108 * @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
37109 * @cfg {Boolean} closable True if the panel can be closed/removed
37110 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37111 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37112 * @cfg {Toolbar} toolbar A toolbar for this panel
37113 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37114 * @cfg {String} title The title for this panel
37115 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37116 * @cfg {String} url Calls {@link #setUrl} with this value
37117 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37118 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37119 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37120 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37121 * @cfg {Boolean} badges render the badges
37124 * Create a new ContentPanel.
37125 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37126 * @param {String/Object} config A string to set only the title or a config object
37127 * @param {String} content (optional) Set the HTML content for this panel
37128 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37130 Roo.bootstrap.panel.Content = function( config){
37132 this.tpl = config.tpl || false;
37134 var el = config.el;
37135 var content = config.content;
37137 if(config.autoCreate){ // xtype is available if this is called from factory
37140 this.el = Roo.get(el);
37141 if(!this.el && config && config.autoCreate){
37142 if(typeof config.autoCreate == "object"){
37143 if(!config.autoCreate.id){
37144 config.autoCreate.id = config.id||el;
37146 this.el = Roo.DomHelper.append(document.body,
37147 config.autoCreate, true);
37149 var elcfg = { tag: "div",
37150 cls: "roo-layout-inactive-content",
37154 elcfg.html = config.html;
37158 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37161 this.closable = false;
37162 this.loaded = false;
37163 this.active = false;
37166 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37168 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37170 this.wrapEl = this.el; //this.el.wrap();
37172 if (config.toolbar.items) {
37173 ti = config.toolbar.items ;
37174 delete config.toolbar.items ;
37178 this.toolbar.render(this.wrapEl, 'before');
37179 for(var i =0;i < ti.length;i++) {
37180 // Roo.log(['add child', items[i]]);
37181 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37183 this.toolbar.items = nitems;
37184 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37185 delete config.toolbar;
37189 // xtype created footer. - not sure if will work as we normally have to render first..
37190 if (this.footer && !this.footer.el && this.footer.xtype) {
37191 if (!this.wrapEl) {
37192 this.wrapEl = this.el.wrap();
37195 this.footer.container = this.wrapEl.createChild();
37197 this.footer = Roo.factory(this.footer, Roo);
37202 if(typeof config == "string"){
37203 this.title = config;
37205 Roo.apply(this, config);
37209 this.resizeEl = Roo.get(this.resizeEl, true);
37211 this.resizeEl = this.el;
37213 // handle view.xtype
37221 * Fires when this panel is activated.
37222 * @param {Roo.ContentPanel} this
37226 * @event deactivate
37227 * Fires when this panel is activated.
37228 * @param {Roo.ContentPanel} this
37230 "deactivate" : true,
37234 * Fires when this panel is resized if fitToFrame is true.
37235 * @param {Roo.ContentPanel} this
37236 * @param {Number} width The width after any component adjustments
37237 * @param {Number} height The height after any component adjustments
37243 * Fires when this tab is created
37244 * @param {Roo.ContentPanel} this
37255 if(this.autoScroll){
37256 this.resizeEl.setStyle("overflow", "auto");
37258 // fix randome scrolling
37259 //this.el.on('scroll', function() {
37260 // Roo.log('fix random scolling');
37261 // this.scrollTo('top',0);
37264 content = content || this.content;
37266 this.setContent(content);
37268 if(config && config.url){
37269 this.setUrl(this.url, this.params, this.loadOnce);
37274 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37276 if (this.view && typeof(this.view.xtype) != 'undefined') {
37277 this.view.el = this.el.appendChild(document.createElement("div"));
37278 this.view = Roo.factory(this.view);
37279 this.view.render && this.view.render(false, '');
37283 this.fireEvent('render', this);
37286 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37290 setRegion : function(region){
37291 this.region = region;
37292 this.setActiveClass(region && !this.background);
37296 setActiveClass: function(state)
37299 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37300 this.el.setStyle('position','relative');
37302 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37303 this.el.setStyle('position', 'absolute');
37308 * Returns the toolbar for this Panel if one was configured.
37309 * @return {Roo.Toolbar}
37311 getToolbar : function(){
37312 return this.toolbar;
37315 setActiveState : function(active)
37317 this.active = active;
37318 this.setActiveClass(active);
37320 if(this.fireEvent("deactivate", this) === false){
37325 this.fireEvent("activate", this);
37329 * Updates this panel's element
37330 * @param {String} content The new content
37331 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37333 setContent : function(content, loadScripts){
37334 this.el.update(content, loadScripts);
37337 ignoreResize : function(w, h){
37338 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37341 this.lastSize = {width: w, height: h};
37346 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37347 * @return {Roo.UpdateManager} The UpdateManager
37349 getUpdateManager : function(){
37350 return this.el.getUpdateManager();
37353 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37354 * @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:
37357 url: "your-url.php",
37358 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37359 callback: yourFunction,
37360 scope: yourObject, //(optional scope)
37363 text: "Loading...",
37368 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37369 * 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.
37370 * @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}
37371 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37372 * @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.
37373 * @return {Roo.ContentPanel} this
37376 var um = this.el.getUpdateManager();
37377 um.update.apply(um, arguments);
37383 * 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.
37384 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37385 * @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)
37386 * @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)
37387 * @return {Roo.UpdateManager} The UpdateManager
37389 setUrl : function(url, params, loadOnce){
37390 if(this.refreshDelegate){
37391 this.removeListener("activate", this.refreshDelegate);
37393 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37394 this.on("activate", this.refreshDelegate);
37395 return this.el.getUpdateManager();
37398 _handleRefresh : function(url, params, loadOnce){
37399 if(!loadOnce || !this.loaded){
37400 var updater = this.el.getUpdateManager();
37401 updater.update(url, params, this._setLoaded.createDelegate(this));
37405 _setLoaded : function(){
37406 this.loaded = true;
37410 * Returns this panel's id
37413 getId : function(){
37418 * Returns this panel's element - used by regiosn to add.
37419 * @return {Roo.Element}
37421 getEl : function(){
37422 return this.wrapEl || this.el;
37427 adjustForComponents : function(width, height)
37429 //Roo.log('adjustForComponents ');
37430 if(this.resizeEl != this.el){
37431 width -= this.el.getFrameWidth('lr');
37432 height -= this.el.getFrameWidth('tb');
37435 var te = this.toolbar.getEl();
37436 te.setWidth(width);
37437 height -= te.getHeight();
37440 var te = this.footer.getEl();
37441 te.setWidth(width);
37442 height -= te.getHeight();
37446 if(this.adjustments){
37447 width += this.adjustments[0];
37448 height += this.adjustments[1];
37450 return {"width": width, "height": height};
37453 setSize : function(width, height){
37454 if(this.fitToFrame && !this.ignoreResize(width, height)){
37455 if(this.fitContainer && this.resizeEl != this.el){
37456 this.el.setSize(width, height);
37458 var size = this.adjustForComponents(width, height);
37459 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37460 this.fireEvent('resize', this, size.width, size.height);
37465 * Returns this panel's title
37468 getTitle : function(){
37470 if (typeof(this.title) != 'object') {
37475 for (var k in this.title) {
37476 if (!this.title.hasOwnProperty(k)) {
37480 if (k.indexOf('-') >= 0) {
37481 var s = k.split('-');
37482 for (var i = 0; i<s.length; i++) {
37483 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37486 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37493 * Set this panel's title
37494 * @param {String} title
37496 setTitle : function(title){
37497 this.title = title;
37499 this.region.updatePanelTitle(this, title);
37504 * Returns true is this panel was configured to be closable
37505 * @return {Boolean}
37507 isClosable : function(){
37508 return this.closable;
37511 beforeSlide : function(){
37513 this.resizeEl.clip();
37516 afterSlide : function(){
37518 this.resizeEl.unclip();
37522 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37523 * Will fail silently if the {@link #setUrl} method has not been called.
37524 * This does not activate the panel, just updates its content.
37526 refresh : function(){
37527 if(this.refreshDelegate){
37528 this.loaded = false;
37529 this.refreshDelegate();
37534 * Destroys this panel
37536 destroy : function(){
37537 this.el.removeAllListeners();
37538 var tempEl = document.createElement("span");
37539 tempEl.appendChild(this.el.dom);
37540 tempEl.innerHTML = "";
37546 * form - if the content panel contains a form - this is a reference to it.
37547 * @type {Roo.form.Form}
37551 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37552 * This contains a reference to it.
37558 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37568 * @param {Object} cfg Xtype definition of item to add.
37572 getChildContainer: function () {
37573 return this.getEl();
37578 var ret = new Roo.factory(cfg);
37583 if (cfg.xtype.match(/^Form$/)) {
37586 //if (this.footer) {
37587 // el = this.footer.container.insertSibling(false, 'before');
37589 el = this.el.createChild();
37592 this.form = new Roo.form.Form(cfg);
37595 if ( this.form.allItems.length) {
37596 this.form.render(el.dom);
37600 // should only have one of theses..
37601 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37602 // views.. should not be just added - used named prop 'view''
37604 cfg.el = this.el.appendChild(document.createElement("div"));
37607 var ret = new Roo.factory(cfg);
37609 ret.render && ret.render(false, ''); // render blank..
37619 * @class Roo.bootstrap.panel.Grid
37620 * @extends Roo.bootstrap.panel.Content
37622 * Create a new GridPanel.
37623 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37624 * @param {Object} config A the config object
37630 Roo.bootstrap.panel.Grid = function(config)
37634 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37635 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37637 config.el = this.wrapper;
37638 //this.el = this.wrapper;
37640 if (config.container) {
37641 // ctor'ed from a Border/panel.grid
37644 this.wrapper.setStyle("overflow", "hidden");
37645 this.wrapper.addClass('roo-grid-container');
37650 if(config.toolbar){
37651 var tool_el = this.wrapper.createChild();
37652 this.toolbar = Roo.factory(config.toolbar);
37654 if (config.toolbar.items) {
37655 ti = config.toolbar.items ;
37656 delete config.toolbar.items ;
37660 this.toolbar.render(tool_el);
37661 for(var i =0;i < ti.length;i++) {
37662 // Roo.log(['add child', items[i]]);
37663 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37665 this.toolbar.items = nitems;
37667 delete config.toolbar;
37670 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37671 config.grid.scrollBody = true;;
37672 config.grid.monitorWindowResize = false; // turn off autosizing
37673 config.grid.autoHeight = false;
37674 config.grid.autoWidth = false;
37676 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37678 if (config.background) {
37679 // render grid on panel activation (if panel background)
37680 this.on('activate', function(gp) {
37681 if (!gp.grid.rendered) {
37682 gp.grid.render(this.wrapper);
37683 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37688 this.grid.render(this.wrapper);
37689 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37692 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37693 // ??? needed ??? config.el = this.wrapper;
37698 // xtype created footer. - not sure if will work as we normally have to render first..
37699 if (this.footer && !this.footer.el && this.footer.xtype) {
37701 var ctr = this.grid.getView().getFooterPanel(true);
37702 this.footer.dataSource = this.grid.dataSource;
37703 this.footer = Roo.factory(this.footer, Roo);
37704 this.footer.render(ctr);
37714 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37715 getId : function(){
37716 return this.grid.id;
37720 * Returns the grid for this panel
37721 * @return {Roo.bootstrap.Table}
37723 getGrid : function(){
37727 setSize : function(width, height){
37728 if(!this.ignoreResize(width, height)){
37729 var grid = this.grid;
37730 var size = this.adjustForComponents(width, height);
37731 var gridel = grid.getGridEl();
37732 gridel.setSize(size.width, size.height);
37734 var thd = grid.getGridEl().select('thead',true).first();
37735 var tbd = grid.getGridEl().select('tbody', true).first();
37737 tbd.setSize(width, height - thd.getHeight());
37746 beforeSlide : function(){
37747 this.grid.getView().scroller.clip();
37750 afterSlide : function(){
37751 this.grid.getView().scroller.unclip();
37754 destroy : function(){
37755 this.grid.destroy();
37757 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37762 * @class Roo.bootstrap.panel.Nest
37763 * @extends Roo.bootstrap.panel.Content
37765 * Create a new Panel, that can contain a layout.Border.
37768 * @param {Roo.BorderLayout} layout The layout for this panel
37769 * @param {String/Object} config A string to set only the title or a config object
37771 Roo.bootstrap.panel.Nest = function(config)
37773 // construct with only one argument..
37774 /* FIXME - implement nicer consturctors
37775 if (layout.layout) {
37777 layout = config.layout;
37778 delete config.layout;
37780 if (layout.xtype && !layout.getEl) {
37781 // then layout needs constructing..
37782 layout = Roo.factory(layout, Roo);
37786 config.el = config.layout.getEl();
37788 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37790 config.layout.monitorWindowResize = false; // turn off autosizing
37791 this.layout = config.layout;
37792 this.layout.getEl().addClass("roo-layout-nested-layout");
37799 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37801 setSize : function(width, height){
37802 if(!this.ignoreResize(width, height)){
37803 var size = this.adjustForComponents(width, height);
37804 var el = this.layout.getEl();
37805 if (size.height < 1) {
37806 el.setWidth(size.width);
37808 el.setSize(size.width, size.height);
37810 var touch = el.dom.offsetWidth;
37811 this.layout.layout();
37812 // ie requires a double layout on the first pass
37813 if(Roo.isIE && !this.initialized){
37814 this.initialized = true;
37815 this.layout.layout();
37820 // activate all subpanels if not currently active..
37822 setActiveState : function(active){
37823 this.active = active;
37824 this.setActiveClass(active);
37827 this.fireEvent("deactivate", this);
37831 this.fireEvent("activate", this);
37832 // not sure if this should happen before or after..
37833 if (!this.layout) {
37834 return; // should not happen..
37837 for (var r in this.layout.regions) {
37838 reg = this.layout.getRegion(r);
37839 if (reg.getActivePanel()) {
37840 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37841 reg.setActivePanel(reg.getActivePanel());
37844 if (!reg.panels.length) {
37847 reg.showPanel(reg.getPanel(0));
37856 * Returns the nested BorderLayout for this panel
37857 * @return {Roo.BorderLayout}
37859 getLayout : function(){
37860 return this.layout;
37864 * Adds a xtype elements to the layout of the nested panel
37868 xtype : 'ContentPanel',
37875 xtype : 'NestedLayoutPanel',
37881 items : [ ... list of content panels or nested layout panels.. ]
37885 * @param {Object} cfg Xtype definition of item to add.
37887 addxtype : function(cfg) {
37888 return this.layout.addxtype(cfg);
37893 * Ext JS Library 1.1.1
37894 * Copyright(c) 2006-2007, Ext JS, LLC.
37896 * Originally Released Under LGPL - original licence link has changed is not relivant.
37899 * <script type="text/javascript">
37902 * @class Roo.TabPanel
37903 * @extends Roo.util.Observable
37904 * A lightweight tab container.
37908 // basic tabs 1, built from existing content
37909 var tabs = new Roo.TabPanel("tabs1");
37910 tabs.addTab("script", "View Script");
37911 tabs.addTab("markup", "View Markup");
37912 tabs.activate("script");
37914 // more advanced tabs, built from javascript
37915 var jtabs = new Roo.TabPanel("jtabs");
37916 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37918 // set up the UpdateManager
37919 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37920 var updater = tab2.getUpdateManager();
37921 updater.setDefaultUrl("ajax1.htm");
37922 tab2.on('activate', updater.refresh, updater, true);
37924 // Use setUrl for Ajax loading
37925 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37926 tab3.setUrl("ajax2.htm", null, true);
37929 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37932 jtabs.activate("jtabs-1");
37935 * Create a new TabPanel.
37936 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37937 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37939 Roo.bootstrap.panel.Tabs = function(config){
37941 * The container element for this TabPanel.
37942 * @type Roo.Element
37944 this.el = Roo.get(config.el);
37947 if(typeof config == "boolean"){
37948 this.tabPosition = config ? "bottom" : "top";
37950 Roo.apply(this, config);
37954 if(this.tabPosition == "bottom"){
37955 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37956 this.el.addClass("roo-tabs-bottom");
37958 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37959 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37960 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
37961 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37963 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37965 if(this.tabPosition != "bottom"){
37966 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37967 * @type Roo.Element
37969 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37970 this.el.addClass("roo-tabs-top");
37974 this.bodyEl.setStyle("position", "relative");
37976 this.active = null;
37977 this.activateDelegate = this.activate.createDelegate(this);
37982 * Fires when the active tab changes
37983 * @param {Roo.TabPanel} this
37984 * @param {Roo.TabPanelItem} activePanel The new active tab
37988 * @event beforetabchange
37989 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37990 * @param {Roo.TabPanel} this
37991 * @param {Object} e Set cancel to true on this object to cancel the tab change
37992 * @param {Roo.TabPanelItem} tab The tab being changed to
37994 "beforetabchange" : true
37997 Roo.EventManager.onWindowResize(this.onResize, this);
37998 this.cpad = this.el.getPadding("lr");
37999 this.hiddenCount = 0;
38002 // toolbar on the tabbar support...
38003 if (this.toolbar) {
38004 alert("no toolbar support yet");
38005 this.toolbar = false;
38007 var tcfg = this.toolbar;
38008 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38009 this.toolbar = new Roo.Toolbar(tcfg);
38010 if (Roo.isSafari) {
38011 var tbl = tcfg.container.child('table', true);
38012 tbl.setAttribute('width', '100%');
38020 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38023 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38025 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38027 tabPosition : "top",
38029 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38031 currentTabWidth : 0,
38033 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38037 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38041 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38043 preferredTabWidth : 175,
38045 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38047 resizeTabs : false,
38049 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38051 monitorResize : true,
38053 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38058 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38059 * @param {String} id The id of the div to use <b>or create</b>
38060 * @param {String} text The text for the tab
38061 * @param {String} content (optional) Content to put in the TabPanelItem body
38062 * @param {Boolean} closable (optional) True to create a close icon on the tab
38063 * @return {Roo.TabPanelItem} The created TabPanelItem
38065 addTab : function(id, text, content, closable, tpl)
38067 var item = new Roo.bootstrap.panel.TabItem({
38071 closable : closable,
38074 this.addTabItem(item);
38076 item.setContent(content);
38082 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38083 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38084 * @return {Roo.TabPanelItem}
38086 getTab : function(id){
38087 return this.items[id];
38091 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38092 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38094 hideTab : function(id){
38095 var t = this.items[id];
38098 this.hiddenCount++;
38099 this.autoSizeTabs();
38104 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38105 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38107 unhideTab : function(id){
38108 var t = this.items[id];
38110 t.setHidden(false);
38111 this.hiddenCount--;
38112 this.autoSizeTabs();
38117 * Adds an existing {@link Roo.TabPanelItem}.
38118 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38120 addTabItem : function(item)
38122 this.items[item.id] = item;
38123 this.items.push(item);
38124 this.autoSizeTabs();
38125 // if(this.resizeTabs){
38126 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38127 // this.autoSizeTabs();
38129 // item.autoSize();
38134 * Removes a {@link Roo.TabPanelItem}.
38135 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38137 removeTab : function(id){
38138 var items = this.items;
38139 var tab = items[id];
38140 if(!tab) { return; }
38141 var index = items.indexOf(tab);
38142 if(this.active == tab && items.length > 1){
38143 var newTab = this.getNextAvailable(index);
38148 this.stripEl.dom.removeChild(tab.pnode.dom);
38149 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38150 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38152 items.splice(index, 1);
38153 delete this.items[tab.id];
38154 tab.fireEvent("close", tab);
38155 tab.purgeListeners();
38156 this.autoSizeTabs();
38159 getNextAvailable : function(start){
38160 var items = this.items;
38162 // look for a next tab that will slide over to
38163 // replace the one being removed
38164 while(index < items.length){
38165 var item = items[++index];
38166 if(item && !item.isHidden()){
38170 // if one isn't found select the previous tab (on the left)
38173 var item = items[--index];
38174 if(item && !item.isHidden()){
38182 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38183 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38185 disableTab : function(id){
38186 var tab = this.items[id];
38187 if(tab && this.active != tab){
38193 * Enables a {@link Roo.TabPanelItem} that is disabled.
38194 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38196 enableTab : function(id){
38197 var tab = this.items[id];
38202 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38203 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38204 * @return {Roo.TabPanelItem} The TabPanelItem.
38206 activate : function(id)
38208 var tab = this.items[id];
38212 if(tab == this.active || tab.disabled){
38216 this.fireEvent("beforetabchange", this, e, tab);
38217 if(e.cancel !== true && !tab.disabled){
38219 this.active.hide();
38221 this.active = this.items[id];
38222 this.active.show();
38223 this.fireEvent("tabchange", this, this.active);
38229 * Gets the active {@link Roo.TabPanelItem}.
38230 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38232 getActiveTab : function(){
38233 return this.active;
38237 * Updates the tab body element to fit the height of the container element
38238 * for overflow scrolling
38239 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38241 syncHeight : function(targetHeight){
38242 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38243 var bm = this.bodyEl.getMargins();
38244 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38245 this.bodyEl.setHeight(newHeight);
38249 onResize : function(){
38250 if(this.monitorResize){
38251 this.autoSizeTabs();
38256 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38258 beginUpdate : function(){
38259 this.updating = true;
38263 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38265 endUpdate : function(){
38266 this.updating = false;
38267 this.autoSizeTabs();
38271 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38273 autoSizeTabs : function()
38275 var count = this.items.length;
38276 var vcount = count - this.hiddenCount;
38279 this.stripEl.hide();
38281 this.stripEl.show();
38284 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38289 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38290 var availWidth = Math.floor(w / vcount);
38291 var b = this.stripBody;
38292 if(b.getWidth() > w){
38293 var tabs = this.items;
38294 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38295 if(availWidth < this.minTabWidth){
38296 /*if(!this.sleft){ // incomplete scrolling code
38297 this.createScrollButtons();
38300 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38303 if(this.currentTabWidth < this.preferredTabWidth){
38304 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38310 * Returns the number of tabs in this TabPanel.
38313 getCount : function(){
38314 return this.items.length;
38318 * Resizes all the tabs to the passed width
38319 * @param {Number} The new width
38321 setTabWidth : function(width){
38322 this.currentTabWidth = width;
38323 for(var i = 0, len = this.items.length; i < len; i++) {
38324 if(!this.items[i].isHidden()) {
38325 this.items[i].setWidth(width);
38331 * Destroys this TabPanel
38332 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38334 destroy : function(removeEl){
38335 Roo.EventManager.removeResizeListener(this.onResize, this);
38336 for(var i = 0, len = this.items.length; i < len; i++){
38337 this.items[i].purgeListeners();
38339 if(removeEl === true){
38340 this.el.update("");
38345 createStrip : function(container)
38347 var strip = document.createElement("nav");
38348 strip.className = Roo.bootstrap.version == 4 ?
38349 "navbar-light bg-light" :
38350 "navbar navbar-default"; //"x-tabs-wrap";
38351 container.appendChild(strip);
38355 createStripList : function(strip)
38357 // div wrapper for retard IE
38358 // returns the "tr" element.
38359 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38360 //'<div class="x-tabs-strip-wrap">'+
38361 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38362 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38363 return strip.firstChild; //.firstChild.firstChild.firstChild;
38365 createBody : function(container)
38367 var body = document.createElement("div");
38368 Roo.id(body, "tab-body");
38369 //Roo.fly(body).addClass("x-tabs-body");
38370 Roo.fly(body).addClass("tab-content");
38371 container.appendChild(body);
38374 createItemBody :function(bodyEl, id){
38375 var body = Roo.getDom(id);
38377 body = document.createElement("div");
38380 //Roo.fly(body).addClass("x-tabs-item-body");
38381 Roo.fly(body).addClass("tab-pane");
38382 bodyEl.insertBefore(body, bodyEl.firstChild);
38386 createStripElements : function(stripEl, text, closable, tpl)
38388 var td = document.createElement("li"); // was td..
38389 td.className = 'nav-item';
38391 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38394 stripEl.appendChild(td);
38396 td.className = "x-tabs-closable";
38397 if(!this.closeTpl){
38398 this.closeTpl = new Roo.Template(
38399 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38400 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38401 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38404 var el = this.closeTpl.overwrite(td, {"text": text});
38405 var close = el.getElementsByTagName("div")[0];
38406 var inner = el.getElementsByTagName("em")[0];
38407 return {"el": el, "close": close, "inner": inner};
38410 // not sure what this is..
38411 // if(!this.tabTpl){
38412 //this.tabTpl = new Roo.Template(
38413 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38414 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38416 // this.tabTpl = new Roo.Template(
38417 // '<a href="#">' +
38418 // '<span unselectable="on"' +
38419 // (this.disableTooltips ? '' : ' title="{text}"') +
38420 // ' >{text}</span></a>'
38426 var template = tpl || this.tabTpl || false;
38429 template = new Roo.Template(
38430 Roo.bootstrap.version == 4 ?
38432 '<a class="nav-link" href="#" unselectable="on"' +
38433 (this.disableTooltips ? '' : ' title="{text}"') +
38436 '<a class="nav-link" href="#">' +
38437 '<span unselectable="on"' +
38438 (this.disableTooltips ? '' : ' title="{text}"') +
38439 ' >{text}</span></a>'
38444 switch (typeof(template)) {
38448 template = new Roo.Template(template);
38454 var el = template.overwrite(td, {"text": text});
38456 var inner = el.getElementsByTagName("span")[0];
38458 return {"el": el, "inner": inner};
38466 * @class Roo.TabPanelItem
38467 * @extends Roo.util.Observable
38468 * Represents an individual item (tab plus body) in a TabPanel.
38469 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38470 * @param {String} id The id of this TabPanelItem
38471 * @param {String} text The text for the tab of this TabPanelItem
38472 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38474 Roo.bootstrap.panel.TabItem = function(config){
38476 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38477 * @type Roo.TabPanel
38479 this.tabPanel = config.panel;
38481 * The id for this TabPanelItem
38484 this.id = config.id;
38486 this.disabled = false;
38488 this.text = config.text;
38490 this.loaded = false;
38491 this.closable = config.closable;
38494 * The body element for this TabPanelItem.
38495 * @type Roo.Element
38497 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38498 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38499 this.bodyEl.setStyle("display", "block");
38500 this.bodyEl.setStyle("zoom", "1");
38501 //this.hideAction();
38503 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38505 this.el = Roo.get(els.el);
38506 this.inner = Roo.get(els.inner, true);
38507 this.textEl = Roo.bootstrap.version == 4 ?
38508 this.el : Roo.get(this.el.dom.firstChild, true);
38510 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38511 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38514 // this.el.on("mousedown", this.onTabMouseDown, this);
38515 this.el.on("click", this.onTabClick, this);
38517 if(config.closable){
38518 var c = Roo.get(els.close, true);
38519 c.dom.title = this.closeText;
38520 c.addClassOnOver("close-over");
38521 c.on("click", this.closeClick, this);
38527 * Fires when this tab becomes the active tab.
38528 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38529 * @param {Roo.TabPanelItem} this
38533 * @event beforeclose
38534 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38535 * @param {Roo.TabPanelItem} this
38536 * @param {Object} e Set cancel to true on this object to cancel the close.
38538 "beforeclose": true,
38541 * Fires when this tab is closed.
38542 * @param {Roo.TabPanelItem} this
38546 * @event deactivate
38547 * Fires when this tab is no longer the active tab.
38548 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38549 * @param {Roo.TabPanelItem} this
38551 "deactivate" : true
38553 this.hidden = false;
38555 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38558 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38560 purgeListeners : function(){
38561 Roo.util.Observable.prototype.purgeListeners.call(this);
38562 this.el.removeAllListeners();
38565 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38568 this.status_node.addClass("active");
38571 this.tabPanel.stripWrap.repaint();
38573 this.fireEvent("activate", this.tabPanel, this);
38577 * Returns true if this tab is the active tab.
38578 * @return {Boolean}
38580 isActive : function(){
38581 return this.tabPanel.getActiveTab() == this;
38585 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38588 this.status_node.removeClass("active");
38590 this.fireEvent("deactivate", this.tabPanel, this);
38593 hideAction : function(){
38594 this.bodyEl.hide();
38595 this.bodyEl.setStyle("position", "absolute");
38596 this.bodyEl.setLeft("-20000px");
38597 this.bodyEl.setTop("-20000px");
38600 showAction : function(){
38601 this.bodyEl.setStyle("position", "relative");
38602 this.bodyEl.setTop("");
38603 this.bodyEl.setLeft("");
38604 this.bodyEl.show();
38608 * Set the tooltip for the tab.
38609 * @param {String} tooltip The tab's tooltip
38611 setTooltip : function(text){
38612 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38613 this.textEl.dom.qtip = text;
38614 this.textEl.dom.removeAttribute('title');
38616 this.textEl.dom.title = text;
38620 onTabClick : function(e){
38621 e.preventDefault();
38622 this.tabPanel.activate(this.id);
38625 onTabMouseDown : function(e){
38626 e.preventDefault();
38627 this.tabPanel.activate(this.id);
38630 getWidth : function(){
38631 return this.inner.getWidth();
38634 setWidth : function(width){
38635 var iwidth = width - this.linode.getPadding("lr");
38636 this.inner.setWidth(iwidth);
38637 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38638 this.linode.setWidth(width);
38642 * Show or hide the tab
38643 * @param {Boolean} hidden True to hide or false to show.
38645 setHidden : function(hidden){
38646 this.hidden = hidden;
38647 this.linode.setStyle("display", hidden ? "none" : "");
38651 * Returns true if this tab is "hidden"
38652 * @return {Boolean}
38654 isHidden : function(){
38655 return this.hidden;
38659 * Returns the text for this tab
38662 getText : function(){
38666 autoSize : function(){
38667 //this.el.beginMeasure();
38668 this.textEl.setWidth(1);
38670 * #2804 [new] Tabs in Roojs
38671 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38673 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38674 //this.el.endMeasure();
38678 * Sets the text for the tab (Note: this also sets the tooltip text)
38679 * @param {String} text The tab's text and tooltip
38681 setText : function(text){
38683 this.textEl.update(text);
38684 this.setTooltip(text);
38685 //if(!this.tabPanel.resizeTabs){
38686 // this.autoSize();
38690 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38692 activate : function(){
38693 this.tabPanel.activate(this.id);
38697 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38699 disable : function(){
38700 if(this.tabPanel.active != this){
38701 this.disabled = true;
38702 this.status_node.addClass("disabled");
38707 * Enables this TabPanelItem if it was previously disabled.
38709 enable : function(){
38710 this.disabled = false;
38711 this.status_node.removeClass("disabled");
38715 * Sets the content for this TabPanelItem.
38716 * @param {String} content The content
38717 * @param {Boolean} loadScripts true to look for and load scripts
38719 setContent : function(content, loadScripts){
38720 this.bodyEl.update(content, loadScripts);
38724 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38725 * @return {Roo.UpdateManager} The UpdateManager
38727 getUpdateManager : function(){
38728 return this.bodyEl.getUpdateManager();
38732 * Set a URL to be used to load the content for this TabPanelItem.
38733 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38734 * @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)
38735 * @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)
38736 * @return {Roo.UpdateManager} The UpdateManager
38738 setUrl : function(url, params, loadOnce){
38739 if(this.refreshDelegate){
38740 this.un('activate', this.refreshDelegate);
38742 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38743 this.on("activate", this.refreshDelegate);
38744 return this.bodyEl.getUpdateManager();
38748 _handleRefresh : function(url, params, loadOnce){
38749 if(!loadOnce || !this.loaded){
38750 var updater = this.bodyEl.getUpdateManager();
38751 updater.update(url, params, this._setLoaded.createDelegate(this));
38756 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38757 * Will fail silently if the setUrl method has not been called.
38758 * This does not activate the panel, just updates its content.
38760 refresh : function(){
38761 if(this.refreshDelegate){
38762 this.loaded = false;
38763 this.refreshDelegate();
38768 _setLoaded : function(){
38769 this.loaded = true;
38773 closeClick : function(e){
38776 this.fireEvent("beforeclose", this, o);
38777 if(o.cancel !== true){
38778 this.tabPanel.removeTab(this.id);
38782 * The text displayed in the tooltip for the close icon.
38785 closeText : "Close this tab"
38788 * This script refer to:
38789 * Title: International Telephone Input
38790 * Author: Jack O'Connor
38791 * Code version: v12.1.12
38792 * Availability: https://github.com/jackocnr/intl-tel-input.git
38795 Roo.bootstrap.PhoneInputData = function() {
38798 "Afghanistan (افغانستان)",
38803 "Albania (Shqipëri)",
38808 "Algeria (الجزائر)",
38833 "Antigua and Barbuda",
38843 "Armenia (Հայաստան)",
38859 "Austria (Österreich)",
38864 "Azerbaijan (Azərbaycan)",
38874 "Bahrain (البحرين)",
38879 "Bangladesh (বাংলাদেশ)",
38889 "Belarus (Беларусь)",
38894 "Belgium (België)",
38924 "Bosnia and Herzegovina (Босна и Херцеговина)",
38939 "British Indian Ocean Territory",
38944 "British Virgin Islands",
38954 "Bulgaria (България)",
38964 "Burundi (Uburundi)",
38969 "Cambodia (កម្ពុជា)",
38974 "Cameroon (Cameroun)",
38983 ["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"]
38986 "Cape Verde (Kabu Verdi)",
38991 "Caribbean Netherlands",
39002 "Central African Republic (République centrafricaine)",
39022 "Christmas Island",
39028 "Cocos (Keeling) Islands",
39039 "Comoros (جزر القمر)",
39044 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39049 "Congo (Republic) (Congo-Brazzaville)",
39069 "Croatia (Hrvatska)",
39090 "Czech Republic (Česká republika)",
39095 "Denmark (Danmark)",
39110 "Dominican Republic (República Dominicana)",
39114 ["809", "829", "849"]
39132 "Equatorial Guinea (Guinea Ecuatorial)",
39152 "Falkland Islands (Islas Malvinas)",
39157 "Faroe Islands (Føroyar)",
39178 "French Guiana (Guyane française)",
39183 "French Polynesia (Polynésie française)",
39198 "Georgia (საქართველო)",
39203 "Germany (Deutschland)",
39223 "Greenland (Kalaallit Nunaat)",
39260 "Guinea-Bissau (Guiné Bissau)",
39285 "Hungary (Magyarország)",
39290 "Iceland (Ísland)",
39310 "Iraq (العراق)",
39326 "Israel (ישראל)",
39353 "Jordan (الأردن)",
39358 "Kazakhstan (Казахстан)",
39379 "Kuwait (الكويت)",
39384 "Kyrgyzstan (Кыргызстан)",
39394 "Latvia (Latvija)",
39399 "Lebanon (لبنان)",
39414 "Libya (ليبيا)",
39424 "Lithuania (Lietuva)",
39439 "Macedonia (FYROM) (Македонија)",
39444 "Madagascar (Madagasikara)",
39474 "Marshall Islands",
39484 "Mauritania (موريتانيا)",
39489 "Mauritius (Moris)",
39510 "Moldova (Republica Moldova)",
39520 "Mongolia (Монгол)",
39525 "Montenegro (Crna Gora)",
39535 "Morocco (المغرب)",
39541 "Mozambique (Moçambique)",
39546 "Myanmar (Burma) (မြန်မာ)",
39551 "Namibia (Namibië)",
39566 "Netherlands (Nederland)",
39571 "New Caledonia (Nouvelle-Calédonie)",
39606 "North Korea (조선 민주주의 인민 공화국)",
39611 "Northern Mariana Islands",
39627 "Pakistan (پاکستان)",
39637 "Palestine (فلسطين)",
39647 "Papua New Guinea",
39689 "Réunion (La Réunion)",
39695 "Romania (România)",
39711 "Saint Barthélemy",
39722 "Saint Kitts and Nevis",
39732 "Saint Martin (Saint-Martin (partie française))",
39738 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39743 "Saint Vincent and the Grenadines",
39758 "São Tomé and Príncipe (São Tomé e Príncipe)",
39763 "Saudi Arabia (المملكة العربية السعودية)",
39768 "Senegal (Sénégal)",
39798 "Slovakia (Slovensko)",
39803 "Slovenia (Slovenija)",
39813 "Somalia (Soomaaliya)",
39823 "South Korea (대한민국)",
39828 "South Sudan (جنوب السودان)",
39838 "Sri Lanka (ශ්රී ලංකාව)",
39843 "Sudan (السودان)",
39853 "Svalbard and Jan Mayen",
39864 "Sweden (Sverige)",
39869 "Switzerland (Schweiz)",
39874 "Syria (سوريا)",
39919 "Trinidad and Tobago",
39924 "Tunisia (تونس)",
39929 "Turkey (Türkiye)",
39939 "Turks and Caicos Islands",
39949 "U.S. Virgin Islands",
39959 "Ukraine (Україна)",
39964 "United Arab Emirates (الإمارات العربية المتحدة)",
39986 "Uzbekistan (Oʻzbekiston)",
39996 "Vatican City (Città del Vaticano)",
40007 "Vietnam (Việt Nam)",
40012 "Wallis and Futuna (Wallis-et-Futuna)",
40017 "Western Sahara (الصحراء الغربية)",
40023 "Yemen (اليمن)",
40047 * This script refer to:
40048 * Title: International Telephone Input
40049 * Author: Jack O'Connor
40050 * Code version: v12.1.12
40051 * Availability: https://github.com/jackocnr/intl-tel-input.git
40055 * @class Roo.bootstrap.PhoneInput
40056 * @extends Roo.bootstrap.TriggerField
40057 * An input with International dial-code selection
40059 * @cfg {String} defaultDialCode default '+852'
40060 * @cfg {Array} preferedCountries default []
40063 * Create a new PhoneInput.
40064 * @param {Object} config Configuration options
40067 Roo.bootstrap.PhoneInput = function(config) {
40068 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40071 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40073 listWidth: undefined,
40075 selectedClass: 'active',
40077 invalidClass : "has-warning",
40079 validClass: 'has-success',
40081 allowed: '0123456789',
40086 * @cfg {String} defaultDialCode The default dial code when initializing the input
40088 defaultDialCode: '+852',
40091 * @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
40093 preferedCountries: false,
40095 getAutoCreate : function()
40097 var data = Roo.bootstrap.PhoneInputData();
40098 var align = this.labelAlign || this.parentLabelAlign();
40101 this.allCountries = [];
40102 this.dialCodeMapping = [];
40104 for (var i = 0; i < data.length; i++) {
40106 this.allCountries[i] = {
40110 priority: c[3] || 0,
40111 areaCodes: c[4] || null
40113 this.dialCodeMapping[c[2]] = {
40116 priority: c[3] || 0,
40117 areaCodes: c[4] || null
40129 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40130 maxlength: this.max_length,
40131 cls : 'form-control tel-input',
40132 autocomplete: 'new-password'
40135 var hiddenInput = {
40138 cls: 'hidden-tel-input'
40142 hiddenInput.name = this.name;
40145 if (this.disabled) {
40146 input.disabled = true;
40149 var flag_container = {
40166 cls: this.hasFeedback ? 'has-feedback' : '',
40172 cls: 'dial-code-holder',
40179 cls: 'roo-select2-container input-group',
40186 if (this.fieldLabel.length) {
40189 tooltip: 'This field is required'
40195 cls: 'control-label',
40201 html: this.fieldLabel
40204 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40210 if(this.indicatorpos == 'right') {
40211 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40218 if(align == 'left') {
40226 if(this.labelWidth > 12){
40227 label.style = "width: " + this.labelWidth + 'px';
40229 if(this.labelWidth < 13 && this.labelmd == 0){
40230 this.labelmd = this.labelWidth;
40232 if(this.labellg > 0){
40233 label.cls += ' col-lg-' + this.labellg;
40234 input.cls += ' col-lg-' + (12 - this.labellg);
40236 if(this.labelmd > 0){
40237 label.cls += ' col-md-' + this.labelmd;
40238 container.cls += ' col-md-' + (12 - this.labelmd);
40240 if(this.labelsm > 0){
40241 label.cls += ' col-sm-' + this.labelsm;
40242 container.cls += ' col-sm-' + (12 - this.labelsm);
40244 if(this.labelxs > 0){
40245 label.cls += ' col-xs-' + this.labelxs;
40246 container.cls += ' col-xs-' + (12 - this.labelxs);
40256 var settings = this;
40258 ['xs','sm','md','lg'].map(function(size){
40259 if (settings[size]) {
40260 cfg.cls += ' col-' + size + '-' + settings[size];
40264 this.store = new Roo.data.Store({
40265 proxy : new Roo.data.MemoryProxy({}),
40266 reader : new Roo.data.JsonReader({
40277 'name' : 'dialCode',
40281 'name' : 'priority',
40285 'name' : 'areaCodes',
40292 if(!this.preferedCountries) {
40293 this.preferedCountries = [
40300 var p = this.preferedCountries.reverse();
40303 for (var i = 0; i < p.length; i++) {
40304 for (var j = 0; j < this.allCountries.length; j++) {
40305 if(this.allCountries[j].iso2 == p[i]) {
40306 var t = this.allCountries[j];
40307 this.allCountries.splice(j,1);
40308 this.allCountries.unshift(t);
40314 this.store.proxy.data = {
40316 data: this.allCountries
40322 initEvents : function()
40325 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40327 this.indicator = this.indicatorEl();
40328 this.flag = this.flagEl();
40329 this.dialCodeHolder = this.dialCodeHolderEl();
40331 this.trigger = this.el.select('div.flag-box',true).first();
40332 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40337 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40338 _this.list.setWidth(lw);
40341 this.list.on('mouseover', this.onViewOver, this);
40342 this.list.on('mousemove', this.onViewMove, this);
40343 this.inputEl().on("keyup", this.onKeyUp, this);
40344 this.inputEl().on("keypress", this.onKeyPress, this);
40346 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40348 this.view = new Roo.View(this.list, this.tpl, {
40349 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40352 this.view.on('click', this.onViewClick, this);
40353 this.setValue(this.defaultDialCode);
40356 onTriggerClick : function(e)
40358 Roo.log('trigger click');
40363 if(this.isExpanded()){
40365 this.hasFocus = false;
40367 this.store.load({});
40368 this.hasFocus = true;
40373 isExpanded : function()
40375 return this.list.isVisible();
40378 collapse : function()
40380 if(!this.isExpanded()){
40384 Roo.get(document).un('mousedown', this.collapseIf, this);
40385 Roo.get(document).un('mousewheel', this.collapseIf, this);
40386 this.fireEvent('collapse', this);
40390 expand : function()
40394 if(this.isExpanded() || !this.hasFocus){
40398 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40399 this.list.setWidth(lw);
40402 this.restrictHeight();
40404 Roo.get(document).on('mousedown', this.collapseIf, this);
40405 Roo.get(document).on('mousewheel', this.collapseIf, this);
40407 this.fireEvent('expand', this);
40410 restrictHeight : function()
40412 this.list.alignTo(this.inputEl(), this.listAlign);
40413 this.list.alignTo(this.inputEl(), this.listAlign);
40416 onViewOver : function(e, t)
40418 if(this.inKeyMode){
40421 var item = this.view.findItemFromChild(t);
40424 var index = this.view.indexOf(item);
40425 this.select(index, false);
40430 onViewClick : function(view, doFocus, el, e)
40432 var index = this.view.getSelectedIndexes()[0];
40434 var r = this.store.getAt(index);
40437 this.onSelect(r, index);
40439 if(doFocus !== false && !this.blockFocus){
40440 this.inputEl().focus();
40444 onViewMove : function(e, t)
40446 this.inKeyMode = false;
40449 select : function(index, scrollIntoView)
40451 this.selectedIndex = index;
40452 this.view.select(index);
40453 if(scrollIntoView !== false){
40454 var el = this.view.getNode(index);
40456 this.list.scrollChildIntoView(el, false);
40461 createList : function()
40463 this.list = Roo.get(document.body).createChild({
40465 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40466 style: 'display:none'
40469 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40472 collapseIf : function(e)
40474 var in_combo = e.within(this.el);
40475 var in_list = e.within(this.list);
40476 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40478 if (in_combo || in_list || is_list) {
40484 onSelect : function(record, index)
40486 if(this.fireEvent('beforeselect', this, record, index) !== false){
40488 this.setFlagClass(record.data.iso2);
40489 this.setDialCode(record.data.dialCode);
40490 this.hasFocus = false;
40492 this.fireEvent('select', this, record, index);
40496 flagEl : function()
40498 var flag = this.el.select('div.flag',true).first();
40505 dialCodeHolderEl : function()
40507 var d = this.el.select('input.dial-code-holder',true).first();
40514 setDialCode : function(v)
40516 this.dialCodeHolder.dom.value = '+'+v;
40519 setFlagClass : function(n)
40521 this.flag.dom.className = 'flag '+n;
40524 getValue : function()
40526 var v = this.inputEl().getValue();
40527 if(this.dialCodeHolder) {
40528 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40533 setValue : function(v)
40535 var d = this.getDialCode(v);
40537 //invalid dial code
40538 if(v.length == 0 || !d || d.length == 0) {
40540 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40541 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40547 this.setFlagClass(this.dialCodeMapping[d].iso2);
40548 this.setDialCode(d);
40549 this.inputEl().dom.value = v.replace('+'+d,'');
40550 this.hiddenEl().dom.value = this.getValue();
40555 getDialCode : function(v)
40559 if (v.length == 0) {
40560 return this.dialCodeHolder.dom.value;
40564 if (v.charAt(0) != "+") {
40567 var numericChars = "";
40568 for (var i = 1; i < v.length; i++) {
40569 var c = v.charAt(i);
40572 if (this.dialCodeMapping[numericChars]) {
40573 dialCode = v.substr(1, i);
40575 if (numericChars.length == 4) {
40585 this.setValue(this.defaultDialCode);
40589 hiddenEl : function()
40591 return this.el.select('input.hidden-tel-input',true).first();
40594 // after setting val
40595 onKeyUp : function(e){
40596 this.setValue(this.getValue());
40599 onKeyPress : function(e){
40600 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40607 * @class Roo.bootstrap.MoneyField
40608 * @extends Roo.bootstrap.ComboBox
40609 * Bootstrap MoneyField class
40612 * Create a new MoneyField.
40613 * @param {Object} config Configuration options
40616 Roo.bootstrap.MoneyField = function(config) {
40618 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40622 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40625 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40627 allowDecimals : true,
40629 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40631 decimalSeparator : ".",
40633 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40635 decimalPrecision : 0,
40637 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40639 allowNegative : true,
40641 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40645 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40647 minValue : Number.NEGATIVE_INFINITY,
40649 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40651 maxValue : Number.MAX_VALUE,
40653 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40655 minText : "The minimum value for this field is {0}",
40657 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40659 maxText : "The maximum value for this field is {0}",
40661 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40662 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40664 nanText : "{0} is not a valid number",
40666 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40670 * @cfg {String} defaults currency of the MoneyField
40671 * value should be in lkey
40673 defaultCurrency : false,
40675 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40677 thousandsDelimiter : false,
40679 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40690 getAutoCreate : function()
40692 var align = this.labelAlign || this.parentLabelAlign();
40704 cls : 'form-control roo-money-amount-input',
40705 autocomplete: 'new-password'
40708 var hiddenInput = {
40712 cls: 'hidden-number-input'
40715 if(this.max_length) {
40716 input.maxlength = this.max_length;
40720 hiddenInput.name = this.name;
40723 if (this.disabled) {
40724 input.disabled = true;
40727 var clg = 12 - this.inputlg;
40728 var cmd = 12 - this.inputmd;
40729 var csm = 12 - this.inputsm;
40730 var cxs = 12 - this.inputxs;
40734 cls : 'row roo-money-field',
40738 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40742 cls: 'roo-select2-container input-group',
40746 cls : 'form-control roo-money-currency-input',
40747 autocomplete: 'new-password',
40749 name : this.currencyName
40753 cls : 'input-group-addon',
40767 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40771 cls: this.hasFeedback ? 'has-feedback' : '',
40782 if (this.fieldLabel.length) {
40785 tooltip: 'This field is required'
40791 cls: 'control-label',
40797 html: this.fieldLabel
40800 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40806 if(this.indicatorpos == 'right') {
40807 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40814 if(align == 'left') {
40822 if(this.labelWidth > 12){
40823 label.style = "width: " + this.labelWidth + 'px';
40825 if(this.labelWidth < 13 && this.labelmd == 0){
40826 this.labelmd = this.labelWidth;
40828 if(this.labellg > 0){
40829 label.cls += ' col-lg-' + this.labellg;
40830 input.cls += ' col-lg-' + (12 - this.labellg);
40832 if(this.labelmd > 0){
40833 label.cls += ' col-md-' + this.labelmd;
40834 container.cls += ' col-md-' + (12 - this.labelmd);
40836 if(this.labelsm > 0){
40837 label.cls += ' col-sm-' + this.labelsm;
40838 container.cls += ' col-sm-' + (12 - this.labelsm);
40840 if(this.labelxs > 0){
40841 label.cls += ' col-xs-' + this.labelxs;
40842 container.cls += ' col-xs-' + (12 - this.labelxs);
40853 var settings = this;
40855 ['xs','sm','md','lg'].map(function(size){
40856 if (settings[size]) {
40857 cfg.cls += ' col-' + size + '-' + settings[size];
40864 initEvents : function()
40866 this.indicator = this.indicatorEl();
40868 this.initCurrencyEvent();
40870 this.initNumberEvent();
40873 initCurrencyEvent : function()
40876 throw "can not find store for combo";
40879 this.store = Roo.factory(this.store, Roo.data);
40880 this.store.parent = this;
40884 this.triggerEl = this.el.select('.input-group-addon', true).first();
40886 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40891 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40892 _this.list.setWidth(lw);
40895 this.list.on('mouseover', this.onViewOver, this);
40896 this.list.on('mousemove', this.onViewMove, this);
40897 this.list.on('scroll', this.onViewScroll, this);
40900 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40903 this.view = new Roo.View(this.list, this.tpl, {
40904 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40907 this.view.on('click', this.onViewClick, this);
40909 this.store.on('beforeload', this.onBeforeLoad, this);
40910 this.store.on('load', this.onLoad, this);
40911 this.store.on('loadexception', this.onLoadException, this);
40913 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40914 "up" : function(e){
40915 this.inKeyMode = true;
40919 "down" : function(e){
40920 if(!this.isExpanded()){
40921 this.onTriggerClick();
40923 this.inKeyMode = true;
40928 "enter" : function(e){
40931 if(this.fireEvent("specialkey", this, e)){
40932 this.onViewClick(false);
40938 "esc" : function(e){
40942 "tab" : function(e){
40945 if(this.fireEvent("specialkey", this, e)){
40946 this.onViewClick(false);
40954 doRelay : function(foo, bar, hname){
40955 if(hname == 'down' || this.scope.isExpanded()){
40956 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40964 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40968 initNumberEvent : function(e)
40970 this.inputEl().on("keydown" , this.fireKey, this);
40971 this.inputEl().on("focus", this.onFocus, this);
40972 this.inputEl().on("blur", this.onBlur, this);
40974 this.inputEl().relayEvent('keyup', this);
40976 if(this.indicator){
40977 this.indicator.addClass('invisible');
40980 this.originalValue = this.getValue();
40982 if(this.validationEvent == 'keyup'){
40983 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40984 this.inputEl().on('keyup', this.filterValidation, this);
40986 else if(this.validationEvent !== false){
40987 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40990 if(this.selectOnFocus){
40991 this.on("focus", this.preFocus, this);
40994 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40995 this.inputEl().on("keypress", this.filterKeys, this);
40997 this.inputEl().relayEvent('keypress', this);
41000 var allowed = "0123456789";
41002 if(this.allowDecimals){
41003 allowed += this.decimalSeparator;
41006 if(this.allowNegative){
41010 if(this.thousandsDelimiter) {
41014 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41016 var keyPress = function(e){
41018 var k = e.getKey();
41020 var c = e.getCharCode();
41023 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41024 allowed.indexOf(String.fromCharCode(c)) === -1
41030 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41034 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41039 this.inputEl().on("keypress", keyPress, this);
41043 onTriggerClick : function(e)
41050 this.loadNext = false;
41052 if(this.isExpanded()){
41057 this.hasFocus = true;
41059 if(this.triggerAction == 'all') {
41060 this.doQuery(this.allQuery, true);
41064 this.doQuery(this.getRawValue());
41067 getCurrency : function()
41069 var v = this.currencyEl().getValue();
41074 restrictHeight : function()
41076 this.list.alignTo(this.currencyEl(), this.listAlign);
41077 this.list.alignTo(this.currencyEl(), this.listAlign);
41080 onViewClick : function(view, doFocus, el, e)
41082 var index = this.view.getSelectedIndexes()[0];
41084 var r = this.store.getAt(index);
41087 this.onSelect(r, index);
41091 onSelect : function(record, index){
41093 if(this.fireEvent('beforeselect', this, record, index) !== false){
41095 this.setFromCurrencyData(index > -1 ? record.data : false);
41099 this.fireEvent('select', this, record, index);
41103 setFromCurrencyData : function(o)
41107 this.lastCurrency = o;
41109 if (this.currencyField) {
41110 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41112 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41115 this.lastSelectionText = currency;
41117 //setting default currency
41118 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41119 this.setCurrency(this.defaultCurrency);
41123 this.setCurrency(currency);
41126 setFromData : function(o)
41130 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41132 this.setFromCurrencyData(c);
41137 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41139 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41142 this.setValue(value);
41146 setCurrency : function(v)
41148 this.currencyValue = v;
41151 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41156 setValue : function(v)
41158 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41164 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41166 this.inputEl().dom.value = (v == '') ? '' :
41167 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41169 if(!this.allowZero && v === '0') {
41170 this.hiddenEl().dom.value = '';
41171 this.inputEl().dom.value = '';
41178 getRawValue : function()
41180 var v = this.inputEl().getValue();
41185 getValue : function()
41187 return this.fixPrecision(this.parseValue(this.getRawValue()));
41190 parseValue : function(value)
41192 if(this.thousandsDelimiter) {
41194 r = new RegExp(",", "g");
41195 value = value.replace(r, "");
41198 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41199 return isNaN(value) ? '' : value;
41203 fixPrecision : function(value)
41205 if(this.thousandsDelimiter) {
41207 r = new RegExp(",", "g");
41208 value = value.replace(r, "");
41211 var nan = isNaN(value);
41213 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41214 return nan ? '' : value;
41216 return parseFloat(value).toFixed(this.decimalPrecision);
41219 decimalPrecisionFcn : function(v)
41221 return Math.floor(v);
41224 validateValue : function(value)
41226 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41230 var num = this.parseValue(value);
41233 this.markInvalid(String.format(this.nanText, value));
41237 if(num < this.minValue){
41238 this.markInvalid(String.format(this.minText, this.minValue));
41242 if(num > this.maxValue){
41243 this.markInvalid(String.format(this.maxText, this.maxValue));
41250 validate : function()
41252 if(this.disabled || this.allowBlank){
41257 var currency = this.getCurrency();
41259 if(this.validateValue(this.getRawValue()) && currency.length){
41264 this.markInvalid();
41268 getName: function()
41273 beforeBlur : function()
41279 var v = this.parseValue(this.getRawValue());
41286 onBlur : function()
41290 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41291 //this.el.removeClass(this.focusClass);
41294 this.hasFocus = false;
41296 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41300 var v = this.getValue();
41302 if(String(v) !== String(this.startValue)){
41303 this.fireEvent('change', this, v, this.startValue);
41306 this.fireEvent("blur", this);
41309 inputEl : function()
41311 return this.el.select('.roo-money-amount-input', true).first();
41314 currencyEl : function()
41316 return this.el.select('.roo-money-currency-input', true).first();
41319 hiddenEl : function()
41321 return this.el.select('input.hidden-number-input',true).first();