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){
9557 if(value.length > this.maxLength){
9561 var vt = Roo.form.VTypes;
9562 if(!vt[this.vtype](value, this)){
9566 if(typeof this.validator == "function"){
9567 var msg = this.validator(value);
9571 if (typeof(msg) == 'string') {
9572 this.invalidText = msg;
9576 if(this.regex && !this.regex.test(value)){
9584 fireKey : function(e){
9585 //Roo.log('field ' + e.getKey());
9586 if(e.isNavKeyPress()){
9587 this.fireEvent("specialkey", this, e);
9590 focus : function (selectText){
9592 this.inputEl().focus();
9593 if(selectText === true){
9594 this.inputEl().dom.select();
9600 onFocus : function(){
9601 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9602 // this.el.addClass(this.focusClass);
9605 this.hasFocus = true;
9606 this.startValue = this.getValue();
9607 this.fireEvent("focus", this);
9611 beforeBlur : Roo.emptyFn,
9615 onBlur : function(){
9617 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9618 //this.el.removeClass(this.focusClass);
9620 this.hasFocus = false;
9621 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9624 var v = this.getValue();
9625 if(String(v) !== String(this.startValue)){
9626 this.fireEvent('change', this, v, this.startValue);
9628 this.fireEvent("blur", this);
9631 onChange : function(e)
9633 var v = this.getValue();
9634 if(String(v) !== String(this.startValue)){
9635 this.fireEvent('change', this, v, this.startValue);
9641 * Resets the current field value to the originally loaded value and clears any validation messages
9644 this.setValue(this.originalValue);
9648 * Returns the name of the field
9649 * @return {Mixed} name The name field
9651 getName: function(){
9655 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9656 * @return {Mixed} value The field value
9658 getValue : function(){
9660 var v = this.inputEl().getValue();
9665 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9666 * @return {Mixed} value The field value
9668 getRawValue : function(){
9669 var v = this.inputEl().getValue();
9675 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9676 * @param {Mixed} value The value to set
9678 setRawValue : function(v){
9679 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9682 selectText : function(start, end){
9683 var v = this.getRawValue();
9685 start = start === undefined ? 0 : start;
9686 end = end === undefined ? v.length : end;
9687 var d = this.inputEl().dom;
9688 if(d.setSelectionRange){
9689 d.setSelectionRange(start, end);
9690 }else if(d.createTextRange){
9691 var range = d.createTextRange();
9692 range.moveStart("character", start);
9693 range.moveEnd("character", v.length-end);
9700 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9701 * @param {Mixed} value The value to set
9703 setValue : function(v){
9706 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9712 processValue : function(value){
9713 if(this.stripCharsRe){
9714 var newValue = value.replace(this.stripCharsRe, '');
9715 if(newValue !== value){
9716 this.setRawValue(newValue);
9723 preFocus : function(){
9725 if(this.selectOnFocus){
9726 this.inputEl().dom.select();
9729 filterKeys : function(e){
9731 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9734 var c = e.getCharCode(), cc = String.fromCharCode(c);
9735 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9738 if(!this.maskRe.test(cc)){
9743 * Clear any invalid styles/messages for this field
9745 clearInvalid : function(){
9747 if(!this.el || this.preventMark){ // not rendered
9752 this.el.removeClass(this.invalidClass);
9754 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9756 var feedback = this.el.select('.form-control-feedback', true).first();
9759 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9765 this.indicator.removeClass('visible');
9766 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9769 this.fireEvent('valid', this);
9773 * Mark this field as valid
9775 markValid : function()
9777 if(!this.el || this.preventMark){ // not rendered...
9781 this.el.removeClass([this.invalidClass, this.validClass]);
9783 var feedback = this.el.select('.form-control-feedback', true).first();
9786 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9790 this.indicator.removeClass('visible');
9791 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9798 if(this.allowBlank && !this.getRawValue().length){
9802 this.el.addClass(this.validClass);
9804 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9806 var feedback = this.el.select('.form-control-feedback', true).first();
9809 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9810 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9815 this.fireEvent('valid', this);
9819 * Mark this field as invalid
9820 * @param {String} msg The validation message
9822 markInvalid : function(msg)
9824 if(!this.el || this.preventMark){ // not rendered
9828 this.el.removeClass([this.invalidClass, this.validClass]);
9830 var feedback = this.el.select('.form-control-feedback', true).first();
9833 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9840 if(this.allowBlank && !this.getRawValue().length){
9845 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9846 this.indicator.addClass('visible');
9849 this.el.addClass(this.invalidClass);
9851 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9853 var feedback = this.el.select('.form-control-feedback', true).first();
9856 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9858 if(this.getValue().length || this.forceFeedback){
9859 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9866 this.fireEvent('invalid', this, msg);
9869 SafariOnKeyDown : function(event)
9871 // this is a workaround for a password hang bug on chrome/ webkit.
9872 if (this.inputEl().dom.type != 'password') {
9876 var isSelectAll = false;
9878 if(this.inputEl().dom.selectionEnd > 0){
9879 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9881 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9882 event.preventDefault();
9887 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9889 event.preventDefault();
9890 // this is very hacky as keydown always get's upper case.
9892 var cc = String.fromCharCode(event.getCharCode());
9893 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9897 adjustWidth : function(tag, w){
9898 tag = tag.toLowerCase();
9899 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9900 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9904 if(tag == 'textarea'){
9907 }else if(Roo.isOpera){
9911 if(tag == 'textarea'){
9919 setFieldLabel : function(v)
9925 if(this.indicatorEl()){
9926 var ar = this.el.select('label > span',true);
9928 if (ar.elements.length) {
9929 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9930 this.fieldLabel = v;
9934 var br = this.el.select('label',true);
9936 if(br.elements.length) {
9937 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9938 this.fieldLabel = v;
9942 Roo.log('Cannot Found any of label > span || label in input');
9946 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9947 this.fieldLabel = v;
9962 * @class Roo.bootstrap.TextArea
9963 * @extends Roo.bootstrap.Input
9964 * Bootstrap TextArea class
9965 * @cfg {Number} cols Specifies the visible width of a text area
9966 * @cfg {Number} rows Specifies the visible number of lines in a text area
9967 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9968 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9969 * @cfg {string} html text
9972 * Create a new TextArea
9973 * @param {Object} config The config object
9976 Roo.bootstrap.TextArea = function(config){
9977 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9981 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
9991 getAutoCreate : function(){
9993 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9999 if(this.inputType != 'hidden'){
10000 cfg.cls = 'form-group' //input-group
10008 value : this.value || '',
10009 html: this.html || '',
10010 cls : 'form-control',
10011 placeholder : this.placeholder || ''
10015 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10016 input.maxLength = this.maxLength;
10020 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10024 input.cols = this.cols;
10027 if (this.readOnly) {
10028 input.readonly = true;
10032 input.name = this.name;
10036 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10040 ['xs','sm','md','lg'].map(function(size){
10041 if (settings[size]) {
10042 cfg.cls += ' col-' + size + '-' + settings[size];
10046 var inputblock = input;
10048 if(this.hasFeedback && !this.allowBlank){
10052 cls: 'glyphicon form-control-feedback'
10056 cls : 'has-feedback',
10065 if (this.before || this.after) {
10068 cls : 'input-group',
10072 inputblock.cn.push({
10074 cls : 'input-group-addon',
10079 inputblock.cn.push(input);
10081 if(this.hasFeedback && !this.allowBlank){
10082 inputblock.cls += ' has-feedback';
10083 inputblock.cn.push(feedback);
10087 inputblock.cn.push({
10089 cls : 'input-group-addon',
10096 if (align ==='left' && this.fieldLabel.length) {
10101 cls : 'control-label',
10102 html : this.fieldLabel
10113 if(this.labelWidth > 12){
10114 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10117 if(this.labelWidth < 13 && this.labelmd == 0){
10118 this.labelmd = this.labelWidth;
10121 if(this.labellg > 0){
10122 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10123 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10126 if(this.labelmd > 0){
10127 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10128 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10131 if(this.labelsm > 0){
10132 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10133 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10136 if(this.labelxs > 0){
10137 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10138 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10141 } else if ( this.fieldLabel.length) {
10146 //cls : 'input-group-addon',
10147 html : this.fieldLabel
10165 if (this.disabled) {
10166 input.disabled=true;
10173 * return the real textarea element.
10175 inputEl: function ()
10177 return this.el.select('textarea.form-control',true).first();
10181 * Clear any invalid styles/messages for this field
10183 clearInvalid : function()
10186 if(!this.el || this.preventMark){ // not rendered
10190 var label = this.el.select('label', true).first();
10191 var icon = this.el.select('i.fa-star', true).first();
10197 this.el.removeClass(this.invalidClass);
10199 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10201 var feedback = this.el.select('.form-control-feedback', true).first();
10204 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10209 this.fireEvent('valid', this);
10213 * Mark this field as valid
10215 markValid : function()
10217 if(!this.el || this.preventMark){ // not rendered
10221 this.el.removeClass([this.invalidClass, this.validClass]);
10223 var feedback = this.el.select('.form-control-feedback', true).first();
10226 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10229 if(this.disabled || this.allowBlank){
10233 var label = this.el.select('label', true).first();
10234 var icon = this.el.select('i.fa-star', true).first();
10240 this.el.addClass(this.validClass);
10242 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10244 var feedback = this.el.select('.form-control-feedback', true).first();
10247 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10248 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10253 this.fireEvent('valid', this);
10257 * Mark this field as invalid
10258 * @param {String} msg The validation message
10260 markInvalid : function(msg)
10262 if(!this.el || this.preventMark){ // not rendered
10266 this.el.removeClass([this.invalidClass, this.validClass]);
10268 var feedback = this.el.select('.form-control-feedback', true).first();
10271 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10274 if(this.disabled || this.allowBlank){
10278 var label = this.el.select('label', true).first();
10279 var icon = this.el.select('i.fa-star', true).first();
10281 if(!this.getValue().length && label && !icon){
10282 this.el.createChild({
10284 cls : 'text-danger fa fa-lg fa-star',
10285 tooltip : 'This field is required',
10286 style : 'margin-right:5px;'
10290 this.el.addClass(this.invalidClass);
10292 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10294 var feedback = this.el.select('.form-control-feedback', true).first();
10297 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10299 if(this.getValue().length || this.forceFeedback){
10300 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10307 this.fireEvent('invalid', this, msg);
10315 * trigger field - base class for combo..
10320 * @class Roo.bootstrap.TriggerField
10321 * @extends Roo.bootstrap.Input
10322 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10323 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10324 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10325 * for which you can provide a custom implementation. For example:
10327 var trigger = new Roo.bootstrap.TriggerField();
10328 trigger.onTriggerClick = myTriggerFn;
10329 trigger.applyTo('my-field');
10332 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10333 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10334 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10335 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10336 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10339 * Create a new TriggerField.
10340 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10341 * to the base TextField)
10343 Roo.bootstrap.TriggerField = function(config){
10344 this.mimicing = false;
10345 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10348 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10350 * @cfg {String} triggerClass A CSS class to apply to the trigger
10353 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10358 * @cfg {Boolean} removable (true|false) special filter default false
10362 /** @cfg {Boolean} grow @hide */
10363 /** @cfg {Number} growMin @hide */
10364 /** @cfg {Number} growMax @hide */
10370 autoSize: Roo.emptyFn,
10374 deferHeight : true,
10377 actionMode : 'wrap',
10382 getAutoCreate : function(){
10384 var align = this.labelAlign || this.parentLabelAlign();
10389 cls: 'form-group' //input-group
10396 type : this.inputType,
10397 cls : 'form-control',
10398 autocomplete: 'new-password',
10399 placeholder : this.placeholder || ''
10403 input.name = this.name;
10406 input.cls += ' input-' + this.size;
10409 if (this.disabled) {
10410 input.disabled=true;
10413 var inputblock = input;
10415 if(this.hasFeedback && !this.allowBlank){
10419 cls: 'glyphicon form-control-feedback'
10422 if(this.removable && !this.editable && !this.tickable){
10424 cls : 'has-feedback',
10430 cls : 'roo-combo-removable-btn close'
10437 cls : 'has-feedback',
10446 if(this.removable && !this.editable && !this.tickable){
10448 cls : 'roo-removable',
10454 cls : 'roo-combo-removable-btn close'
10461 if (this.before || this.after) {
10464 cls : 'input-group',
10468 inputblock.cn.push({
10470 cls : 'input-group-addon input-group-prepend input-group-text',
10475 inputblock.cn.push(input);
10477 if(this.hasFeedback && !this.allowBlank){
10478 inputblock.cls += ' has-feedback';
10479 inputblock.cn.push(feedback);
10483 inputblock.cn.push({
10485 cls : 'input-group-addon input-group-append input-group-text',
10494 var ibwrap = inputblock;
10499 cls: 'roo-select2-choices',
10503 cls: 'roo-select2-search-field',
10515 cls: 'roo-select2-container input-group',
10520 cls: 'form-hidden-field'
10526 if(!this.multiple && this.showToggleBtn){
10532 if (this.caret != false) {
10535 cls: 'fa fa-' + this.caret
10542 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10547 cls: 'combobox-clear',
10561 combobox.cls += ' roo-select2-container-multi';
10565 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10566 tooltip : 'This field is required'
10568 if (Roo.bootstrap.version == 4) {
10571 style : 'display:none'
10576 if (align ==='left' && this.fieldLabel.length) {
10578 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10585 cls : 'control-label',
10586 html : this.fieldLabel
10598 var labelCfg = cfg.cn[1];
10599 var contentCfg = cfg.cn[2];
10601 if(this.indicatorpos == 'right'){
10606 cls : 'control-label',
10610 html : this.fieldLabel
10624 labelCfg = cfg.cn[0];
10625 contentCfg = cfg.cn[1];
10628 if(this.labelWidth > 12){
10629 labelCfg.style = "width: " + this.labelWidth + 'px';
10632 if(this.labelWidth < 13 && this.labelmd == 0){
10633 this.labelmd = this.labelWidth;
10636 if(this.labellg > 0){
10637 labelCfg.cls += ' col-lg-' + this.labellg;
10638 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10641 if(this.labelmd > 0){
10642 labelCfg.cls += ' col-md-' + this.labelmd;
10643 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10646 if(this.labelsm > 0){
10647 labelCfg.cls += ' col-sm-' + this.labelsm;
10648 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10651 if(this.labelxs > 0){
10652 labelCfg.cls += ' col-xs-' + this.labelxs;
10653 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10656 } else if ( this.fieldLabel.length) {
10657 // Roo.log(" label");
10662 //cls : 'input-group-addon',
10663 html : this.fieldLabel
10671 if(this.indicatorpos == 'right'){
10679 html : this.fieldLabel
10693 // Roo.log(" no label && no align");
10700 ['xs','sm','md','lg'].map(function(size){
10701 if (settings[size]) {
10702 cfg.cls += ' col-' + size + '-' + settings[size];
10713 onResize : function(w, h){
10714 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10715 // if(typeof w == 'number'){
10716 // var x = w - this.trigger.getWidth();
10717 // this.inputEl().setWidth(this.adjustWidth('input', x));
10718 // this.trigger.setStyle('left', x+'px');
10723 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10726 getResizeEl : function(){
10727 return this.inputEl();
10731 getPositionEl : function(){
10732 return this.inputEl();
10736 alignErrorIcon : function(){
10737 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10741 initEvents : function(){
10745 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10746 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10747 if(!this.multiple && this.showToggleBtn){
10748 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10749 if(this.hideTrigger){
10750 this.trigger.setDisplayed(false);
10752 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10756 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10759 if(this.removable && !this.editable && !this.tickable){
10760 var close = this.closeTriggerEl();
10763 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10764 close.on('click', this.removeBtnClick, this, close);
10768 //this.trigger.addClassOnOver('x-form-trigger-over');
10769 //this.trigger.addClassOnClick('x-form-trigger-click');
10772 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10776 closeTriggerEl : function()
10778 var close = this.el.select('.roo-combo-removable-btn', true).first();
10779 return close ? close : false;
10782 removeBtnClick : function(e, h, el)
10784 e.preventDefault();
10786 if(this.fireEvent("remove", this) !== false){
10788 this.fireEvent("afterremove", this)
10792 createList : function()
10794 this.list = Roo.get(document.body).createChild({
10795 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10796 cls: 'typeahead typeahead-long dropdown-menu',
10797 style: 'display:none'
10800 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10805 initTrigger : function(){
10810 onDestroy : function(){
10812 this.trigger.removeAllListeners();
10813 // this.trigger.remove();
10816 // this.wrap.remove();
10818 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10822 onFocus : function(){
10823 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10825 if(!this.mimicing){
10826 this.wrap.addClass('x-trigger-wrap-focus');
10827 this.mimicing = true;
10828 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10829 if(this.monitorTab){
10830 this.el.on("keydown", this.checkTab, this);
10837 checkTab : function(e){
10838 if(e.getKey() == e.TAB){
10839 this.triggerBlur();
10844 onBlur : function(){
10849 mimicBlur : function(e, t){
10851 if(!this.wrap.contains(t) && this.validateBlur()){
10852 this.triggerBlur();
10858 triggerBlur : function(){
10859 this.mimicing = false;
10860 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10861 if(this.monitorTab){
10862 this.el.un("keydown", this.checkTab, this);
10864 //this.wrap.removeClass('x-trigger-wrap-focus');
10865 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10869 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10870 validateBlur : function(e, t){
10875 onDisable : function(){
10876 this.inputEl().dom.disabled = true;
10877 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10879 // this.wrap.addClass('x-item-disabled');
10884 onEnable : function(){
10885 this.inputEl().dom.disabled = false;
10886 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10888 // this.el.removeClass('x-item-disabled');
10893 onShow : function(){
10894 var ae = this.getActionEl();
10897 ae.dom.style.display = '';
10898 ae.dom.style.visibility = 'visible';
10904 onHide : function(){
10905 var ae = this.getActionEl();
10906 ae.dom.style.display = 'none';
10910 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10911 * by an implementing function.
10913 * @param {EventObject} e
10915 onTriggerClick : Roo.emptyFn
10919 * Ext JS Library 1.1.1
10920 * Copyright(c) 2006-2007, Ext JS, LLC.
10922 * Originally Released Under LGPL - original licence link has changed is not relivant.
10925 * <script type="text/javascript">
10930 * @class Roo.data.SortTypes
10932 * Defines the default sorting (casting?) comparison functions used when sorting data.
10934 Roo.data.SortTypes = {
10936 * Default sort that does nothing
10937 * @param {Mixed} s The value being converted
10938 * @return {Mixed} The comparison value
10940 none : function(s){
10945 * The regular expression used to strip tags
10949 stripTagsRE : /<\/?[^>]+>/gi,
10952 * Strips all HTML tags to sort on text only
10953 * @param {Mixed} s The value being converted
10954 * @return {String} The comparison value
10956 asText : function(s){
10957 return String(s).replace(this.stripTagsRE, "");
10961 * Strips all HTML tags to sort on text only - Case insensitive
10962 * @param {Mixed} s The value being converted
10963 * @return {String} The comparison value
10965 asUCText : function(s){
10966 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10970 * Case insensitive string
10971 * @param {Mixed} s The value being converted
10972 * @return {String} The comparison value
10974 asUCString : function(s) {
10975 return String(s).toUpperCase();
10980 * @param {Mixed} s The value being converted
10981 * @return {Number} The comparison value
10983 asDate : function(s) {
10987 if(s instanceof Date){
10988 return s.getTime();
10990 return Date.parse(String(s));
10995 * @param {Mixed} s The value being converted
10996 * @return {Float} The comparison value
10998 asFloat : function(s) {
10999 var val = parseFloat(String(s).replace(/,/g, ""));
11008 * @param {Mixed} s The value being converted
11009 * @return {Number} The comparison value
11011 asInt : function(s) {
11012 var val = parseInt(String(s).replace(/,/g, ""));
11020 * Ext JS Library 1.1.1
11021 * Copyright(c) 2006-2007, Ext JS, LLC.
11023 * Originally Released Under LGPL - original licence link has changed is not relivant.
11026 * <script type="text/javascript">
11030 * @class Roo.data.Record
11031 * Instances of this class encapsulate both record <em>definition</em> information, and record
11032 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11033 * to access Records cached in an {@link Roo.data.Store} object.<br>
11035 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11036 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11039 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11041 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11042 * {@link #create}. The parameters are the same.
11043 * @param {Array} data An associative Array of data values keyed by the field name.
11044 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11045 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11046 * not specified an integer id is generated.
11048 Roo.data.Record = function(data, id){
11049 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11054 * Generate a constructor for a specific record layout.
11055 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11056 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11057 * Each field definition object may contain the following properties: <ul>
11058 * <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,
11059 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11060 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11061 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11062 * is being used, then this is a string containing the javascript expression to reference the data relative to
11063 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11064 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11065 * this may be omitted.</p></li>
11066 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11067 * <ul><li>auto (Default, implies no conversion)</li>
11072 * <li>date</li></ul></p></li>
11073 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11074 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11075 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11076 * by the Reader into an object that will be stored in the Record. It is passed the
11077 * following parameters:<ul>
11078 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11080 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11082 * <br>usage:<br><pre><code>
11083 var TopicRecord = Roo.data.Record.create(
11084 {name: 'title', mapping: 'topic_title'},
11085 {name: 'author', mapping: 'username'},
11086 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11087 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11088 {name: 'lastPoster', mapping: 'user2'},
11089 {name: 'excerpt', mapping: 'post_text'}
11092 var myNewRecord = new TopicRecord({
11093 title: 'Do my job please',
11096 lastPost: new Date(),
11097 lastPoster: 'Animal',
11098 excerpt: 'No way dude!'
11100 myStore.add(myNewRecord);
11105 Roo.data.Record.create = function(o){
11106 var f = function(){
11107 f.superclass.constructor.apply(this, arguments);
11109 Roo.extend(f, Roo.data.Record);
11110 var p = f.prototype;
11111 p.fields = new Roo.util.MixedCollection(false, function(field){
11114 for(var i = 0, len = o.length; i < len; i++){
11115 p.fields.add(new Roo.data.Field(o[i]));
11117 f.getField = function(name){
11118 return p.fields.get(name);
11123 Roo.data.Record.AUTO_ID = 1000;
11124 Roo.data.Record.EDIT = 'edit';
11125 Roo.data.Record.REJECT = 'reject';
11126 Roo.data.Record.COMMIT = 'commit';
11128 Roo.data.Record.prototype = {
11130 * Readonly flag - true if this record has been modified.
11139 join : function(store){
11140 this.store = store;
11144 * Set the named field to the specified value.
11145 * @param {String} name The name of the field to set.
11146 * @param {Object} value The value to set the field to.
11148 set : function(name, value){
11149 if(this.data[name] == value){
11153 if(!this.modified){
11154 this.modified = {};
11156 if(typeof this.modified[name] == 'undefined'){
11157 this.modified[name] = this.data[name];
11159 this.data[name] = value;
11160 if(!this.editing && this.store){
11161 this.store.afterEdit(this);
11166 * Get the value of the named field.
11167 * @param {String} name The name of the field to get the value of.
11168 * @return {Object} The value of the field.
11170 get : function(name){
11171 return this.data[name];
11175 beginEdit : function(){
11176 this.editing = true;
11177 this.modified = {};
11181 cancelEdit : function(){
11182 this.editing = false;
11183 delete this.modified;
11187 endEdit : function(){
11188 this.editing = false;
11189 if(this.dirty && this.store){
11190 this.store.afterEdit(this);
11195 * Usually called by the {@link Roo.data.Store} which owns the Record.
11196 * Rejects all changes made to the Record since either creation, or the last commit operation.
11197 * Modified fields are reverted to their original values.
11199 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11200 * of reject operations.
11202 reject : function(){
11203 var m = this.modified;
11205 if(typeof m[n] != "function"){
11206 this.data[n] = m[n];
11209 this.dirty = false;
11210 delete this.modified;
11211 this.editing = false;
11213 this.store.afterReject(this);
11218 * Usually called by the {@link Roo.data.Store} which owns the Record.
11219 * Commits all changes made to the Record since either creation, or the last commit operation.
11221 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11222 * of commit operations.
11224 commit : function(){
11225 this.dirty = false;
11226 delete this.modified;
11227 this.editing = false;
11229 this.store.afterCommit(this);
11234 hasError : function(){
11235 return this.error != null;
11239 clearError : function(){
11244 * Creates a copy of this record.
11245 * @param {String} id (optional) A new record id if you don't want to use this record's id
11248 copy : function(newId) {
11249 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11253 * Ext JS Library 1.1.1
11254 * Copyright(c) 2006-2007, Ext JS, LLC.
11256 * Originally Released Under LGPL - original licence link has changed is not relivant.
11259 * <script type="text/javascript">
11265 * @class Roo.data.Store
11266 * @extends Roo.util.Observable
11267 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11268 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11270 * 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
11271 * has no knowledge of the format of the data returned by the Proxy.<br>
11273 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11274 * instances from the data object. These records are cached and made available through accessor functions.
11276 * Creates a new Store.
11277 * @param {Object} config A config object containing the objects needed for the Store to access data,
11278 * and read the data into Records.
11280 Roo.data.Store = function(config){
11281 this.data = new Roo.util.MixedCollection(false);
11282 this.data.getKey = function(o){
11285 this.baseParams = {};
11287 this.paramNames = {
11292 "multisort" : "_multisort"
11295 if(config && config.data){
11296 this.inlineData = config.data;
11297 delete config.data;
11300 Roo.apply(this, config);
11302 if(this.reader){ // reader passed
11303 this.reader = Roo.factory(this.reader, Roo.data);
11304 this.reader.xmodule = this.xmodule || false;
11305 if(!this.recordType){
11306 this.recordType = this.reader.recordType;
11308 if(this.reader.onMetaChange){
11309 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11313 if(this.recordType){
11314 this.fields = this.recordType.prototype.fields;
11316 this.modified = [];
11320 * @event datachanged
11321 * Fires when the data cache has changed, and a widget which is using this Store
11322 * as a Record cache should refresh its view.
11323 * @param {Store} this
11325 datachanged : true,
11327 * @event metachange
11328 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11329 * @param {Store} this
11330 * @param {Object} meta The JSON metadata
11335 * Fires when Records have been added to the Store
11336 * @param {Store} this
11337 * @param {Roo.data.Record[]} records The array of Records added
11338 * @param {Number} index The index at which the record(s) were added
11343 * Fires when a Record has been removed from the Store
11344 * @param {Store} this
11345 * @param {Roo.data.Record} record The Record that was removed
11346 * @param {Number} index The index at which the record was removed
11351 * Fires when a Record has been updated
11352 * @param {Store} this
11353 * @param {Roo.data.Record} record The Record that was updated
11354 * @param {String} operation The update operation being performed. Value may be one of:
11356 Roo.data.Record.EDIT
11357 Roo.data.Record.REJECT
11358 Roo.data.Record.COMMIT
11364 * Fires when the data cache has been cleared.
11365 * @param {Store} this
11369 * @event beforeload
11370 * Fires before a request is made for a new data object. If the beforeload handler returns false
11371 * the load action will be canceled.
11372 * @param {Store} this
11373 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11377 * @event beforeloadadd
11378 * Fires after a new set of Records has been loaded.
11379 * @param {Store} this
11380 * @param {Roo.data.Record[]} records The Records that were loaded
11381 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11383 beforeloadadd : true,
11386 * Fires after a new set of Records has been loaded, before they are added to the store.
11387 * @param {Store} this
11388 * @param {Roo.data.Record[]} records The Records that were loaded
11389 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11390 * @params {Object} return from reader
11394 * @event loadexception
11395 * Fires if an exception occurs in the Proxy during loading.
11396 * Called with the signature of the Proxy's "loadexception" event.
11397 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11400 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11401 * @param {Object} load options
11402 * @param {Object} jsonData from your request (normally this contains the Exception)
11404 loadexception : true
11408 this.proxy = Roo.factory(this.proxy, Roo.data);
11409 this.proxy.xmodule = this.xmodule || false;
11410 this.relayEvents(this.proxy, ["loadexception"]);
11412 this.sortToggle = {};
11413 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11415 Roo.data.Store.superclass.constructor.call(this);
11417 if(this.inlineData){
11418 this.loadData(this.inlineData);
11419 delete this.inlineData;
11423 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11425 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11426 * without a remote query - used by combo/forms at present.
11430 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11433 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11436 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11437 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11440 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11441 * on any HTTP request
11444 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11447 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11451 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11452 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11454 remoteSort : false,
11457 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11458 * loaded or when a record is removed. (defaults to false).
11460 pruneModifiedRecords : false,
11463 lastOptions : null,
11466 * Add Records to the Store and fires the add event.
11467 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11469 add : function(records){
11470 records = [].concat(records);
11471 for(var i = 0, len = records.length; i < len; i++){
11472 records[i].join(this);
11474 var index = this.data.length;
11475 this.data.addAll(records);
11476 this.fireEvent("add", this, records, index);
11480 * Remove a Record from the Store and fires the remove event.
11481 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11483 remove : function(record){
11484 var index = this.data.indexOf(record);
11485 this.data.removeAt(index);
11487 if(this.pruneModifiedRecords){
11488 this.modified.remove(record);
11490 this.fireEvent("remove", this, record, index);
11494 * Remove all Records from the Store and fires the clear event.
11496 removeAll : function(){
11498 if(this.pruneModifiedRecords){
11499 this.modified = [];
11501 this.fireEvent("clear", this);
11505 * Inserts Records to the Store at the given index and fires the add event.
11506 * @param {Number} index The start index at which to insert the passed Records.
11507 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11509 insert : function(index, records){
11510 records = [].concat(records);
11511 for(var i = 0, len = records.length; i < len; i++){
11512 this.data.insert(index, records[i]);
11513 records[i].join(this);
11515 this.fireEvent("add", this, records, index);
11519 * Get the index within the cache of the passed Record.
11520 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11521 * @return {Number} The index of the passed Record. Returns -1 if not found.
11523 indexOf : function(record){
11524 return this.data.indexOf(record);
11528 * Get the index within the cache of the Record with the passed id.
11529 * @param {String} id The id of the Record to find.
11530 * @return {Number} The index of the Record. Returns -1 if not found.
11532 indexOfId : function(id){
11533 return this.data.indexOfKey(id);
11537 * Get the Record with the specified id.
11538 * @param {String} id The id of the Record to find.
11539 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11541 getById : function(id){
11542 return this.data.key(id);
11546 * Get the Record at the specified index.
11547 * @param {Number} index The index of the Record to find.
11548 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11550 getAt : function(index){
11551 return this.data.itemAt(index);
11555 * Returns a range of Records between specified indices.
11556 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11557 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11558 * @return {Roo.data.Record[]} An array of Records
11560 getRange : function(start, end){
11561 return this.data.getRange(start, end);
11565 storeOptions : function(o){
11566 o = Roo.apply({}, o);
11569 this.lastOptions = o;
11573 * Loads the Record cache from the configured Proxy using the configured Reader.
11575 * If using remote paging, then the first load call must specify the <em>start</em>
11576 * and <em>limit</em> properties in the options.params property to establish the initial
11577 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11579 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11580 * and this call will return before the new data has been loaded. Perform any post-processing
11581 * in a callback function, or in a "load" event handler.</strong>
11583 * @param {Object} options An object containing properties which control loading options:<ul>
11584 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11585 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11586 * passed the following arguments:<ul>
11587 * <li>r : Roo.data.Record[]</li>
11588 * <li>options: Options object from the load call</li>
11589 * <li>success: Boolean success indicator</li></ul></li>
11590 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11591 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11594 load : function(options){
11595 options = options || {};
11596 if(this.fireEvent("beforeload", this, options) !== false){
11597 this.storeOptions(options);
11598 var p = Roo.apply(options.params || {}, this.baseParams);
11599 // if meta was not loaded from remote source.. try requesting it.
11600 if (!this.reader.metaFromRemote) {
11601 p._requestMeta = 1;
11603 if(this.sortInfo && this.remoteSort){
11604 var pn = this.paramNames;
11605 p[pn["sort"]] = this.sortInfo.field;
11606 p[pn["dir"]] = this.sortInfo.direction;
11608 if (this.multiSort) {
11609 var pn = this.paramNames;
11610 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11613 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11618 * Reloads the Record cache from the configured Proxy using the configured Reader and
11619 * the options from the last load operation performed.
11620 * @param {Object} options (optional) An object containing properties which may override the options
11621 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11622 * the most recently used options are reused).
11624 reload : function(options){
11625 this.load(Roo.applyIf(options||{}, this.lastOptions));
11629 // Called as a callback by the Reader during a load operation.
11630 loadRecords : function(o, options, success){
11631 if(!o || success === false){
11632 if(success !== false){
11633 this.fireEvent("load", this, [], options, o);
11635 if(options.callback){
11636 options.callback.call(options.scope || this, [], options, false);
11640 // if data returned failure - throw an exception.
11641 if (o.success === false) {
11642 // show a message if no listener is registered.
11643 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11644 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11646 // loadmask wil be hooked into this..
11647 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11650 var r = o.records, t = o.totalRecords || r.length;
11652 this.fireEvent("beforeloadadd", this, r, options, o);
11654 if(!options || options.add !== true){
11655 if(this.pruneModifiedRecords){
11656 this.modified = [];
11658 for(var i = 0, len = r.length; i < len; i++){
11662 this.data = this.snapshot;
11663 delete this.snapshot;
11666 this.data.addAll(r);
11667 this.totalLength = t;
11669 this.fireEvent("datachanged", this);
11671 this.totalLength = Math.max(t, this.data.length+r.length);
11675 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11677 var e = new Roo.data.Record({});
11679 e.set(this.parent.displayField, this.parent.emptyTitle);
11680 e.set(this.parent.valueField, '');
11685 this.fireEvent("load", this, r, options, o);
11686 if(options.callback){
11687 options.callback.call(options.scope || this, r, options, true);
11693 * Loads data from a passed data block. A Reader which understands the format of the data
11694 * must have been configured in the constructor.
11695 * @param {Object} data The data block from which to read the Records. The format of the data expected
11696 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11697 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11699 loadData : function(o, append){
11700 var r = this.reader.readRecords(o);
11701 this.loadRecords(r, {add: append}, true);
11705 * Gets the number of cached records.
11707 * <em>If using paging, this may not be the total size of the dataset. If the data object
11708 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11709 * the data set size</em>
11711 getCount : function(){
11712 return this.data.length || 0;
11716 * Gets the total number of records in the dataset as returned by the server.
11718 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11719 * the dataset size</em>
11721 getTotalCount : function(){
11722 return this.totalLength || 0;
11726 * Returns the sort state of the Store as an object with two properties:
11728 field {String} The name of the field by which the Records are sorted
11729 direction {String} The sort order, "ASC" or "DESC"
11732 getSortState : function(){
11733 return this.sortInfo;
11737 applySort : function(){
11738 if(this.sortInfo && !this.remoteSort){
11739 var s = this.sortInfo, f = s.field;
11740 var st = this.fields.get(f).sortType;
11741 var fn = function(r1, r2){
11742 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11743 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11745 this.data.sort(s.direction, fn);
11746 if(this.snapshot && this.snapshot != this.data){
11747 this.snapshot.sort(s.direction, fn);
11753 * Sets the default sort column and order to be used by the next load operation.
11754 * @param {String} fieldName The name of the field to sort by.
11755 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11757 setDefaultSort : function(field, dir){
11758 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11762 * Sort the Records.
11763 * If remote sorting is used, the sort is performed on the server, and the cache is
11764 * reloaded. If local sorting is used, the cache is sorted internally.
11765 * @param {String} fieldName The name of the field to sort by.
11766 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11768 sort : function(fieldName, dir){
11769 var f = this.fields.get(fieldName);
11771 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11773 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11774 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11779 this.sortToggle[f.name] = dir;
11780 this.sortInfo = {field: f.name, direction: dir};
11781 if(!this.remoteSort){
11783 this.fireEvent("datachanged", this);
11785 this.load(this.lastOptions);
11790 * Calls the specified function for each of the Records in the cache.
11791 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11792 * Returning <em>false</em> aborts and exits the iteration.
11793 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11795 each : function(fn, scope){
11796 this.data.each(fn, scope);
11800 * Gets all records modified since the last commit. Modified records are persisted across load operations
11801 * (e.g., during paging).
11802 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11804 getModifiedRecords : function(){
11805 return this.modified;
11809 createFilterFn : function(property, value, anyMatch){
11810 if(!value.exec){ // not a regex
11811 value = String(value);
11812 if(value.length == 0){
11815 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11817 return function(r){
11818 return value.test(r.data[property]);
11823 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11824 * @param {String} property A field on your records
11825 * @param {Number} start The record index to start at (defaults to 0)
11826 * @param {Number} end The last record index to include (defaults to length - 1)
11827 * @return {Number} The sum
11829 sum : function(property, start, end){
11830 var rs = this.data.items, v = 0;
11831 start = start || 0;
11832 end = (end || end === 0) ? end : rs.length-1;
11834 for(var i = start; i <= end; i++){
11835 v += (rs[i].data[property] || 0);
11841 * Filter the records by a specified property.
11842 * @param {String} field A field on your records
11843 * @param {String/RegExp} value Either a string that the field
11844 * should start with or a RegExp to test against the field
11845 * @param {Boolean} anyMatch True to match any part not just the beginning
11847 filter : function(property, value, anyMatch){
11848 var fn = this.createFilterFn(property, value, anyMatch);
11849 return fn ? this.filterBy(fn) : this.clearFilter();
11853 * Filter by a function. The specified function will be called with each
11854 * record in this data source. If the function returns true the record is included,
11855 * otherwise it is filtered.
11856 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11857 * @param {Object} scope (optional) The scope of the function (defaults to this)
11859 filterBy : function(fn, scope){
11860 this.snapshot = this.snapshot || this.data;
11861 this.data = this.queryBy(fn, scope||this);
11862 this.fireEvent("datachanged", this);
11866 * Query the records by a specified property.
11867 * @param {String} field A field on your records
11868 * @param {String/RegExp} value Either a string that the field
11869 * should start with or a RegExp to test against the field
11870 * @param {Boolean} anyMatch True to match any part not just the beginning
11871 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11873 query : function(property, value, anyMatch){
11874 var fn = this.createFilterFn(property, value, anyMatch);
11875 return fn ? this.queryBy(fn) : this.data.clone();
11879 * Query by a function. The specified function will be called with each
11880 * record in this data source. If the function returns true the record is included
11882 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11883 * @param {Object} scope (optional) The scope of the function (defaults to this)
11884 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11886 queryBy : function(fn, scope){
11887 var data = this.snapshot || this.data;
11888 return data.filterBy(fn, scope||this);
11892 * Collects unique values for a particular dataIndex from this store.
11893 * @param {String} dataIndex The property to collect
11894 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11895 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11896 * @return {Array} An array of the unique values
11898 collect : function(dataIndex, allowNull, bypassFilter){
11899 var d = (bypassFilter === true && this.snapshot) ?
11900 this.snapshot.items : this.data.items;
11901 var v, sv, r = [], l = {};
11902 for(var i = 0, len = d.length; i < len; i++){
11903 v = d[i].data[dataIndex];
11905 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11914 * Revert to a view of the Record cache with no filtering applied.
11915 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11917 clearFilter : function(suppressEvent){
11918 if(this.snapshot && this.snapshot != this.data){
11919 this.data = this.snapshot;
11920 delete this.snapshot;
11921 if(suppressEvent !== true){
11922 this.fireEvent("datachanged", this);
11928 afterEdit : function(record){
11929 if(this.modified.indexOf(record) == -1){
11930 this.modified.push(record);
11932 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11936 afterReject : function(record){
11937 this.modified.remove(record);
11938 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11942 afterCommit : function(record){
11943 this.modified.remove(record);
11944 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11948 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11949 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11951 commitChanges : function(){
11952 var m = this.modified.slice(0);
11953 this.modified = [];
11954 for(var i = 0, len = m.length; i < len; i++){
11960 * Cancel outstanding changes on all changed records.
11962 rejectChanges : function(){
11963 var m = this.modified.slice(0);
11964 this.modified = [];
11965 for(var i = 0, len = m.length; i < len; i++){
11970 onMetaChange : function(meta, rtype, o){
11971 this.recordType = rtype;
11972 this.fields = rtype.prototype.fields;
11973 delete this.snapshot;
11974 this.sortInfo = meta.sortInfo || this.sortInfo;
11975 this.modified = [];
11976 this.fireEvent('metachange', this, this.reader.meta);
11979 moveIndex : function(data, type)
11981 var index = this.indexOf(data);
11983 var newIndex = index + type;
11987 this.insert(newIndex, data);
11992 * Ext JS Library 1.1.1
11993 * Copyright(c) 2006-2007, Ext JS, LLC.
11995 * Originally Released Under LGPL - original licence link has changed is not relivant.
11998 * <script type="text/javascript">
12002 * @class Roo.data.SimpleStore
12003 * @extends Roo.data.Store
12004 * Small helper class to make creating Stores from Array data easier.
12005 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12006 * @cfg {Array} fields An array of field definition objects, or field name strings.
12007 * @cfg {Array} data The multi-dimensional array of data
12009 * @param {Object} config
12011 Roo.data.SimpleStore = function(config){
12012 Roo.data.SimpleStore.superclass.constructor.call(this, {
12014 reader: new Roo.data.ArrayReader({
12017 Roo.data.Record.create(config.fields)
12019 proxy : new Roo.data.MemoryProxy(config.data)
12023 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12025 * Ext JS Library 1.1.1
12026 * Copyright(c) 2006-2007, Ext JS, LLC.
12028 * Originally Released Under LGPL - original licence link has changed is not relivant.
12031 * <script type="text/javascript">
12036 * @extends Roo.data.Store
12037 * @class Roo.data.JsonStore
12038 * Small helper class to make creating Stores for JSON data easier. <br/>
12040 var store = new Roo.data.JsonStore({
12041 url: 'get-images.php',
12043 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12046 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12047 * JsonReader and HttpProxy (unless inline data is provided).</b>
12048 * @cfg {Array} fields An array of field definition objects, or field name strings.
12050 * @param {Object} config
12052 Roo.data.JsonStore = function(c){
12053 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12054 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12055 reader: new Roo.data.JsonReader(c, c.fields)
12058 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12060 * Ext JS Library 1.1.1
12061 * Copyright(c) 2006-2007, Ext JS, LLC.
12063 * Originally Released Under LGPL - original licence link has changed is not relivant.
12066 * <script type="text/javascript">
12070 Roo.data.Field = function(config){
12071 if(typeof config == "string"){
12072 config = {name: config};
12074 Roo.apply(this, config);
12077 this.type = "auto";
12080 var st = Roo.data.SortTypes;
12081 // named sortTypes are supported, here we look them up
12082 if(typeof this.sortType == "string"){
12083 this.sortType = st[this.sortType];
12086 // set default sortType for strings and dates
12087 if(!this.sortType){
12090 this.sortType = st.asUCString;
12093 this.sortType = st.asDate;
12096 this.sortType = st.none;
12101 var stripRe = /[\$,%]/g;
12103 // prebuilt conversion function for this field, instead of
12104 // switching every time we're reading a value
12106 var cv, dateFormat = this.dateFormat;
12111 cv = function(v){ return v; };
12114 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12118 return v !== undefined && v !== null && v !== '' ?
12119 parseInt(String(v).replace(stripRe, ""), 10) : '';
12124 return v !== undefined && v !== null && v !== '' ?
12125 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12130 cv = function(v){ return v === true || v === "true" || v == 1; };
12137 if(v instanceof Date){
12141 if(dateFormat == "timestamp"){
12142 return new Date(v*1000);
12144 return Date.parseDate(v, dateFormat);
12146 var parsed = Date.parse(v);
12147 return parsed ? new Date(parsed) : null;
12156 Roo.data.Field.prototype = {
12164 * Ext JS Library 1.1.1
12165 * Copyright(c) 2006-2007, Ext JS, LLC.
12167 * Originally Released Under LGPL - original licence link has changed is not relivant.
12170 * <script type="text/javascript">
12173 // Base class for reading structured data from a data source. This class is intended to be
12174 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12177 * @class Roo.data.DataReader
12178 * Base class for reading structured data from a data source. This class is intended to be
12179 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12182 Roo.data.DataReader = function(meta, recordType){
12186 this.recordType = recordType instanceof Array ?
12187 Roo.data.Record.create(recordType) : recordType;
12190 Roo.data.DataReader.prototype = {
12192 * Create an empty record
12193 * @param {Object} data (optional) - overlay some values
12194 * @return {Roo.data.Record} record created.
12196 newRow : function(d) {
12198 this.recordType.prototype.fields.each(function(c) {
12200 case 'int' : da[c.name] = 0; break;
12201 case 'date' : da[c.name] = new Date(); break;
12202 case 'float' : da[c.name] = 0.0; break;
12203 case 'boolean' : da[c.name] = false; break;
12204 default : da[c.name] = ""; break;
12208 return new this.recordType(Roo.apply(da, d));
12213 * Ext JS Library 1.1.1
12214 * Copyright(c) 2006-2007, Ext JS, LLC.
12216 * Originally Released Under LGPL - original licence link has changed is not relivant.
12219 * <script type="text/javascript">
12223 * @class Roo.data.DataProxy
12224 * @extends Roo.data.Observable
12225 * This class is an abstract base class for implementations which provide retrieval of
12226 * unformatted data objects.<br>
12228 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12229 * (of the appropriate type which knows how to parse the data object) to provide a block of
12230 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12232 * Custom implementations must implement the load method as described in
12233 * {@link Roo.data.HttpProxy#load}.
12235 Roo.data.DataProxy = function(){
12238 * @event beforeload
12239 * Fires before a network request is made to retrieve a data object.
12240 * @param {Object} This DataProxy object.
12241 * @param {Object} params The params parameter to the load function.
12246 * Fires before the load method's callback is called.
12247 * @param {Object} This DataProxy object.
12248 * @param {Object} o The data object.
12249 * @param {Object} arg The callback argument object passed to the load function.
12253 * @event loadexception
12254 * Fires if an Exception occurs during data retrieval.
12255 * @param {Object} This DataProxy object.
12256 * @param {Object} o The data object.
12257 * @param {Object} arg The callback argument object passed to the load function.
12258 * @param {Object} e The Exception.
12260 loadexception : true
12262 Roo.data.DataProxy.superclass.constructor.call(this);
12265 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12268 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12272 * Ext JS Library 1.1.1
12273 * Copyright(c) 2006-2007, Ext JS, LLC.
12275 * Originally Released Under LGPL - original licence link has changed is not relivant.
12278 * <script type="text/javascript">
12281 * @class Roo.data.MemoryProxy
12282 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12283 * to the Reader when its load method is called.
12285 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12287 Roo.data.MemoryProxy = function(data){
12291 Roo.data.MemoryProxy.superclass.constructor.call(this);
12295 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12298 * Load data from the requested source (in this case an in-memory
12299 * data object passed to the constructor), read the data object into
12300 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12301 * process that block using the passed callback.
12302 * @param {Object} params This parameter is not used by the MemoryProxy class.
12303 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12304 * object into a block of Roo.data.Records.
12305 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12306 * The function must be passed <ul>
12307 * <li>The Record block object</li>
12308 * <li>The "arg" argument from the load function</li>
12309 * <li>A boolean success indicator</li>
12311 * @param {Object} scope The scope in which to call the callback
12312 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12314 load : function(params, reader, callback, scope, arg){
12315 params = params || {};
12318 result = reader.readRecords(this.data);
12320 this.fireEvent("loadexception", this, arg, null, e);
12321 callback.call(scope, null, arg, false);
12324 callback.call(scope, result, arg, true);
12328 update : function(params, records){
12333 * Ext JS Library 1.1.1
12334 * Copyright(c) 2006-2007, Ext JS, LLC.
12336 * Originally Released Under LGPL - original licence link has changed is not relivant.
12339 * <script type="text/javascript">
12342 * @class Roo.data.HttpProxy
12343 * @extends Roo.data.DataProxy
12344 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12345 * configured to reference a certain URL.<br><br>
12347 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12348 * from which the running page was served.<br><br>
12350 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12352 * Be aware that to enable the browser to parse an XML document, the server must set
12353 * the Content-Type header in the HTTP response to "text/xml".
12355 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12356 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12357 * will be used to make the request.
12359 Roo.data.HttpProxy = function(conn){
12360 Roo.data.HttpProxy.superclass.constructor.call(this);
12361 // is conn a conn config or a real conn?
12363 this.useAjax = !conn || !conn.events;
12367 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12368 // thse are take from connection...
12371 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12374 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12375 * extra parameters to each request made by this object. (defaults to undefined)
12378 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12379 * to each request made by this object. (defaults to undefined)
12382 * @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)
12385 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12388 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12394 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12398 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12399 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12400 * a finer-grained basis than the DataProxy events.
12402 getConnection : function(){
12403 return this.useAjax ? Roo.Ajax : this.conn;
12407 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12408 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12409 * process that block using the passed callback.
12410 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12411 * for the request to the remote server.
12412 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12413 * object into a block of Roo.data.Records.
12414 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12415 * The function must be passed <ul>
12416 * <li>The Record block object</li>
12417 * <li>The "arg" argument from the load function</li>
12418 * <li>A boolean success indicator</li>
12420 * @param {Object} scope The scope in which to call the callback
12421 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12423 load : function(params, reader, callback, scope, arg){
12424 if(this.fireEvent("beforeload", this, params) !== false){
12426 params : params || {},
12428 callback : callback,
12433 callback : this.loadResponse,
12437 Roo.applyIf(o, this.conn);
12438 if(this.activeRequest){
12439 Roo.Ajax.abort(this.activeRequest);
12441 this.activeRequest = Roo.Ajax.request(o);
12443 this.conn.request(o);
12446 callback.call(scope||this, null, arg, false);
12451 loadResponse : function(o, success, response){
12452 delete this.activeRequest;
12454 this.fireEvent("loadexception", this, o, response);
12455 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12460 result = o.reader.read(response);
12462 this.fireEvent("loadexception", this, o, response, e);
12463 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12467 this.fireEvent("load", this, o, o.request.arg);
12468 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12472 update : function(dataSet){
12477 updateResponse : function(dataSet){
12482 * Ext JS Library 1.1.1
12483 * Copyright(c) 2006-2007, Ext JS, LLC.
12485 * Originally Released Under LGPL - original licence link has changed is not relivant.
12488 * <script type="text/javascript">
12492 * @class Roo.data.ScriptTagProxy
12493 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12494 * other than the originating domain of the running page.<br><br>
12496 * <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
12497 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12499 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12500 * source code that is used as the source inside a <script> tag.<br><br>
12502 * In order for the browser to process the returned data, the server must wrap the data object
12503 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12504 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12505 * depending on whether the callback name was passed:
12508 boolean scriptTag = false;
12509 String cb = request.getParameter("callback");
12512 response.setContentType("text/javascript");
12514 response.setContentType("application/x-json");
12516 Writer out = response.getWriter();
12518 out.write(cb + "(");
12520 out.print(dataBlock.toJsonString());
12527 * @param {Object} config A configuration object.
12529 Roo.data.ScriptTagProxy = function(config){
12530 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12531 Roo.apply(this, config);
12532 this.head = document.getElementsByTagName("head")[0];
12535 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12537 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12539 * @cfg {String} url The URL from which to request the data object.
12542 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12546 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12547 * the server the name of the callback function set up by the load call to process the returned data object.
12548 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12549 * javascript output which calls this named function passing the data object as its only parameter.
12551 callbackParam : "callback",
12553 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12554 * name to the request.
12559 * Load data from the configured URL, read the data object into
12560 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12561 * process that block using the passed callback.
12562 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12563 * for the request to the remote server.
12564 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12565 * object into a block of Roo.data.Records.
12566 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12567 * The function must be passed <ul>
12568 * <li>The Record block object</li>
12569 * <li>The "arg" argument from the load function</li>
12570 * <li>A boolean success indicator</li>
12572 * @param {Object} scope The scope in which to call the callback
12573 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12575 load : function(params, reader, callback, scope, arg){
12576 if(this.fireEvent("beforeload", this, params) !== false){
12578 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12580 var url = this.url;
12581 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12583 url += "&_dc=" + (new Date().getTime());
12585 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12588 cb : "stcCallback"+transId,
12589 scriptId : "stcScript"+transId,
12593 callback : callback,
12599 window[trans.cb] = function(o){
12600 conn.handleResponse(o, trans);
12603 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12605 if(this.autoAbort !== false){
12609 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12611 var script = document.createElement("script");
12612 script.setAttribute("src", url);
12613 script.setAttribute("type", "text/javascript");
12614 script.setAttribute("id", trans.scriptId);
12615 this.head.appendChild(script);
12617 this.trans = trans;
12619 callback.call(scope||this, null, arg, false);
12624 isLoading : function(){
12625 return this.trans ? true : false;
12629 * Abort the current server request.
12631 abort : function(){
12632 if(this.isLoading()){
12633 this.destroyTrans(this.trans);
12638 destroyTrans : function(trans, isLoaded){
12639 this.head.removeChild(document.getElementById(trans.scriptId));
12640 clearTimeout(trans.timeoutId);
12642 window[trans.cb] = undefined;
12644 delete window[trans.cb];
12647 // if hasn't been loaded, wait for load to remove it to prevent script error
12648 window[trans.cb] = function(){
12649 window[trans.cb] = undefined;
12651 delete window[trans.cb];
12658 handleResponse : function(o, trans){
12659 this.trans = false;
12660 this.destroyTrans(trans, true);
12663 result = trans.reader.readRecords(o);
12665 this.fireEvent("loadexception", this, o, trans.arg, e);
12666 trans.callback.call(trans.scope||window, null, trans.arg, false);
12669 this.fireEvent("load", this, o, trans.arg);
12670 trans.callback.call(trans.scope||window, result, trans.arg, true);
12674 handleFailure : function(trans){
12675 this.trans = false;
12676 this.destroyTrans(trans, false);
12677 this.fireEvent("loadexception", this, null, trans.arg);
12678 trans.callback.call(trans.scope||window, null, trans.arg, false);
12682 * Ext JS Library 1.1.1
12683 * Copyright(c) 2006-2007, Ext JS, LLC.
12685 * Originally Released Under LGPL - original licence link has changed is not relivant.
12688 * <script type="text/javascript">
12692 * @class Roo.data.JsonReader
12693 * @extends Roo.data.DataReader
12694 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12695 * based on mappings in a provided Roo.data.Record constructor.
12697 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12698 * in the reply previously.
12703 var RecordDef = Roo.data.Record.create([
12704 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12705 {name: 'occupation'} // This field will use "occupation" as the mapping.
12707 var myReader = new Roo.data.JsonReader({
12708 totalProperty: "results", // The property which contains the total dataset size (optional)
12709 root: "rows", // The property which contains an Array of row objects
12710 id: "id" // The property within each row object that provides an ID for the record (optional)
12714 * This would consume a JSON file like this:
12716 { 'results': 2, 'rows': [
12717 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12718 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12721 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12722 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12723 * paged from the remote server.
12724 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12725 * @cfg {String} root name of the property which contains the Array of row objects.
12726 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12727 * @cfg {Array} fields Array of field definition objects
12729 * Create a new JsonReader
12730 * @param {Object} meta Metadata configuration options
12731 * @param {Object} recordType Either an Array of field definition objects,
12732 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12734 Roo.data.JsonReader = function(meta, recordType){
12737 // set some defaults:
12738 Roo.applyIf(meta, {
12739 totalProperty: 'total',
12740 successProperty : 'success',
12745 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12747 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12750 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12751 * Used by Store query builder to append _requestMeta to params.
12754 metaFromRemote : false,
12756 * This method is only used by a DataProxy which has retrieved data from a remote server.
12757 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12758 * @return {Object} data A data block which is used by an Roo.data.Store object as
12759 * a cache of Roo.data.Records.
12761 read : function(response){
12762 var json = response.responseText;
12764 var o = /* eval:var:o */ eval("("+json+")");
12766 throw {message: "JsonReader.read: Json object not found"};
12772 this.metaFromRemote = true;
12773 this.meta = o.metaData;
12774 this.recordType = Roo.data.Record.create(o.metaData.fields);
12775 this.onMetaChange(this.meta, this.recordType, o);
12777 return this.readRecords(o);
12780 // private function a store will implement
12781 onMetaChange : function(meta, recordType, o){
12788 simpleAccess: function(obj, subsc) {
12795 getJsonAccessor: function(){
12797 return function(expr) {
12799 return(re.test(expr))
12800 ? new Function("obj", "return obj." + expr)
12805 return Roo.emptyFn;
12810 * Create a data block containing Roo.data.Records from an XML document.
12811 * @param {Object} o An object which contains an Array of row objects in the property specified
12812 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12813 * which contains the total size of the dataset.
12814 * @return {Object} data A data block which is used by an Roo.data.Store object as
12815 * a cache of Roo.data.Records.
12817 readRecords : function(o){
12819 * After any data loads, the raw JSON data is available for further custom processing.
12823 var s = this.meta, Record = this.recordType,
12824 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12826 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12828 if(s.totalProperty) {
12829 this.getTotal = this.getJsonAccessor(s.totalProperty);
12831 if(s.successProperty) {
12832 this.getSuccess = this.getJsonAccessor(s.successProperty);
12834 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12836 var g = this.getJsonAccessor(s.id);
12837 this.getId = function(rec) {
12839 return (r === undefined || r === "") ? null : r;
12842 this.getId = function(){return null;};
12845 for(var jj = 0; jj < fl; jj++){
12847 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12848 this.ef[jj] = this.getJsonAccessor(map);
12852 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12853 if(s.totalProperty){
12854 var vt = parseInt(this.getTotal(o), 10);
12859 if(s.successProperty){
12860 var vs = this.getSuccess(o);
12861 if(vs === false || vs === 'false'){
12866 for(var i = 0; i < c; i++){
12869 var id = this.getId(n);
12870 for(var j = 0; j < fl; j++){
12872 var v = this.ef[j](n);
12874 Roo.log('missing convert for ' + f.name);
12878 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12880 var record = new Record(values, id);
12882 records[i] = record;
12888 totalRecords : totalRecords
12893 * Ext JS Library 1.1.1
12894 * Copyright(c) 2006-2007, Ext JS, LLC.
12896 * Originally Released Under LGPL - original licence link has changed is not relivant.
12899 * <script type="text/javascript">
12903 * @class Roo.data.ArrayReader
12904 * @extends Roo.data.DataReader
12905 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12906 * Each element of that Array represents a row of data fields. The
12907 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12908 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12912 var RecordDef = Roo.data.Record.create([
12913 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12914 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12916 var myReader = new Roo.data.ArrayReader({
12917 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12921 * This would consume an Array like this:
12923 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12925 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12927 * Create a new JsonReader
12928 * @param {Object} meta Metadata configuration options.
12929 * @param {Object} recordType Either an Array of field definition objects
12930 * as specified to {@link Roo.data.Record#create},
12931 * or an {@link Roo.data.Record} object
12932 * created using {@link Roo.data.Record#create}.
12934 Roo.data.ArrayReader = function(meta, recordType){
12935 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12938 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12940 * Create a data block containing Roo.data.Records from an XML document.
12941 * @param {Object} o An Array of row objects which represents the dataset.
12942 * @return {Object} data A data block which is used by an Roo.data.Store object as
12943 * a cache of Roo.data.Records.
12945 readRecords : function(o){
12946 var sid = this.meta ? this.meta.id : null;
12947 var recordType = this.recordType, fields = recordType.prototype.fields;
12950 for(var i = 0; i < root.length; i++){
12953 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12954 for(var j = 0, jlen = fields.length; j < jlen; j++){
12955 var f = fields.items[j];
12956 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12957 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12959 values[f.name] = v;
12961 var record = new recordType(values, id);
12963 records[records.length] = record;
12967 totalRecords : records.length
12976 * @class Roo.bootstrap.ComboBox
12977 * @extends Roo.bootstrap.TriggerField
12978 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12979 * @cfg {Boolean} append (true|false) default false
12980 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12981 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12982 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12983 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12984 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12985 * @cfg {Boolean} animate default true
12986 * @cfg {Boolean} emptyResultText only for touch device
12987 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12988 * @cfg {String} emptyTitle default ''
12990 * Create a new ComboBox.
12991 * @param {Object} config Configuration options
12993 Roo.bootstrap.ComboBox = function(config){
12994 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
12998 * Fires when the dropdown list is expanded
12999 * @param {Roo.bootstrap.ComboBox} combo This combo box
13004 * Fires when the dropdown list is collapsed
13005 * @param {Roo.bootstrap.ComboBox} combo This combo box
13009 * @event beforeselect
13010 * Fires before a list item is selected. Return false to cancel the selection.
13011 * @param {Roo.bootstrap.ComboBox} combo This combo box
13012 * @param {Roo.data.Record} record The data record returned from the underlying store
13013 * @param {Number} index The index of the selected item in the dropdown list
13015 'beforeselect' : true,
13018 * Fires when a list item is selected
13019 * @param {Roo.bootstrap.ComboBox} combo This combo box
13020 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13021 * @param {Number} index The index of the selected item in the dropdown list
13025 * @event beforequery
13026 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13027 * The event object passed has these properties:
13028 * @param {Roo.bootstrap.ComboBox} combo This combo box
13029 * @param {String} query The query
13030 * @param {Boolean} forceAll true to force "all" query
13031 * @param {Boolean} cancel true to cancel the query
13032 * @param {Object} e The query event object
13034 'beforequery': true,
13037 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13038 * @param {Roo.bootstrap.ComboBox} combo This combo box
13043 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13044 * @param {Roo.bootstrap.ComboBox} combo This combo box
13045 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13050 * Fires when the remove value from the combobox array
13051 * @param {Roo.bootstrap.ComboBox} combo This combo box
13055 * @event afterremove
13056 * Fires when the remove value from the combobox array
13057 * @param {Roo.bootstrap.ComboBox} combo This combo box
13059 'afterremove' : true,
13061 * @event specialfilter
13062 * Fires when specialfilter
13063 * @param {Roo.bootstrap.ComboBox} combo This combo box
13065 'specialfilter' : true,
13068 * Fires when tick the element
13069 * @param {Roo.bootstrap.ComboBox} combo This combo box
13073 * @event touchviewdisplay
13074 * Fires when touch view require special display (default is using displayField)
13075 * @param {Roo.bootstrap.ComboBox} combo This combo box
13076 * @param {Object} cfg set html .
13078 'touchviewdisplay' : true
13083 this.tickItems = [];
13085 this.selectedIndex = -1;
13086 if(this.mode == 'local'){
13087 if(config.queryDelay === undefined){
13088 this.queryDelay = 10;
13090 if(config.minChars === undefined){
13096 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13099 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13100 * rendering into an Roo.Editor, defaults to false)
13103 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13104 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13107 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13110 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13111 * the dropdown list (defaults to undefined, with no header element)
13115 * @cfg {String/Roo.Template} tpl The template to use to render the output
13119 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13121 listWidth: undefined,
13123 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13124 * mode = 'remote' or 'text' if mode = 'local')
13126 displayField: undefined,
13129 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13130 * mode = 'remote' or 'value' if mode = 'local').
13131 * Note: use of a valueField requires the user make a selection
13132 * in order for a value to be mapped.
13134 valueField: undefined,
13136 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13141 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13142 * field's data value (defaults to the underlying DOM element's name)
13144 hiddenName: undefined,
13146 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13150 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13152 selectedClass: 'active',
13155 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13159 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13160 * anchor positions (defaults to 'tl-bl')
13162 listAlign: 'tl-bl?',
13164 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13168 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13169 * query specified by the allQuery config option (defaults to 'query')
13171 triggerAction: 'query',
13173 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13174 * (defaults to 4, does not apply if editable = false)
13178 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13179 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13183 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13184 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13188 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13189 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13193 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13194 * when editable = true (defaults to false)
13196 selectOnFocus:false,
13198 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13200 queryParam: 'query',
13202 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13203 * when mode = 'remote' (defaults to 'Loading...')
13205 loadingText: 'Loading...',
13207 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13211 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13215 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13216 * traditional select (defaults to true)
13220 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13224 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13228 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13229 * listWidth has a higher value)
13233 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13234 * allow the user to set arbitrary text into the field (defaults to false)
13236 forceSelection:false,
13238 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13239 * if typeAhead = true (defaults to 250)
13241 typeAheadDelay : 250,
13243 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13244 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13246 valueNotFoundText : undefined,
13248 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13250 blockFocus : false,
13253 * @cfg {Boolean} disableClear Disable showing of clear button.
13255 disableClear : false,
13257 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13259 alwaysQuery : false,
13262 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13267 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13269 invalidClass : "has-warning",
13272 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13274 validClass : "has-success",
13277 * @cfg {Boolean} specialFilter (true|false) special filter default false
13279 specialFilter : false,
13282 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13284 mobileTouchView : true,
13287 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13289 useNativeIOS : false,
13292 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13294 mobile_restrict_height : false,
13296 ios_options : false,
13308 btnPosition : 'right',
13309 triggerList : true,
13310 showToggleBtn : true,
13312 emptyResultText: 'Empty',
13313 triggerText : 'Select',
13316 // element that contains real text value.. (when hidden is used..)
13318 getAutoCreate : function()
13323 * Render classic select for iso
13326 if(Roo.isIOS && this.useNativeIOS){
13327 cfg = this.getAutoCreateNativeIOS();
13335 if(Roo.isTouch && this.mobileTouchView){
13336 cfg = this.getAutoCreateTouchView();
13343 if(!this.tickable){
13344 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13349 * ComboBox with tickable selections
13352 var align = this.labelAlign || this.parentLabelAlign();
13355 cls : 'form-group roo-combobox-tickable' //input-group
13358 var btn_text_select = '';
13359 var btn_text_done = '';
13360 var btn_text_cancel = '';
13362 if (this.btn_text_show) {
13363 btn_text_select = 'Select';
13364 btn_text_done = 'Done';
13365 btn_text_cancel = 'Cancel';
13370 cls : 'tickable-buttons',
13375 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13376 //html : this.triggerText
13377 html: btn_text_select
13383 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13385 html: btn_text_done
13391 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13393 html: btn_text_cancel
13399 buttons.cn.unshift({
13401 cls: 'roo-select2-search-field-input'
13407 Roo.each(buttons.cn, function(c){
13409 c.cls += ' btn-' + _this.size;
13412 if (_this.disabled) {
13419 style : 'display: contents',
13424 cls: 'form-hidden-field'
13428 cls: 'roo-select2-choices',
13432 cls: 'roo-select2-search-field',
13443 cls: 'roo-select2-container input-group roo-select2-container-multi',
13449 // cls: 'typeahead typeahead-long dropdown-menu',
13450 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13455 if(this.hasFeedback && !this.allowBlank){
13459 cls: 'glyphicon form-control-feedback'
13462 combobox.cn.push(feedback);
13467 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13468 tooltip : 'This field is required'
13470 if (Roo.bootstrap.version == 4) {
13473 style : 'display:none'
13476 if (align ==='left' && this.fieldLabel.length) {
13478 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13485 cls : 'control-label col-form-label',
13486 html : this.fieldLabel
13498 var labelCfg = cfg.cn[1];
13499 var contentCfg = cfg.cn[2];
13502 if(this.indicatorpos == 'right'){
13508 cls : 'control-label col-form-label',
13512 html : this.fieldLabel
13528 labelCfg = cfg.cn[0];
13529 contentCfg = cfg.cn[1];
13533 if(this.labelWidth > 12){
13534 labelCfg.style = "width: " + this.labelWidth + 'px';
13537 if(this.labelWidth < 13 && this.labelmd == 0){
13538 this.labelmd = this.labelWidth;
13541 if(this.labellg > 0){
13542 labelCfg.cls += ' col-lg-' + this.labellg;
13543 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13546 if(this.labelmd > 0){
13547 labelCfg.cls += ' col-md-' + this.labelmd;
13548 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13551 if(this.labelsm > 0){
13552 labelCfg.cls += ' col-sm-' + this.labelsm;
13553 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13556 if(this.labelxs > 0){
13557 labelCfg.cls += ' col-xs-' + this.labelxs;
13558 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13562 } else if ( this.fieldLabel.length) {
13563 // Roo.log(" label");
13568 //cls : 'input-group-addon',
13569 html : this.fieldLabel
13574 if(this.indicatorpos == 'right'){
13578 //cls : 'input-group-addon',
13579 html : this.fieldLabel
13589 // Roo.log(" no label && no align");
13596 ['xs','sm','md','lg'].map(function(size){
13597 if (settings[size]) {
13598 cfg.cls += ' col-' + size + '-' + settings[size];
13606 _initEventsCalled : false,
13609 initEvents: function()
13611 if (this._initEventsCalled) { // as we call render... prevent looping...
13614 this._initEventsCalled = true;
13617 throw "can not find store for combo";
13620 this.indicator = this.indicatorEl();
13622 this.store = Roo.factory(this.store, Roo.data);
13623 this.store.parent = this;
13625 // if we are building from html. then this element is so complex, that we can not really
13626 // use the rendered HTML.
13627 // so we have to trash and replace the previous code.
13628 if (Roo.XComponent.build_from_html) {
13629 // remove this element....
13630 var e = this.el.dom, k=0;
13631 while (e ) { e = e.previousSibling; ++k;}
13636 this.rendered = false;
13638 this.render(this.parent().getChildContainer(true), k);
13641 if(Roo.isIOS && this.useNativeIOS){
13642 this.initIOSView();
13650 if(Roo.isTouch && this.mobileTouchView){
13651 this.initTouchView();
13656 this.initTickableEvents();
13660 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13662 if(this.hiddenName){
13664 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13666 this.hiddenField.dom.value =
13667 this.hiddenValue !== undefined ? this.hiddenValue :
13668 this.value !== undefined ? this.value : '';
13670 // prevent input submission
13671 this.el.dom.removeAttribute('name');
13672 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13677 // this.el.dom.setAttribute('autocomplete', 'off');
13680 var cls = 'x-combo-list';
13682 //this.list = new Roo.Layer({
13683 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13689 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13690 _this.list.setWidth(lw);
13693 this.list.on('mouseover', this.onViewOver, this);
13694 this.list.on('mousemove', this.onViewMove, this);
13695 this.list.on('scroll', this.onViewScroll, this);
13698 this.list.swallowEvent('mousewheel');
13699 this.assetHeight = 0;
13702 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13703 this.assetHeight += this.header.getHeight();
13706 this.innerList = this.list.createChild({cls:cls+'-inner'});
13707 this.innerList.on('mouseover', this.onViewOver, this);
13708 this.innerList.on('mousemove', this.onViewMove, this);
13709 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13711 if(this.allowBlank && !this.pageSize && !this.disableClear){
13712 this.footer = this.list.createChild({cls:cls+'-ft'});
13713 this.pageTb = new Roo.Toolbar(this.footer);
13717 this.footer = this.list.createChild({cls:cls+'-ft'});
13718 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13719 {pageSize: this.pageSize});
13723 if (this.pageTb && this.allowBlank && !this.disableClear) {
13725 this.pageTb.add(new Roo.Toolbar.Fill(), {
13726 cls: 'x-btn-icon x-btn-clear',
13728 handler: function()
13731 _this.clearValue();
13732 _this.onSelect(false, -1);
13737 this.assetHeight += this.footer.getHeight();
13742 this.tpl = Roo.bootstrap.version == 4 ?
13743 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13744 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13747 this.view = new Roo.View(this.list, this.tpl, {
13748 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13750 //this.view.wrapEl.setDisplayed(false);
13751 this.view.on('click', this.onViewClick, this);
13754 this.store.on('beforeload', this.onBeforeLoad, this);
13755 this.store.on('load', this.onLoad, this);
13756 this.store.on('loadexception', this.onLoadException, this);
13758 if(this.resizable){
13759 this.resizer = new Roo.Resizable(this.list, {
13760 pinned:true, handles:'se'
13762 this.resizer.on('resize', function(r, w, h){
13763 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13764 this.listWidth = w;
13765 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13766 this.restrictHeight();
13768 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13771 if(!this.editable){
13772 this.editable = true;
13773 this.setEditable(false);
13778 if (typeof(this.events.add.listeners) != 'undefined') {
13780 this.addicon = this.wrap.createChild(
13781 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13783 this.addicon.on('click', function(e) {
13784 this.fireEvent('add', this);
13787 if (typeof(this.events.edit.listeners) != 'undefined') {
13789 this.editicon = this.wrap.createChild(
13790 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13791 if (this.addicon) {
13792 this.editicon.setStyle('margin-left', '40px');
13794 this.editicon.on('click', function(e) {
13796 // we fire even if inothing is selected..
13797 this.fireEvent('edit', this, this.lastData );
13803 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13804 "up" : function(e){
13805 this.inKeyMode = true;
13809 "down" : function(e){
13810 if(!this.isExpanded()){
13811 this.onTriggerClick();
13813 this.inKeyMode = true;
13818 "enter" : function(e){
13819 // this.onViewClick();
13823 if(this.fireEvent("specialkey", this, e)){
13824 this.onViewClick(false);
13830 "esc" : function(e){
13834 "tab" : function(e){
13837 if(this.fireEvent("specialkey", this, e)){
13838 this.onViewClick(false);
13846 doRelay : function(foo, bar, hname){
13847 if(hname == 'down' || this.scope.isExpanded()){
13848 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13857 this.queryDelay = Math.max(this.queryDelay || 10,
13858 this.mode == 'local' ? 10 : 250);
13861 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13863 if(this.typeAhead){
13864 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13866 if(this.editable !== false){
13867 this.inputEl().on("keyup", this.onKeyUp, this);
13869 if(this.forceSelection){
13870 this.inputEl().on('blur', this.doForce, this);
13874 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13875 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13879 initTickableEvents: function()
13883 if(this.hiddenName){
13885 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13887 this.hiddenField.dom.value =
13888 this.hiddenValue !== undefined ? this.hiddenValue :
13889 this.value !== undefined ? this.value : '';
13891 // prevent input submission
13892 this.el.dom.removeAttribute('name');
13893 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13898 // this.list = this.el.select('ul.dropdown-menu',true).first();
13900 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13901 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13902 if(this.triggerList){
13903 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13906 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13907 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13909 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13910 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13912 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13913 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13915 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13916 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13917 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13920 this.cancelBtn.hide();
13925 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13926 _this.list.setWidth(lw);
13929 this.list.on('mouseover', this.onViewOver, this);
13930 this.list.on('mousemove', this.onViewMove, this);
13932 this.list.on('scroll', this.onViewScroll, this);
13935 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13936 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13939 this.view = new Roo.View(this.list, this.tpl, {
13944 selectedClass: this.selectedClass
13947 //this.view.wrapEl.setDisplayed(false);
13948 this.view.on('click', this.onViewClick, this);
13952 this.store.on('beforeload', this.onBeforeLoad, this);
13953 this.store.on('load', this.onLoad, this);
13954 this.store.on('loadexception', this.onLoadException, this);
13957 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13958 "up" : function(e){
13959 this.inKeyMode = true;
13963 "down" : function(e){
13964 this.inKeyMode = true;
13968 "enter" : function(e){
13969 if(this.fireEvent("specialkey", this, e)){
13970 this.onViewClick(false);
13976 "esc" : function(e){
13977 this.onTickableFooterButtonClick(e, false, false);
13980 "tab" : function(e){
13981 this.fireEvent("specialkey", this, e);
13983 this.onTickableFooterButtonClick(e, false, false);
13990 doRelay : function(e, fn, key){
13991 if(this.scope.isExpanded()){
13992 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14001 this.queryDelay = Math.max(this.queryDelay || 10,
14002 this.mode == 'local' ? 10 : 250);
14005 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14007 if(this.typeAhead){
14008 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14011 if(this.editable !== false){
14012 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14015 this.indicator = this.indicatorEl();
14017 if(this.indicator){
14018 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14019 this.indicator.hide();
14024 onDestroy : function(){
14026 this.view.setStore(null);
14027 this.view.el.removeAllListeners();
14028 this.view.el.remove();
14029 this.view.purgeListeners();
14032 this.list.dom.innerHTML = '';
14036 this.store.un('beforeload', this.onBeforeLoad, this);
14037 this.store.un('load', this.onLoad, this);
14038 this.store.un('loadexception', this.onLoadException, this);
14040 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14044 fireKey : function(e){
14045 if(e.isNavKeyPress() && !this.list.isVisible()){
14046 this.fireEvent("specialkey", this, e);
14051 onResize: function(w, h){
14052 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14054 // if(typeof w != 'number'){
14055 // // we do not handle it!?!?
14058 // var tw = this.trigger.getWidth();
14059 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14060 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14062 // this.inputEl().setWidth( this.adjustWidth('input', x));
14064 // //this.trigger.setStyle('left', x+'px');
14066 // if(this.list && this.listWidth === undefined){
14067 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14068 // this.list.setWidth(lw);
14069 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14077 * Allow or prevent the user from directly editing the field text. If false is passed,
14078 * the user will only be able to select from the items defined in the dropdown list. This method
14079 * is the runtime equivalent of setting the 'editable' config option at config time.
14080 * @param {Boolean} value True to allow the user to directly edit the field text
14082 setEditable : function(value){
14083 if(value == this.editable){
14086 this.editable = value;
14088 this.inputEl().dom.setAttribute('readOnly', true);
14089 this.inputEl().on('mousedown', this.onTriggerClick, this);
14090 this.inputEl().addClass('x-combo-noedit');
14092 this.inputEl().dom.setAttribute('readOnly', false);
14093 this.inputEl().un('mousedown', this.onTriggerClick, this);
14094 this.inputEl().removeClass('x-combo-noedit');
14100 onBeforeLoad : function(combo,opts){
14101 if(!this.hasFocus){
14105 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14107 this.restrictHeight();
14108 this.selectedIndex = -1;
14112 onLoad : function(){
14114 this.hasQuery = false;
14116 if(!this.hasFocus){
14120 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14121 this.loading.hide();
14124 if(this.store.getCount() > 0){
14127 this.restrictHeight();
14128 if(this.lastQuery == this.allQuery){
14129 if(this.editable && !this.tickable){
14130 this.inputEl().dom.select();
14134 !this.selectByValue(this.value, true) &&
14137 !this.store.lastOptions ||
14138 typeof(this.store.lastOptions.add) == 'undefined' ||
14139 this.store.lastOptions.add != true
14142 this.select(0, true);
14145 if(this.autoFocus){
14148 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14149 this.taTask.delay(this.typeAheadDelay);
14153 this.onEmptyResults();
14159 onLoadException : function()
14161 this.hasQuery = false;
14163 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14164 this.loading.hide();
14167 if(this.tickable && this.editable){
14172 // only causes errors at present
14173 //Roo.log(this.store.reader.jsonData);
14174 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14176 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14182 onTypeAhead : function(){
14183 if(this.store.getCount() > 0){
14184 var r = this.store.getAt(0);
14185 var newValue = r.data[this.displayField];
14186 var len = newValue.length;
14187 var selStart = this.getRawValue().length;
14189 if(selStart != len){
14190 this.setRawValue(newValue);
14191 this.selectText(selStart, newValue.length);
14197 onSelect : function(record, index){
14199 if(this.fireEvent('beforeselect', this, record, index) !== false){
14201 this.setFromData(index > -1 ? record.data : false);
14204 this.fireEvent('select', this, record, index);
14209 * Returns the currently selected field value or empty string if no value is set.
14210 * @return {String} value The selected value
14212 getValue : function()
14214 if(Roo.isIOS && this.useNativeIOS){
14215 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14219 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14222 if(this.valueField){
14223 return typeof this.value != 'undefined' ? this.value : '';
14225 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14229 getRawValue : function()
14231 if(Roo.isIOS && this.useNativeIOS){
14232 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14235 var v = this.inputEl().getValue();
14241 * Clears any text/value currently set in the field
14243 clearValue : function(){
14245 if(this.hiddenField){
14246 this.hiddenField.dom.value = '';
14249 this.setRawValue('');
14250 this.lastSelectionText = '';
14251 this.lastData = false;
14253 var close = this.closeTriggerEl();
14264 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14265 * will be displayed in the field. If the value does not match the data value of an existing item,
14266 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14267 * Otherwise the field will be blank (although the value will still be set).
14268 * @param {String} value The value to match
14270 setValue : function(v)
14272 if(Roo.isIOS && this.useNativeIOS){
14273 this.setIOSValue(v);
14283 if(this.valueField){
14284 var r = this.findRecord(this.valueField, v);
14286 text = r.data[this.displayField];
14287 }else if(this.valueNotFoundText !== undefined){
14288 text = this.valueNotFoundText;
14291 this.lastSelectionText = text;
14292 if(this.hiddenField){
14293 this.hiddenField.dom.value = v;
14295 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14298 var close = this.closeTriggerEl();
14301 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14307 * @property {Object} the last set data for the element
14312 * Sets the value of the field based on a object which is related to the record format for the store.
14313 * @param {Object} value the value to set as. or false on reset?
14315 setFromData : function(o){
14322 var dv = ''; // display value
14323 var vv = ''; // value value..
14325 if (this.displayField) {
14326 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14328 // this is an error condition!!!
14329 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14332 if(this.valueField){
14333 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14336 var close = this.closeTriggerEl();
14339 if(dv.length || vv * 1 > 0){
14341 this.blockFocus=true;
14347 if(this.hiddenField){
14348 this.hiddenField.dom.value = vv;
14350 this.lastSelectionText = dv;
14351 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14355 // no hidden field.. - we store the value in 'value', but still display
14356 // display field!!!!
14357 this.lastSelectionText = dv;
14358 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14365 reset : function(){
14366 // overridden so that last data is reset..
14373 this.setValue(this.originalValue);
14374 //this.clearInvalid();
14375 this.lastData = false;
14377 this.view.clearSelections();
14383 findRecord : function(prop, value){
14385 if(this.store.getCount() > 0){
14386 this.store.each(function(r){
14387 if(r.data[prop] == value){
14397 getName: function()
14399 // returns hidden if it's set..
14400 if (!this.rendered) {return ''};
14401 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14405 onViewMove : function(e, t){
14406 this.inKeyMode = false;
14410 onViewOver : function(e, t){
14411 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14414 var item = this.view.findItemFromChild(t);
14417 var index = this.view.indexOf(item);
14418 this.select(index, false);
14423 onViewClick : function(view, doFocus, el, e)
14425 var index = this.view.getSelectedIndexes()[0];
14427 var r = this.store.getAt(index);
14431 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14438 Roo.each(this.tickItems, function(v,k){
14440 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14442 _this.tickItems.splice(k, 1);
14444 if(typeof(e) == 'undefined' && view == false){
14445 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14457 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14458 this.tickItems.push(r.data);
14461 if(typeof(e) == 'undefined' && view == false){
14462 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14469 this.onSelect(r, index);
14471 if(doFocus !== false && !this.blockFocus){
14472 this.inputEl().focus();
14477 restrictHeight : function(){
14478 //this.innerList.dom.style.height = '';
14479 //var inner = this.innerList.dom;
14480 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14481 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14482 //this.list.beginUpdate();
14483 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14484 this.list.alignTo(this.inputEl(), this.listAlign);
14485 this.list.alignTo(this.inputEl(), this.listAlign);
14486 //this.list.endUpdate();
14490 onEmptyResults : function(){
14492 if(this.tickable && this.editable){
14493 this.hasFocus = false;
14494 this.restrictHeight();
14502 * Returns true if the dropdown list is expanded, else false.
14504 isExpanded : function(){
14505 return this.list.isVisible();
14509 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14510 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14511 * @param {String} value The data value of the item to select
14512 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14513 * selected item if it is not currently in view (defaults to true)
14514 * @return {Boolean} True if the value matched an item in the list, else false
14516 selectByValue : function(v, scrollIntoView){
14517 if(v !== undefined && v !== null){
14518 var r = this.findRecord(this.valueField || this.displayField, v);
14520 this.select(this.store.indexOf(r), scrollIntoView);
14528 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14529 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14530 * @param {Number} index The zero-based index of the list item to select
14531 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14532 * selected item if it is not currently in view (defaults to true)
14534 select : function(index, scrollIntoView){
14535 this.selectedIndex = index;
14536 this.view.select(index);
14537 if(scrollIntoView !== false){
14538 var el = this.view.getNode(index);
14540 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14543 this.list.scrollChildIntoView(el, false);
14549 selectNext : function(){
14550 var ct = this.store.getCount();
14552 if(this.selectedIndex == -1){
14554 }else if(this.selectedIndex < ct-1){
14555 this.select(this.selectedIndex+1);
14561 selectPrev : function(){
14562 var ct = this.store.getCount();
14564 if(this.selectedIndex == -1){
14566 }else if(this.selectedIndex != 0){
14567 this.select(this.selectedIndex-1);
14573 onKeyUp : function(e){
14574 if(this.editable !== false && !e.isSpecialKey()){
14575 this.lastKey = e.getKey();
14576 this.dqTask.delay(this.queryDelay);
14581 validateBlur : function(){
14582 return !this.list || !this.list.isVisible();
14586 initQuery : function(){
14588 var v = this.getRawValue();
14590 if(this.tickable && this.editable){
14591 v = this.tickableInputEl().getValue();
14598 doForce : function(){
14599 if(this.inputEl().dom.value.length > 0){
14600 this.inputEl().dom.value =
14601 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14607 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14608 * query allowing the query action to be canceled if needed.
14609 * @param {String} query The SQL query to execute
14610 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14611 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14612 * saved in the current store (defaults to false)
14614 doQuery : function(q, forceAll){
14616 if(q === undefined || q === null){
14621 forceAll: forceAll,
14625 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14630 forceAll = qe.forceAll;
14631 if(forceAll === true || (q.length >= this.minChars)){
14633 this.hasQuery = true;
14635 if(this.lastQuery != q || this.alwaysQuery){
14636 this.lastQuery = q;
14637 if(this.mode == 'local'){
14638 this.selectedIndex = -1;
14640 this.store.clearFilter();
14643 if(this.specialFilter){
14644 this.fireEvent('specialfilter', this);
14649 this.store.filter(this.displayField, q);
14652 this.store.fireEvent("datachanged", this.store);
14659 this.store.baseParams[this.queryParam] = q;
14661 var options = {params : this.getParams(q)};
14664 options.add = true;
14665 options.params.start = this.page * this.pageSize;
14668 this.store.load(options);
14671 * this code will make the page width larger, at the beginning, the list not align correctly,
14672 * we should expand the list on onLoad
14673 * so command out it
14678 this.selectedIndex = -1;
14683 this.loadNext = false;
14687 getParams : function(q){
14689 //p[this.queryParam] = q;
14693 p.limit = this.pageSize;
14699 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14701 collapse : function(){
14702 if(!this.isExpanded()){
14708 this.hasFocus = false;
14712 this.cancelBtn.hide();
14713 this.trigger.show();
14716 this.tickableInputEl().dom.value = '';
14717 this.tickableInputEl().blur();
14722 Roo.get(document).un('mousedown', this.collapseIf, this);
14723 Roo.get(document).un('mousewheel', this.collapseIf, this);
14724 if (!this.editable) {
14725 Roo.get(document).un('keydown', this.listKeyPress, this);
14727 this.fireEvent('collapse', this);
14733 collapseIf : function(e){
14734 var in_combo = e.within(this.el);
14735 var in_list = e.within(this.list);
14736 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14738 if (in_combo || in_list || is_list) {
14739 //e.stopPropagation();
14744 this.onTickableFooterButtonClick(e, false, false);
14752 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14754 expand : function(){
14756 if(this.isExpanded() || !this.hasFocus){
14760 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14761 this.list.setWidth(lw);
14767 this.restrictHeight();
14771 this.tickItems = Roo.apply([], this.item);
14774 this.cancelBtn.show();
14775 this.trigger.hide();
14778 this.tickableInputEl().focus();
14783 Roo.get(document).on('mousedown', this.collapseIf, this);
14784 Roo.get(document).on('mousewheel', this.collapseIf, this);
14785 if (!this.editable) {
14786 Roo.get(document).on('keydown', this.listKeyPress, this);
14789 this.fireEvent('expand', this);
14793 // Implements the default empty TriggerField.onTriggerClick function
14794 onTriggerClick : function(e)
14796 Roo.log('trigger click');
14798 if(this.disabled || !this.triggerList){
14803 this.loadNext = false;
14805 if(this.isExpanded()){
14807 if (!this.blockFocus) {
14808 this.inputEl().focus();
14812 this.hasFocus = true;
14813 if(this.triggerAction == 'all') {
14814 this.doQuery(this.allQuery, true);
14816 this.doQuery(this.getRawValue());
14818 if (!this.blockFocus) {
14819 this.inputEl().focus();
14824 onTickableTriggerClick : function(e)
14831 this.loadNext = false;
14832 this.hasFocus = true;
14834 if(this.triggerAction == 'all') {
14835 this.doQuery(this.allQuery, true);
14837 this.doQuery(this.getRawValue());
14841 onSearchFieldClick : function(e)
14843 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14844 this.onTickableFooterButtonClick(e, false, false);
14848 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14853 this.loadNext = false;
14854 this.hasFocus = true;
14856 if(this.triggerAction == 'all') {
14857 this.doQuery(this.allQuery, true);
14859 this.doQuery(this.getRawValue());
14863 listKeyPress : function(e)
14865 //Roo.log('listkeypress');
14866 // scroll to first matching element based on key pres..
14867 if (e.isSpecialKey()) {
14870 var k = String.fromCharCode(e.getKey()).toUpperCase();
14873 var csel = this.view.getSelectedNodes();
14874 var cselitem = false;
14876 var ix = this.view.indexOf(csel[0]);
14877 cselitem = this.store.getAt(ix);
14878 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14884 this.store.each(function(v) {
14886 // start at existing selection.
14887 if (cselitem.id == v.id) {
14893 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14894 match = this.store.indexOf(v);
14900 if (match === false) {
14901 return true; // no more action?
14904 this.view.select(match);
14905 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14906 sn.scrollIntoView(sn.dom.parentNode, false);
14909 onViewScroll : function(e, t){
14911 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){
14915 this.hasQuery = true;
14917 this.loading = this.list.select('.loading', true).first();
14919 if(this.loading === null){
14920 this.list.createChild({
14922 cls: 'loading roo-select2-more-results roo-select2-active',
14923 html: 'Loading more results...'
14926 this.loading = this.list.select('.loading', true).first();
14928 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14930 this.loading.hide();
14933 this.loading.show();
14938 this.loadNext = true;
14940 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14945 addItem : function(o)
14947 var dv = ''; // display value
14949 if (this.displayField) {
14950 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14952 // this is an error condition!!!
14953 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14960 var choice = this.choices.createChild({
14962 cls: 'roo-select2-search-choice',
14971 cls: 'roo-select2-search-choice-close fa fa-times',
14976 }, this.searchField);
14978 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14980 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14988 this.inputEl().dom.value = '';
14993 onRemoveItem : function(e, _self, o)
14995 e.preventDefault();
14997 this.lastItem = Roo.apply([], this.item);
14999 var index = this.item.indexOf(o.data) * 1;
15002 Roo.log('not this item?!');
15006 this.item.splice(index, 1);
15011 this.fireEvent('remove', this, e);
15017 syncValue : function()
15019 if(!this.item.length){
15026 Roo.each(this.item, function(i){
15027 if(_this.valueField){
15028 value.push(i[_this.valueField]);
15035 this.value = value.join(',');
15037 if(this.hiddenField){
15038 this.hiddenField.dom.value = this.value;
15041 this.store.fireEvent("datachanged", this.store);
15046 clearItem : function()
15048 if(!this.multiple){
15054 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15062 if(this.tickable && !Roo.isTouch){
15063 this.view.refresh();
15067 inputEl: function ()
15069 if(Roo.isIOS && this.useNativeIOS){
15070 return this.el.select('select.roo-ios-select', true).first();
15073 if(Roo.isTouch && this.mobileTouchView){
15074 return this.el.select('input.form-control',true).first();
15078 return this.searchField;
15081 return this.el.select('input.form-control',true).first();
15084 onTickableFooterButtonClick : function(e, btn, el)
15086 e.preventDefault();
15088 this.lastItem = Roo.apply([], this.item);
15090 if(btn && btn.name == 'cancel'){
15091 this.tickItems = Roo.apply([], this.item);
15100 Roo.each(this.tickItems, function(o){
15108 validate : function()
15110 if(this.getVisibilityEl().hasClass('hidden')){
15114 var v = this.getRawValue();
15117 v = this.getValue();
15120 if(this.disabled || this.allowBlank || v.length){
15125 this.markInvalid();
15129 tickableInputEl : function()
15131 if(!this.tickable || !this.editable){
15132 return this.inputEl();
15135 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15139 getAutoCreateTouchView : function()
15144 cls: 'form-group' //input-group
15150 type : this.inputType,
15151 cls : 'form-control x-combo-noedit',
15152 autocomplete: 'new-password',
15153 placeholder : this.placeholder || '',
15158 input.name = this.name;
15162 input.cls += ' input-' + this.size;
15165 if (this.disabled) {
15166 input.disabled = true;
15177 inputblock.cls += ' input-group';
15179 inputblock.cn.unshift({
15181 cls : 'input-group-addon input-group-prepend input-group-text',
15186 if(this.removable && !this.multiple){
15187 inputblock.cls += ' roo-removable';
15189 inputblock.cn.push({
15192 cls : 'roo-combo-removable-btn close'
15196 if(this.hasFeedback && !this.allowBlank){
15198 inputblock.cls += ' has-feedback';
15200 inputblock.cn.push({
15202 cls: 'glyphicon form-control-feedback'
15209 inputblock.cls += (this.before) ? '' : ' input-group';
15211 inputblock.cn.push({
15213 cls : 'input-group-addon input-group-append input-group-text',
15219 var ibwrap = inputblock;
15224 cls: 'roo-select2-choices',
15228 cls: 'roo-select2-search-field',
15241 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15246 cls: 'form-hidden-field'
15252 if(!this.multiple && this.showToggleBtn){
15259 if (this.caret != false) {
15262 cls: 'fa fa-' + this.caret
15269 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15274 cls: 'combobox-clear',
15288 combobox.cls += ' roo-select2-container-multi';
15291 var align = this.labelAlign || this.parentLabelAlign();
15293 if (align ==='left' && this.fieldLabel.length) {
15298 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15299 tooltip : 'This field is required'
15303 cls : 'control-label col-form-label',
15304 html : this.fieldLabel
15315 var labelCfg = cfg.cn[1];
15316 var contentCfg = cfg.cn[2];
15319 if(this.indicatorpos == 'right'){
15324 cls : 'control-label col-form-label',
15328 html : this.fieldLabel
15332 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15333 tooltip : 'This field is required'
15346 labelCfg = cfg.cn[0];
15347 contentCfg = cfg.cn[1];
15352 if(this.labelWidth > 12){
15353 labelCfg.style = "width: " + this.labelWidth + 'px';
15356 if(this.labelWidth < 13 && this.labelmd == 0){
15357 this.labelmd = this.labelWidth;
15360 if(this.labellg > 0){
15361 labelCfg.cls += ' col-lg-' + this.labellg;
15362 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15365 if(this.labelmd > 0){
15366 labelCfg.cls += ' col-md-' + this.labelmd;
15367 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15370 if(this.labelsm > 0){
15371 labelCfg.cls += ' col-sm-' + this.labelsm;
15372 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15375 if(this.labelxs > 0){
15376 labelCfg.cls += ' col-xs-' + this.labelxs;
15377 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15381 } else if ( this.fieldLabel.length) {
15385 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15386 tooltip : 'This field is required'
15390 cls : 'control-label',
15391 html : this.fieldLabel
15402 if(this.indicatorpos == 'right'){
15406 cls : 'control-label',
15407 html : this.fieldLabel,
15411 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15412 tooltip : 'This field is required'
15429 var settings = this;
15431 ['xs','sm','md','lg'].map(function(size){
15432 if (settings[size]) {
15433 cfg.cls += ' col-' + size + '-' + settings[size];
15440 initTouchView : function()
15442 this.renderTouchView();
15444 this.touchViewEl.on('scroll', function(){
15445 this.el.dom.scrollTop = 0;
15448 this.originalValue = this.getValue();
15450 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15452 this.inputEl().on("click", this.showTouchView, this);
15453 if (this.triggerEl) {
15454 this.triggerEl.on("click", this.showTouchView, this);
15458 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15459 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15461 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15463 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15464 this.store.on('load', this.onTouchViewLoad, this);
15465 this.store.on('loadexception', this.onTouchViewLoadException, this);
15467 if(this.hiddenName){
15469 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15471 this.hiddenField.dom.value =
15472 this.hiddenValue !== undefined ? this.hiddenValue :
15473 this.value !== undefined ? this.value : '';
15475 this.el.dom.removeAttribute('name');
15476 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15480 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15481 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15484 if(this.removable && !this.multiple){
15485 var close = this.closeTriggerEl();
15487 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15488 close.on('click', this.removeBtnClick, this, close);
15492 * fix the bug in Safari iOS8
15494 this.inputEl().on("focus", function(e){
15495 document.activeElement.blur();
15498 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15505 renderTouchView : function()
15507 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15508 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15510 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15511 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15513 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15514 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15515 this.touchViewBodyEl.setStyle('overflow', 'auto');
15517 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15518 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15520 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15521 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15525 showTouchView : function()
15531 this.touchViewHeaderEl.hide();
15533 if(this.modalTitle.length){
15534 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15535 this.touchViewHeaderEl.show();
15538 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15539 this.touchViewEl.show();
15541 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15543 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15544 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15546 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15548 if(this.modalTitle.length){
15549 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15552 this.touchViewBodyEl.setHeight(bodyHeight);
15556 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15558 this.touchViewEl.addClass('in');
15561 if(this._touchViewMask){
15562 Roo.get(document.body).addClass("x-body-masked");
15563 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15564 this._touchViewMask.setStyle('z-index', 10000);
15565 this._touchViewMask.addClass('show');
15568 this.doTouchViewQuery();
15572 hideTouchView : function()
15574 this.touchViewEl.removeClass('in');
15578 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15580 this.touchViewEl.setStyle('display', 'none');
15583 if(this._touchViewMask){
15584 this._touchViewMask.removeClass('show');
15585 Roo.get(document.body).removeClass("x-body-masked");
15589 setTouchViewValue : function()
15596 Roo.each(this.tickItems, function(o){
15601 this.hideTouchView();
15604 doTouchViewQuery : function()
15613 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15617 if(!this.alwaysQuery || this.mode == 'local'){
15618 this.onTouchViewLoad();
15625 onTouchViewBeforeLoad : function(combo,opts)
15631 onTouchViewLoad : function()
15633 if(this.store.getCount() < 1){
15634 this.onTouchViewEmptyResults();
15638 this.clearTouchView();
15640 var rawValue = this.getRawValue();
15642 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15644 this.tickItems = [];
15646 this.store.data.each(function(d, rowIndex){
15647 var row = this.touchViewListGroup.createChild(template);
15649 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15650 row.addClass(d.data.cls);
15653 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15656 html : d.data[this.displayField]
15659 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15660 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15663 row.removeClass('selected');
15664 if(!this.multiple && this.valueField &&
15665 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15668 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15669 row.addClass('selected');
15672 if(this.multiple && this.valueField &&
15673 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15677 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15678 this.tickItems.push(d.data);
15681 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15685 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15687 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15689 if(this.modalTitle.length){
15690 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15693 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15695 if(this.mobile_restrict_height && listHeight < bodyHeight){
15696 this.touchViewBodyEl.setHeight(listHeight);
15701 if(firstChecked && listHeight > bodyHeight){
15702 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15707 onTouchViewLoadException : function()
15709 this.hideTouchView();
15712 onTouchViewEmptyResults : function()
15714 this.clearTouchView();
15716 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15718 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15722 clearTouchView : function()
15724 this.touchViewListGroup.dom.innerHTML = '';
15727 onTouchViewClick : function(e, el, o)
15729 e.preventDefault();
15732 var rowIndex = o.rowIndex;
15734 var r = this.store.getAt(rowIndex);
15736 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15738 if(!this.multiple){
15739 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15740 c.dom.removeAttribute('checked');
15743 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15745 this.setFromData(r.data);
15747 var close = this.closeTriggerEl();
15753 this.hideTouchView();
15755 this.fireEvent('select', this, r, rowIndex);
15760 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15761 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15762 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15766 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15767 this.addItem(r.data);
15768 this.tickItems.push(r.data);
15772 getAutoCreateNativeIOS : function()
15775 cls: 'form-group' //input-group,
15780 cls : 'roo-ios-select'
15784 combobox.name = this.name;
15787 if (this.disabled) {
15788 combobox.disabled = true;
15791 var settings = this;
15793 ['xs','sm','md','lg'].map(function(size){
15794 if (settings[size]) {
15795 cfg.cls += ' col-' + size + '-' + settings[size];
15805 initIOSView : function()
15807 this.store.on('load', this.onIOSViewLoad, this);
15812 onIOSViewLoad : function()
15814 if(this.store.getCount() < 1){
15818 this.clearIOSView();
15820 if(this.allowBlank) {
15822 var default_text = '-- SELECT --';
15824 if(this.placeholder.length){
15825 default_text = this.placeholder;
15828 if(this.emptyTitle.length){
15829 default_text += ' - ' + this.emptyTitle + ' -';
15832 var opt = this.inputEl().createChild({
15835 html : default_text
15839 o[this.valueField] = 0;
15840 o[this.displayField] = default_text;
15842 this.ios_options.push({
15849 this.store.data.each(function(d, rowIndex){
15853 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15854 html = d.data[this.displayField];
15859 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15860 value = d.data[this.valueField];
15869 if(this.value == d.data[this.valueField]){
15870 option['selected'] = true;
15873 var opt = this.inputEl().createChild(option);
15875 this.ios_options.push({
15882 this.inputEl().on('change', function(){
15883 this.fireEvent('select', this);
15888 clearIOSView: function()
15890 this.inputEl().dom.innerHTML = '';
15892 this.ios_options = [];
15895 setIOSValue: function(v)
15899 if(!this.ios_options){
15903 Roo.each(this.ios_options, function(opts){
15905 opts.el.dom.removeAttribute('selected');
15907 if(opts.data[this.valueField] != v){
15911 opts.el.dom.setAttribute('selected', true);
15917 * @cfg {Boolean} grow
15921 * @cfg {Number} growMin
15925 * @cfg {Number} growMax
15934 Roo.apply(Roo.bootstrap.ComboBox, {
15938 cls: 'modal-header',
15960 cls: 'list-group-item',
15964 cls: 'roo-combobox-list-group-item-value'
15968 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15982 listItemCheckbox : {
15984 cls: 'list-group-item',
15988 cls: 'roo-combobox-list-group-item-value'
15992 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16008 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16013 cls: 'modal-footer',
16021 cls: 'col-xs-6 text-left',
16024 cls: 'btn btn-danger roo-touch-view-cancel',
16030 cls: 'col-xs-6 text-right',
16033 cls: 'btn btn-success roo-touch-view-ok',
16044 Roo.apply(Roo.bootstrap.ComboBox, {
16046 touchViewTemplate : {
16048 cls: 'modal fade roo-combobox-touch-view',
16052 cls: 'modal-dialog',
16053 style : 'position:fixed', // we have to fix position....
16057 cls: 'modal-content',
16059 Roo.bootstrap.ComboBox.header,
16060 Roo.bootstrap.ComboBox.body,
16061 Roo.bootstrap.ComboBox.footer
16070 * Ext JS Library 1.1.1
16071 * Copyright(c) 2006-2007, Ext JS, LLC.
16073 * Originally Released Under LGPL - original licence link has changed is not relivant.
16076 * <script type="text/javascript">
16081 * @extends Roo.util.Observable
16082 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16083 * This class also supports single and multi selection modes. <br>
16084 * Create a data model bound view:
16086 var store = new Roo.data.Store(...);
16088 var view = new Roo.View({
16090 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16092 singleSelect: true,
16093 selectedClass: "ydataview-selected",
16097 // listen for node click?
16098 view.on("click", function(vw, index, node, e){
16099 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16103 dataModel.load("foobar.xml");
16105 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16107 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16108 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16110 * Note: old style constructor is still suported (container, template, config)
16113 * Create a new View
16114 * @param {Object} config The config object
16117 Roo.View = function(config, depreciated_tpl, depreciated_config){
16119 this.parent = false;
16121 if (typeof(depreciated_tpl) == 'undefined') {
16122 // new way.. - universal constructor.
16123 Roo.apply(this, config);
16124 this.el = Roo.get(this.el);
16127 this.el = Roo.get(config);
16128 this.tpl = depreciated_tpl;
16129 Roo.apply(this, depreciated_config);
16131 this.wrapEl = this.el.wrap().wrap();
16132 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16135 if(typeof(this.tpl) == "string"){
16136 this.tpl = new Roo.Template(this.tpl);
16138 // support xtype ctors..
16139 this.tpl = new Roo.factory(this.tpl, Roo);
16143 this.tpl.compile();
16148 * @event beforeclick
16149 * Fires before a click is processed. Returns false to cancel the default action.
16150 * @param {Roo.View} this
16151 * @param {Number} index The index of the target node
16152 * @param {HTMLElement} node The target node
16153 * @param {Roo.EventObject} e The raw event object
16155 "beforeclick" : true,
16158 * Fires when a template node is clicked.
16159 * @param {Roo.View} this
16160 * @param {Number} index The index of the target node
16161 * @param {HTMLElement} node The target node
16162 * @param {Roo.EventObject} e The raw event object
16167 * Fires when a template node is double clicked.
16168 * @param {Roo.View} this
16169 * @param {Number} index The index of the target node
16170 * @param {HTMLElement} node The target node
16171 * @param {Roo.EventObject} e The raw event object
16175 * @event contextmenu
16176 * Fires when a template node is right clicked.
16177 * @param {Roo.View} this
16178 * @param {Number} index The index of the target node
16179 * @param {HTMLElement} node The target node
16180 * @param {Roo.EventObject} e The raw event object
16182 "contextmenu" : true,
16184 * @event selectionchange
16185 * Fires when the selected nodes change.
16186 * @param {Roo.View} this
16187 * @param {Array} selections Array of the selected nodes
16189 "selectionchange" : true,
16192 * @event beforeselect
16193 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16194 * @param {Roo.View} this
16195 * @param {HTMLElement} node The node to be selected
16196 * @param {Array} selections Array of currently selected nodes
16198 "beforeselect" : true,
16200 * @event preparedata
16201 * Fires on every row to render, to allow you to change the data.
16202 * @param {Roo.View} this
16203 * @param {Object} data to be rendered (change this)
16205 "preparedata" : true
16213 "click": this.onClick,
16214 "dblclick": this.onDblClick,
16215 "contextmenu": this.onContextMenu,
16219 this.selections = [];
16221 this.cmp = new Roo.CompositeElementLite([]);
16223 this.store = Roo.factory(this.store, Roo.data);
16224 this.setStore(this.store, true);
16227 if ( this.footer && this.footer.xtype) {
16229 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16231 this.footer.dataSource = this.store;
16232 this.footer.container = fctr;
16233 this.footer = Roo.factory(this.footer, Roo);
16234 fctr.insertFirst(this.el);
16236 // this is a bit insane - as the paging toolbar seems to detach the el..
16237 // dom.parentNode.parentNode.parentNode
16238 // they get detached?
16242 Roo.View.superclass.constructor.call(this);
16247 Roo.extend(Roo.View, Roo.util.Observable, {
16250 * @cfg {Roo.data.Store} store Data store to load data from.
16255 * @cfg {String|Roo.Element} el The container element.
16260 * @cfg {String|Roo.Template} tpl The template used by this View
16264 * @cfg {String} dataName the named area of the template to use as the data area
16265 * Works with domtemplates roo-name="name"
16269 * @cfg {String} selectedClass The css class to add to selected nodes
16271 selectedClass : "x-view-selected",
16273 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16278 * @cfg {String} text to display on mask (default Loading)
16282 * @cfg {Boolean} multiSelect Allow multiple selection
16284 multiSelect : false,
16286 * @cfg {Boolean} singleSelect Allow single selection
16288 singleSelect: false,
16291 * @cfg {Boolean} toggleSelect - selecting
16293 toggleSelect : false,
16296 * @cfg {Boolean} tickable - selecting
16301 * Returns the element this view is bound to.
16302 * @return {Roo.Element}
16304 getEl : function(){
16305 return this.wrapEl;
16311 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16313 refresh : function(){
16314 //Roo.log('refresh');
16317 // if we are using something like 'domtemplate', then
16318 // the what gets used is:
16319 // t.applySubtemplate(NAME, data, wrapping data..)
16320 // the outer template then get' applied with
16321 // the store 'extra data'
16322 // and the body get's added to the
16323 // roo-name="data" node?
16324 // <span class='roo-tpl-{name}'></span> ?????
16328 this.clearSelections();
16329 this.el.update("");
16331 var records = this.store.getRange();
16332 if(records.length < 1) {
16334 // is this valid?? = should it render a template??
16336 this.el.update(this.emptyText);
16340 if (this.dataName) {
16341 this.el.update(t.apply(this.store.meta)); //????
16342 el = this.el.child('.roo-tpl-' + this.dataName);
16345 for(var i = 0, len = records.length; i < len; i++){
16346 var data = this.prepareData(records[i].data, i, records[i]);
16347 this.fireEvent("preparedata", this, data, i, records[i]);
16349 var d = Roo.apply({}, data);
16352 Roo.apply(d, {'roo-id' : Roo.id()});
16356 Roo.each(this.parent.item, function(item){
16357 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16360 Roo.apply(d, {'roo-data-checked' : 'checked'});
16364 html[html.length] = Roo.util.Format.trim(
16366 t.applySubtemplate(this.dataName, d, this.store.meta) :
16373 el.update(html.join(""));
16374 this.nodes = el.dom.childNodes;
16375 this.updateIndexes(0);
16380 * Function to override to reformat the data that is sent to
16381 * the template for each node.
16382 * DEPRICATED - use the preparedata event handler.
16383 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16384 * a JSON object for an UpdateManager bound view).
16386 prepareData : function(data, index, record)
16388 this.fireEvent("preparedata", this, data, index, record);
16392 onUpdate : function(ds, record){
16393 // Roo.log('on update');
16394 this.clearSelections();
16395 var index = this.store.indexOf(record);
16396 var n = this.nodes[index];
16397 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16398 n.parentNode.removeChild(n);
16399 this.updateIndexes(index, index);
16405 onAdd : function(ds, records, index)
16407 //Roo.log(['on Add', ds, records, index] );
16408 this.clearSelections();
16409 if(this.nodes.length == 0){
16413 var n = this.nodes[index];
16414 for(var i = 0, len = records.length; i < len; i++){
16415 var d = this.prepareData(records[i].data, i, records[i]);
16417 this.tpl.insertBefore(n, d);
16420 this.tpl.append(this.el, d);
16423 this.updateIndexes(index);
16426 onRemove : function(ds, record, index){
16427 // Roo.log('onRemove');
16428 this.clearSelections();
16429 var el = this.dataName ?
16430 this.el.child('.roo-tpl-' + this.dataName) :
16433 el.dom.removeChild(this.nodes[index]);
16434 this.updateIndexes(index);
16438 * Refresh an individual node.
16439 * @param {Number} index
16441 refreshNode : function(index){
16442 this.onUpdate(this.store, this.store.getAt(index));
16445 updateIndexes : function(startIndex, endIndex){
16446 var ns = this.nodes;
16447 startIndex = startIndex || 0;
16448 endIndex = endIndex || ns.length - 1;
16449 for(var i = startIndex; i <= endIndex; i++){
16450 ns[i].nodeIndex = i;
16455 * Changes the data store this view uses and refresh the view.
16456 * @param {Store} store
16458 setStore : function(store, initial){
16459 if(!initial && this.store){
16460 this.store.un("datachanged", this.refresh);
16461 this.store.un("add", this.onAdd);
16462 this.store.un("remove", this.onRemove);
16463 this.store.un("update", this.onUpdate);
16464 this.store.un("clear", this.refresh);
16465 this.store.un("beforeload", this.onBeforeLoad);
16466 this.store.un("load", this.onLoad);
16467 this.store.un("loadexception", this.onLoad);
16471 store.on("datachanged", this.refresh, this);
16472 store.on("add", this.onAdd, this);
16473 store.on("remove", this.onRemove, this);
16474 store.on("update", this.onUpdate, this);
16475 store.on("clear", this.refresh, this);
16476 store.on("beforeload", this.onBeforeLoad, this);
16477 store.on("load", this.onLoad, this);
16478 store.on("loadexception", this.onLoad, this);
16486 * onbeforeLoad - masks the loading area.
16489 onBeforeLoad : function(store,opts)
16491 //Roo.log('onBeforeLoad');
16493 this.el.update("");
16495 this.el.mask(this.mask ? this.mask : "Loading" );
16497 onLoad : function ()
16504 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16505 * @param {HTMLElement} node
16506 * @return {HTMLElement} The template node
16508 findItemFromChild : function(node){
16509 var el = this.dataName ?
16510 this.el.child('.roo-tpl-' + this.dataName,true) :
16513 if(!node || node.parentNode == el){
16516 var p = node.parentNode;
16517 while(p && p != el){
16518 if(p.parentNode == el){
16527 onClick : function(e){
16528 var item = this.findItemFromChild(e.getTarget());
16530 var index = this.indexOf(item);
16531 if(this.onItemClick(item, index, e) !== false){
16532 this.fireEvent("click", this, index, item, e);
16535 this.clearSelections();
16540 onContextMenu : function(e){
16541 var item = this.findItemFromChild(e.getTarget());
16543 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16548 onDblClick : function(e){
16549 var item = this.findItemFromChild(e.getTarget());
16551 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16555 onItemClick : function(item, index, e)
16557 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16560 if (this.toggleSelect) {
16561 var m = this.isSelected(item) ? 'unselect' : 'select';
16564 _t[m](item, true, false);
16567 if(this.multiSelect || this.singleSelect){
16568 if(this.multiSelect && e.shiftKey && this.lastSelection){
16569 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16571 this.select(item, this.multiSelect && e.ctrlKey);
16572 this.lastSelection = item;
16575 if(!this.tickable){
16576 e.preventDefault();
16584 * Get the number of selected nodes.
16587 getSelectionCount : function(){
16588 return this.selections.length;
16592 * Get the currently selected nodes.
16593 * @return {Array} An array of HTMLElements
16595 getSelectedNodes : function(){
16596 return this.selections;
16600 * Get the indexes of the selected nodes.
16603 getSelectedIndexes : function(){
16604 var indexes = [], s = this.selections;
16605 for(var i = 0, len = s.length; i < len; i++){
16606 indexes.push(s[i].nodeIndex);
16612 * Clear all selections
16613 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16615 clearSelections : function(suppressEvent){
16616 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16617 this.cmp.elements = this.selections;
16618 this.cmp.removeClass(this.selectedClass);
16619 this.selections = [];
16620 if(!suppressEvent){
16621 this.fireEvent("selectionchange", this, this.selections);
16627 * Returns true if the passed node is selected
16628 * @param {HTMLElement/Number} node The node or node index
16629 * @return {Boolean}
16631 isSelected : function(node){
16632 var s = this.selections;
16636 node = this.getNode(node);
16637 return s.indexOf(node) !== -1;
16642 * @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
16643 * @param {Boolean} keepExisting (optional) true to keep existing selections
16644 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16646 select : function(nodeInfo, keepExisting, suppressEvent){
16647 if(nodeInfo instanceof Array){
16649 this.clearSelections(true);
16651 for(var i = 0, len = nodeInfo.length; i < len; i++){
16652 this.select(nodeInfo[i], true, true);
16656 var node = this.getNode(nodeInfo);
16657 if(!node || this.isSelected(node)){
16658 return; // already selected.
16661 this.clearSelections(true);
16664 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16665 Roo.fly(node).addClass(this.selectedClass);
16666 this.selections.push(node);
16667 if(!suppressEvent){
16668 this.fireEvent("selectionchange", this, this.selections);
16676 * @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
16677 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16678 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16680 unselect : function(nodeInfo, keepExisting, suppressEvent)
16682 if(nodeInfo instanceof Array){
16683 Roo.each(this.selections, function(s) {
16684 this.unselect(s, nodeInfo);
16688 var node = this.getNode(nodeInfo);
16689 if(!node || !this.isSelected(node)){
16690 //Roo.log("not selected");
16691 return; // not selected.
16695 Roo.each(this.selections, function(s) {
16697 Roo.fly(node).removeClass(this.selectedClass);
16704 this.selections= ns;
16705 this.fireEvent("selectionchange", this, this.selections);
16709 * Gets a template node.
16710 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16711 * @return {HTMLElement} The node or null if it wasn't found
16713 getNode : function(nodeInfo){
16714 if(typeof nodeInfo == "string"){
16715 return document.getElementById(nodeInfo);
16716 }else if(typeof nodeInfo == "number"){
16717 return this.nodes[nodeInfo];
16723 * Gets a range template nodes.
16724 * @param {Number} startIndex
16725 * @param {Number} endIndex
16726 * @return {Array} An array of nodes
16728 getNodes : function(start, end){
16729 var ns = this.nodes;
16730 start = start || 0;
16731 end = typeof end == "undefined" ? ns.length - 1 : end;
16734 for(var i = start; i <= end; i++){
16738 for(var i = start; i >= end; i--){
16746 * Finds the index of the passed node
16747 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16748 * @return {Number} The index of the node or -1
16750 indexOf : function(node){
16751 node = this.getNode(node);
16752 if(typeof node.nodeIndex == "number"){
16753 return node.nodeIndex;
16755 var ns = this.nodes;
16756 for(var i = 0, len = ns.length; i < len; i++){
16767 * based on jquery fullcalendar
16771 Roo.bootstrap = Roo.bootstrap || {};
16773 * @class Roo.bootstrap.Calendar
16774 * @extends Roo.bootstrap.Component
16775 * Bootstrap Calendar class
16776 * @cfg {Boolean} loadMask (true|false) default false
16777 * @cfg {Object} header generate the user specific header of the calendar, default false
16780 * Create a new Container
16781 * @param {Object} config The config object
16786 Roo.bootstrap.Calendar = function(config){
16787 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16791 * Fires when a date is selected
16792 * @param {DatePicker} this
16793 * @param {Date} date The selected date
16797 * @event monthchange
16798 * Fires when the displayed month changes
16799 * @param {DatePicker} this
16800 * @param {Date} date The selected month
16802 'monthchange': true,
16804 * @event evententer
16805 * Fires when mouse over an event
16806 * @param {Calendar} this
16807 * @param {event} Event
16809 'evententer': true,
16811 * @event eventleave
16812 * Fires when the mouse leaves an
16813 * @param {Calendar} this
16816 'eventleave': true,
16818 * @event eventclick
16819 * Fires when the mouse click an
16820 * @param {Calendar} this
16829 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16832 * @cfg {Number} startDay
16833 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16841 getAutoCreate : function(){
16844 var fc_button = function(name, corner, style, content ) {
16845 return Roo.apply({},{
16847 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16849 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16852 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16863 style : 'width:100%',
16870 cls : 'fc-header-left',
16872 fc_button('prev', 'left', 'arrow', '‹' ),
16873 fc_button('next', 'right', 'arrow', '›' ),
16874 { tag: 'span', cls: 'fc-header-space' },
16875 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16883 cls : 'fc-header-center',
16887 cls: 'fc-header-title',
16890 html : 'month / year'
16898 cls : 'fc-header-right',
16900 /* fc_button('month', 'left', '', 'month' ),
16901 fc_button('week', '', '', 'week' ),
16902 fc_button('day', 'right', '', 'day' )
16914 header = this.header;
16917 var cal_heads = function() {
16919 // fixme - handle this.
16921 for (var i =0; i < Date.dayNames.length; i++) {
16922 var d = Date.dayNames[i];
16925 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16926 html : d.substring(0,3)
16930 ret[0].cls += ' fc-first';
16931 ret[6].cls += ' fc-last';
16934 var cal_cell = function(n) {
16937 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16942 cls: 'fc-day-number',
16946 cls: 'fc-day-content',
16950 style: 'position: relative;' // height: 17px;
16962 var cal_rows = function() {
16965 for (var r = 0; r < 6; r++) {
16972 for (var i =0; i < Date.dayNames.length; i++) {
16973 var d = Date.dayNames[i];
16974 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16977 row.cn[0].cls+=' fc-first';
16978 row.cn[0].cn[0].style = 'min-height:90px';
16979 row.cn[6].cls+=' fc-last';
16983 ret[0].cls += ' fc-first';
16984 ret[4].cls += ' fc-prev-last';
16985 ret[5].cls += ' fc-last';
16992 cls: 'fc-border-separate',
16993 style : 'width:100%',
17001 cls : 'fc-first fc-last',
17019 cls : 'fc-content',
17020 style : "position: relative;",
17023 cls : 'fc-view fc-view-month fc-grid',
17024 style : 'position: relative',
17025 unselectable : 'on',
17028 cls : 'fc-event-container',
17029 style : 'position:absolute;z-index:8;top:0;left:0;'
17047 initEvents : function()
17050 throw "can not find store for calendar";
17056 style: "text-align:center",
17060 style: "background-color:white;width:50%;margin:250 auto",
17064 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17075 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17077 var size = this.el.select('.fc-content', true).first().getSize();
17078 this.maskEl.setSize(size.width, size.height);
17079 this.maskEl.enableDisplayMode("block");
17080 if(!this.loadMask){
17081 this.maskEl.hide();
17084 this.store = Roo.factory(this.store, Roo.data);
17085 this.store.on('load', this.onLoad, this);
17086 this.store.on('beforeload', this.onBeforeLoad, this);
17090 this.cells = this.el.select('.fc-day',true);
17091 //Roo.log(this.cells);
17092 this.textNodes = this.el.query('.fc-day-number');
17093 this.cells.addClassOnOver('fc-state-hover');
17095 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17096 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17097 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17098 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17100 this.on('monthchange', this.onMonthChange, this);
17102 this.update(new Date().clearTime());
17105 resize : function() {
17106 var sz = this.el.getSize();
17108 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17109 this.el.select('.fc-day-content div',true).setHeight(34);
17114 showPrevMonth : function(e){
17115 this.update(this.activeDate.add("mo", -1));
17117 showToday : function(e){
17118 this.update(new Date().clearTime());
17121 showNextMonth : function(e){
17122 this.update(this.activeDate.add("mo", 1));
17126 showPrevYear : function(){
17127 this.update(this.activeDate.add("y", -1));
17131 showNextYear : function(){
17132 this.update(this.activeDate.add("y", 1));
17137 update : function(date)
17139 var vd = this.activeDate;
17140 this.activeDate = date;
17141 // if(vd && this.el){
17142 // var t = date.getTime();
17143 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17144 // Roo.log('using add remove');
17146 // this.fireEvent('monthchange', this, date);
17148 // this.cells.removeClass("fc-state-highlight");
17149 // this.cells.each(function(c){
17150 // if(c.dateValue == t){
17151 // c.addClass("fc-state-highlight");
17152 // setTimeout(function(){
17153 // try{c.dom.firstChild.focus();}catch(e){}
17163 var days = date.getDaysInMonth();
17165 var firstOfMonth = date.getFirstDateOfMonth();
17166 var startingPos = firstOfMonth.getDay()-this.startDay;
17168 if(startingPos < this.startDay){
17172 var pm = date.add(Date.MONTH, -1);
17173 var prevStart = pm.getDaysInMonth()-startingPos;
17175 this.cells = this.el.select('.fc-day',true);
17176 this.textNodes = this.el.query('.fc-day-number');
17177 this.cells.addClassOnOver('fc-state-hover');
17179 var cells = this.cells.elements;
17180 var textEls = this.textNodes;
17182 Roo.each(cells, function(cell){
17183 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17186 days += startingPos;
17188 // convert everything to numbers so it's fast
17189 var day = 86400000;
17190 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17193 //Roo.log(prevStart);
17195 var today = new Date().clearTime().getTime();
17196 var sel = date.clearTime().getTime();
17197 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17198 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17199 var ddMatch = this.disabledDatesRE;
17200 var ddText = this.disabledDatesText;
17201 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17202 var ddaysText = this.disabledDaysText;
17203 var format = this.format;
17205 var setCellClass = function(cal, cell){
17209 //Roo.log('set Cell Class');
17211 var t = d.getTime();
17215 cell.dateValue = t;
17217 cell.className += " fc-today";
17218 cell.className += " fc-state-highlight";
17219 cell.title = cal.todayText;
17222 // disable highlight in other month..
17223 //cell.className += " fc-state-highlight";
17228 cell.className = " fc-state-disabled";
17229 cell.title = cal.minText;
17233 cell.className = " fc-state-disabled";
17234 cell.title = cal.maxText;
17238 if(ddays.indexOf(d.getDay()) != -1){
17239 cell.title = ddaysText;
17240 cell.className = " fc-state-disabled";
17243 if(ddMatch && format){
17244 var fvalue = d.dateFormat(format);
17245 if(ddMatch.test(fvalue)){
17246 cell.title = ddText.replace("%0", fvalue);
17247 cell.className = " fc-state-disabled";
17251 if (!cell.initialClassName) {
17252 cell.initialClassName = cell.dom.className;
17255 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17260 for(; i < startingPos; i++) {
17261 textEls[i].innerHTML = (++prevStart);
17262 d.setDate(d.getDate()+1);
17264 cells[i].className = "fc-past fc-other-month";
17265 setCellClass(this, cells[i]);
17270 for(; i < days; i++){
17271 intDay = i - startingPos + 1;
17272 textEls[i].innerHTML = (intDay);
17273 d.setDate(d.getDate()+1);
17275 cells[i].className = ''; // "x-date-active";
17276 setCellClass(this, cells[i]);
17280 for(; i < 42; i++) {
17281 textEls[i].innerHTML = (++extraDays);
17282 d.setDate(d.getDate()+1);
17284 cells[i].className = "fc-future fc-other-month";
17285 setCellClass(this, cells[i]);
17288 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17290 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17292 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17293 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17295 if(totalRows != 6){
17296 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17297 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17300 this.fireEvent('monthchange', this, date);
17304 if(!this.internalRender){
17305 var main = this.el.dom.firstChild;
17306 var w = main.offsetWidth;
17307 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17308 Roo.fly(main).setWidth(w);
17309 this.internalRender = true;
17310 // opera does not respect the auto grow header center column
17311 // then, after it gets a width opera refuses to recalculate
17312 // without a second pass
17313 if(Roo.isOpera && !this.secondPass){
17314 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17315 this.secondPass = true;
17316 this.update.defer(10, this, [date]);
17323 findCell : function(dt) {
17324 dt = dt.clearTime().getTime();
17326 this.cells.each(function(c){
17327 //Roo.log("check " +c.dateValue + '?=' + dt);
17328 if(c.dateValue == dt){
17338 findCells : function(ev) {
17339 var s = ev.start.clone().clearTime().getTime();
17341 var e= ev.end.clone().clearTime().getTime();
17344 this.cells.each(function(c){
17345 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17347 if(c.dateValue > e){
17350 if(c.dateValue < s){
17359 // findBestRow: function(cells)
17363 // for (var i =0 ; i < cells.length;i++) {
17364 // ret = Math.max(cells[i].rows || 0,ret);
17371 addItem : function(ev)
17373 // look for vertical location slot in
17374 var cells = this.findCells(ev);
17376 // ev.row = this.findBestRow(cells);
17378 // work out the location.
17382 for(var i =0; i < cells.length; i++) {
17384 cells[i].row = cells[0].row;
17387 cells[i].row = cells[i].row + 1;
17397 if (crow.start.getY() == cells[i].getY()) {
17399 crow.end = cells[i];
17416 cells[0].events.push(ev);
17418 this.calevents.push(ev);
17421 clearEvents: function() {
17423 if(!this.calevents){
17427 Roo.each(this.cells.elements, function(c){
17433 Roo.each(this.calevents, function(e) {
17434 Roo.each(e.els, function(el) {
17435 el.un('mouseenter' ,this.onEventEnter, this);
17436 el.un('mouseleave' ,this.onEventLeave, this);
17441 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17447 renderEvents: function()
17451 this.cells.each(function(c) {
17460 if(c.row != c.events.length){
17461 r = 4 - (4 - (c.row - c.events.length));
17464 c.events = ev.slice(0, r);
17465 c.more = ev.slice(r);
17467 if(c.more.length && c.more.length == 1){
17468 c.events.push(c.more.pop());
17471 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17475 this.cells.each(function(c) {
17477 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17480 for (var e = 0; e < c.events.length; e++){
17481 var ev = c.events[e];
17482 var rows = ev.rows;
17484 for(var i = 0; i < rows.length; i++) {
17486 // how many rows should it span..
17489 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17490 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17492 unselectable : "on",
17495 cls: 'fc-event-inner',
17499 // cls: 'fc-event-time',
17500 // html : cells.length > 1 ? '' : ev.time
17504 cls: 'fc-event-title',
17505 html : String.format('{0}', ev.title)
17512 cls: 'ui-resizable-handle ui-resizable-e',
17513 html : '  '
17520 cfg.cls += ' fc-event-start';
17522 if ((i+1) == rows.length) {
17523 cfg.cls += ' fc-event-end';
17526 var ctr = _this.el.select('.fc-event-container',true).first();
17527 var cg = ctr.createChild(cfg);
17529 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17530 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17532 var r = (c.more.length) ? 1 : 0;
17533 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17534 cg.setWidth(ebox.right - sbox.x -2);
17536 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17537 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17538 cg.on('click', _this.onEventClick, _this, ev);
17549 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17550 style : 'position: absolute',
17551 unselectable : "on",
17554 cls: 'fc-event-inner',
17558 cls: 'fc-event-title',
17566 cls: 'ui-resizable-handle ui-resizable-e',
17567 html : '  '
17573 var ctr = _this.el.select('.fc-event-container',true).first();
17574 var cg = ctr.createChild(cfg);
17576 var sbox = c.select('.fc-day-content',true).first().getBox();
17577 var ebox = c.select('.fc-day-content',true).first().getBox();
17579 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17580 cg.setWidth(ebox.right - sbox.x -2);
17582 cg.on('click', _this.onMoreEventClick, _this, c.more);
17592 onEventEnter: function (e, el,event,d) {
17593 this.fireEvent('evententer', this, el, event);
17596 onEventLeave: function (e, el,event,d) {
17597 this.fireEvent('eventleave', this, el, event);
17600 onEventClick: function (e, el,event,d) {
17601 this.fireEvent('eventclick', this, el, event);
17604 onMonthChange: function () {
17608 onMoreEventClick: function(e, el, more)
17612 this.calpopover.placement = 'right';
17613 this.calpopover.setTitle('More');
17615 this.calpopover.setContent('');
17617 var ctr = this.calpopover.el.select('.popover-content', true).first();
17619 Roo.each(more, function(m){
17621 cls : 'fc-event-hori fc-event-draggable',
17624 var cg = ctr.createChild(cfg);
17626 cg.on('click', _this.onEventClick, _this, m);
17629 this.calpopover.show(el);
17634 onLoad: function ()
17636 this.calevents = [];
17639 if(this.store.getCount() > 0){
17640 this.store.data.each(function(d){
17643 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17644 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17645 time : d.data.start_time,
17646 title : d.data.title,
17647 description : d.data.description,
17648 venue : d.data.venue
17653 this.renderEvents();
17655 if(this.calevents.length && this.loadMask){
17656 this.maskEl.hide();
17660 onBeforeLoad: function()
17662 this.clearEvents();
17664 this.maskEl.show();
17678 * @class Roo.bootstrap.Popover
17679 * @extends Roo.bootstrap.Component
17680 * Bootstrap Popover class
17681 * @cfg {String} html contents of the popover (or false to use children..)
17682 * @cfg {String} title of popover (or false to hide)
17683 * @cfg {String} placement how it is placed
17684 * @cfg {String} trigger click || hover (or false to trigger manually)
17685 * @cfg {String} over what (parent or false to trigger manually.)
17686 * @cfg {Number} delay - delay before showing
17689 * Create a new Popover
17690 * @param {Object} config The config object
17693 Roo.bootstrap.Popover = function(config){
17694 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17700 * After the popover show
17702 * @param {Roo.bootstrap.Popover} this
17707 * After the popover hide
17709 * @param {Roo.bootstrap.Popover} this
17715 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17717 title: 'Fill in a title',
17720 placement : 'right',
17721 trigger : 'hover', // hover
17727 can_build_overlaid : false,
17729 getChildContainer : function()
17731 return this.el.select('.popover-content',true).first();
17734 getAutoCreate : function(){
17737 cls : 'popover roo-dynamic',
17738 style: 'display:block',
17744 cls : 'popover-inner',
17748 cls: 'popover-title popover-header',
17752 cls : 'popover-content popover-body',
17763 setTitle: function(str)
17766 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17768 setContent: function(str)
17771 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17773 // as it get's added to the bottom of the page.
17774 onRender : function(ct, position)
17776 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17778 var cfg = Roo.apply({}, this.getAutoCreate());
17782 cfg.cls += ' ' + this.cls;
17785 cfg.style = this.style;
17787 //Roo.log("adding to ");
17788 this.el = Roo.get(document.body).createChild(cfg, position);
17789 // Roo.log(this.el);
17794 initEvents : function()
17796 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17797 this.el.enableDisplayMode('block');
17799 if (this.over === false) {
17802 if (this.triggers === false) {
17805 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17806 var triggers = this.trigger ? this.trigger.split(' ') : [];
17807 Roo.each(triggers, function(trigger) {
17809 if (trigger == 'click') {
17810 on_el.on('click', this.toggle, this);
17811 } else if (trigger != 'manual') {
17812 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17813 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17815 on_el.on(eventIn ,this.enter, this);
17816 on_el.on(eventOut, this.leave, this);
17827 toggle : function () {
17828 this.hoverState == 'in' ? this.leave() : this.enter();
17831 enter : function () {
17833 clearTimeout(this.timeout);
17835 this.hoverState = 'in';
17837 if (!this.delay || !this.delay.show) {
17842 this.timeout = setTimeout(function () {
17843 if (_t.hoverState == 'in') {
17846 }, this.delay.show)
17849 leave : function() {
17850 clearTimeout(this.timeout);
17852 this.hoverState = 'out';
17854 if (!this.delay || !this.delay.hide) {
17859 this.timeout = setTimeout(function () {
17860 if (_t.hoverState == 'out') {
17863 }, this.delay.hide)
17866 show : function (on_el)
17869 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17873 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17874 if (this.html !== false) {
17875 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17877 this.el.removeClass([
17878 'fade','top','bottom', 'left', 'right','in',
17879 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17881 if (!this.title.length) {
17882 this.el.select('.popover-title',true).hide();
17885 var placement = typeof this.placement == 'function' ?
17886 this.placement.call(this, this.el, on_el) :
17889 var autoToken = /\s?auto?\s?/i;
17890 var autoPlace = autoToken.test(placement);
17892 placement = placement.replace(autoToken, '') || 'top';
17896 //this.el.setXY([0,0]);
17898 this.el.dom.style.display='block';
17899 this.el.addClass(placement);
17901 //this.el.appendTo(on_el);
17903 var p = this.getPosition();
17904 var box = this.el.getBox();
17909 var align = Roo.bootstrap.Popover.alignment[placement];
17912 this.el.alignTo(on_el, align[0],align[1]);
17913 //var arrow = this.el.select('.arrow',true).first();
17914 //arrow.set(align[2],
17916 this.el.addClass('in');
17919 if (this.el.hasClass('fade')) {
17923 this.hoverState = 'in';
17925 this.fireEvent('show', this);
17930 this.el.setXY([0,0]);
17931 this.el.removeClass('in');
17933 this.hoverState = null;
17935 this.fireEvent('hide', this);
17940 Roo.bootstrap.Popover.alignment = {
17941 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17942 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17943 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17944 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17955 * @class Roo.bootstrap.Progress
17956 * @extends Roo.bootstrap.Component
17957 * Bootstrap Progress class
17958 * @cfg {Boolean} striped striped of the progress bar
17959 * @cfg {Boolean} active animated of the progress bar
17963 * Create a new Progress
17964 * @param {Object} config The config object
17967 Roo.bootstrap.Progress = function(config){
17968 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17971 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17976 getAutoCreate : function(){
17984 cfg.cls += ' progress-striped';
17988 cfg.cls += ' active';
18007 * @class Roo.bootstrap.ProgressBar
18008 * @extends Roo.bootstrap.Component
18009 * Bootstrap ProgressBar class
18010 * @cfg {Number} aria_valuenow aria-value now
18011 * @cfg {Number} aria_valuemin aria-value min
18012 * @cfg {Number} aria_valuemax aria-value max
18013 * @cfg {String} label label for the progress bar
18014 * @cfg {String} panel (success | info | warning | danger )
18015 * @cfg {String} role role of the progress bar
18016 * @cfg {String} sr_only text
18020 * Create a new ProgressBar
18021 * @param {Object} config The config object
18024 Roo.bootstrap.ProgressBar = function(config){
18025 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18028 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18032 aria_valuemax : 100,
18038 getAutoCreate : function()
18043 cls: 'progress-bar',
18044 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18056 cfg.role = this.role;
18059 if(this.aria_valuenow){
18060 cfg['aria-valuenow'] = this.aria_valuenow;
18063 if(this.aria_valuemin){
18064 cfg['aria-valuemin'] = this.aria_valuemin;
18067 if(this.aria_valuemax){
18068 cfg['aria-valuemax'] = this.aria_valuemax;
18071 if(this.label && !this.sr_only){
18072 cfg.html = this.label;
18076 cfg.cls += ' progress-bar-' + this.panel;
18082 update : function(aria_valuenow)
18084 this.aria_valuenow = aria_valuenow;
18086 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18101 * @class Roo.bootstrap.TabGroup
18102 * @extends Roo.bootstrap.Column
18103 * Bootstrap Column class
18104 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18105 * @cfg {Boolean} carousel true to make the group behave like a carousel
18106 * @cfg {Boolean} bullets show bullets for the panels
18107 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18108 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18109 * @cfg {Boolean} showarrow (true|false) show arrow default true
18112 * Create a new TabGroup
18113 * @param {Object} config The config object
18116 Roo.bootstrap.TabGroup = function(config){
18117 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18119 this.navId = Roo.id();
18122 Roo.bootstrap.TabGroup.register(this);
18126 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18129 transition : false,
18134 slideOnTouch : false,
18137 getAutoCreate : function()
18139 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18141 cfg.cls += ' tab-content';
18143 if (this.carousel) {
18144 cfg.cls += ' carousel slide';
18147 cls : 'carousel-inner',
18151 if(this.bullets && !Roo.isTouch){
18154 cls : 'carousel-bullets',
18158 if(this.bullets_cls){
18159 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18166 cfg.cn[0].cn.push(bullets);
18169 if(this.showarrow){
18170 cfg.cn[0].cn.push({
18172 class : 'carousel-arrow',
18176 class : 'carousel-prev',
18180 class : 'fa fa-chevron-left'
18186 class : 'carousel-next',
18190 class : 'fa fa-chevron-right'
18203 initEvents: function()
18205 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18206 // this.el.on("touchstart", this.onTouchStart, this);
18209 if(this.autoslide){
18212 this.slideFn = window.setInterval(function() {
18213 _this.showPanelNext();
18217 if(this.showarrow){
18218 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18219 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18225 // onTouchStart : function(e, el, o)
18227 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18231 // this.showPanelNext();
18235 getChildContainer : function()
18237 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18241 * register a Navigation item
18242 * @param {Roo.bootstrap.NavItem} the navitem to add
18244 register : function(item)
18246 this.tabs.push( item);
18247 item.navId = this.navId; // not really needed..
18252 getActivePanel : function()
18255 Roo.each(this.tabs, function(t) {
18265 getPanelByName : function(n)
18268 Roo.each(this.tabs, function(t) {
18269 if (t.tabId == n) {
18277 indexOfPanel : function(p)
18280 Roo.each(this.tabs, function(t,i) {
18281 if (t.tabId == p.tabId) {
18290 * show a specific panel
18291 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18292 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18294 showPanel : function (pan)
18296 if(this.transition || typeof(pan) == 'undefined'){
18297 Roo.log("waiting for the transitionend");
18301 if (typeof(pan) == 'number') {
18302 pan = this.tabs[pan];
18305 if (typeof(pan) == 'string') {
18306 pan = this.getPanelByName(pan);
18309 var cur = this.getActivePanel();
18312 Roo.log('pan or acitve pan is undefined');
18316 if (pan.tabId == this.getActivePanel().tabId) {
18320 if (false === cur.fireEvent('beforedeactivate')) {
18324 if(this.bullets > 0 && !Roo.isTouch){
18325 this.setActiveBullet(this.indexOfPanel(pan));
18328 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18330 this.transition = true;
18331 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18332 var lr = dir == 'next' ? 'left' : 'right';
18333 pan.el.addClass(dir); // or prev
18334 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18335 cur.el.addClass(lr); // or right
18336 pan.el.addClass(lr);
18339 cur.el.on('transitionend', function() {
18340 Roo.log("trans end?");
18342 pan.el.removeClass([lr,dir]);
18343 pan.setActive(true);
18345 cur.el.removeClass([lr]);
18346 cur.setActive(false);
18348 _this.transition = false;
18350 }, this, { single: true } );
18355 cur.setActive(false);
18356 pan.setActive(true);
18361 showPanelNext : function()
18363 var i = this.indexOfPanel(this.getActivePanel());
18365 if (i >= this.tabs.length - 1 && !this.autoslide) {
18369 if (i >= this.tabs.length - 1 && this.autoslide) {
18373 this.showPanel(this.tabs[i+1]);
18376 showPanelPrev : function()
18378 var i = this.indexOfPanel(this.getActivePanel());
18380 if (i < 1 && !this.autoslide) {
18384 if (i < 1 && this.autoslide) {
18385 i = this.tabs.length;
18388 this.showPanel(this.tabs[i-1]);
18392 addBullet: function()
18394 if(!this.bullets || Roo.isTouch){
18397 var ctr = this.el.select('.carousel-bullets',true).first();
18398 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18399 var bullet = ctr.createChild({
18400 cls : 'bullet bullet-' + i
18401 },ctr.dom.lastChild);
18406 bullet.on('click', (function(e, el, o, ii, t){
18408 e.preventDefault();
18410 this.showPanel(ii);
18412 if(this.autoslide && this.slideFn){
18413 clearInterval(this.slideFn);
18414 this.slideFn = window.setInterval(function() {
18415 _this.showPanelNext();
18419 }).createDelegate(this, [i, bullet], true));
18424 setActiveBullet : function(i)
18430 Roo.each(this.el.select('.bullet', true).elements, function(el){
18431 el.removeClass('selected');
18434 var bullet = this.el.select('.bullet-' + i, true).first();
18440 bullet.addClass('selected');
18451 Roo.apply(Roo.bootstrap.TabGroup, {
18455 * register a Navigation Group
18456 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18458 register : function(navgrp)
18460 this.groups[navgrp.navId] = navgrp;
18464 * fetch a Navigation Group based on the navigation ID
18465 * if one does not exist , it will get created.
18466 * @param {string} the navgroup to add
18467 * @returns {Roo.bootstrap.NavGroup} the navgroup
18469 get: function(navId) {
18470 if (typeof(this.groups[navId]) == 'undefined') {
18471 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18473 return this.groups[navId] ;
18488 * @class Roo.bootstrap.TabPanel
18489 * @extends Roo.bootstrap.Component
18490 * Bootstrap TabPanel class
18491 * @cfg {Boolean} active panel active
18492 * @cfg {String} html panel content
18493 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18494 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18495 * @cfg {String} href click to link..
18499 * Create a new TabPanel
18500 * @param {Object} config The config object
18503 Roo.bootstrap.TabPanel = function(config){
18504 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18508 * Fires when the active status changes
18509 * @param {Roo.bootstrap.TabPanel} this
18510 * @param {Boolean} state the new state
18515 * @event beforedeactivate
18516 * Fires before a tab is de-activated - can be used to do validation on a form.
18517 * @param {Roo.bootstrap.TabPanel} this
18518 * @return {Boolean} false if there is an error
18521 'beforedeactivate': true
18524 this.tabId = this.tabId || Roo.id();
18528 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18536 getAutoCreate : function(){
18539 // item is needed for carousel - not sure if it has any effect otherwise
18540 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18541 html: this.html || ''
18545 cfg.cls += ' active';
18549 cfg.tabId = this.tabId;
18556 initEvents: function()
18558 var p = this.parent();
18560 this.navId = this.navId || p.navId;
18562 if (typeof(this.navId) != 'undefined') {
18563 // not really needed.. but just in case.. parent should be a NavGroup.
18564 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18568 var i = tg.tabs.length - 1;
18570 if(this.active && tg.bullets > 0 && i < tg.bullets){
18571 tg.setActiveBullet(i);
18575 this.el.on('click', this.onClick, this);
18578 this.el.on("touchstart", this.onTouchStart, this);
18579 this.el.on("touchmove", this.onTouchMove, this);
18580 this.el.on("touchend", this.onTouchEnd, this);
18585 onRender : function(ct, position)
18587 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18590 setActive : function(state)
18592 Roo.log("panel - set active " + this.tabId + "=" + state);
18594 this.active = state;
18596 this.el.removeClass('active');
18598 } else if (!this.el.hasClass('active')) {
18599 this.el.addClass('active');
18602 this.fireEvent('changed', this, state);
18605 onClick : function(e)
18607 e.preventDefault();
18609 if(!this.href.length){
18613 window.location.href = this.href;
18622 onTouchStart : function(e)
18624 this.swiping = false;
18626 this.startX = e.browserEvent.touches[0].clientX;
18627 this.startY = e.browserEvent.touches[0].clientY;
18630 onTouchMove : function(e)
18632 this.swiping = true;
18634 this.endX = e.browserEvent.touches[0].clientX;
18635 this.endY = e.browserEvent.touches[0].clientY;
18638 onTouchEnd : function(e)
18645 var tabGroup = this.parent();
18647 if(this.endX > this.startX){ // swiping right
18648 tabGroup.showPanelPrev();
18652 if(this.startX > this.endX){ // swiping left
18653 tabGroup.showPanelNext();
18672 * @class Roo.bootstrap.DateField
18673 * @extends Roo.bootstrap.Input
18674 * Bootstrap DateField class
18675 * @cfg {Number} weekStart default 0
18676 * @cfg {String} viewMode default empty, (months|years)
18677 * @cfg {String} minViewMode default empty, (months|years)
18678 * @cfg {Number} startDate default -Infinity
18679 * @cfg {Number} endDate default Infinity
18680 * @cfg {Boolean} todayHighlight default false
18681 * @cfg {Boolean} todayBtn default false
18682 * @cfg {Boolean} calendarWeeks default false
18683 * @cfg {Object} daysOfWeekDisabled default empty
18684 * @cfg {Boolean} singleMode default false (true | false)
18686 * @cfg {Boolean} keyboardNavigation default true
18687 * @cfg {String} language default en
18690 * Create a new DateField
18691 * @param {Object} config The config object
18694 Roo.bootstrap.DateField = function(config){
18695 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18699 * Fires when this field show.
18700 * @param {Roo.bootstrap.DateField} this
18701 * @param {Mixed} date The date value
18706 * Fires when this field hide.
18707 * @param {Roo.bootstrap.DateField} this
18708 * @param {Mixed} date The date value
18713 * Fires when select a date.
18714 * @param {Roo.bootstrap.DateField} this
18715 * @param {Mixed} date The date value
18719 * @event beforeselect
18720 * Fires when before select a date.
18721 * @param {Roo.bootstrap.DateField} this
18722 * @param {Mixed} date The date value
18724 beforeselect : true
18728 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18731 * @cfg {String} format
18732 * The default date format string which can be overriden for localization support. The format must be
18733 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18737 * @cfg {String} altFormats
18738 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18739 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18741 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18749 todayHighlight : false,
18755 keyboardNavigation: true,
18757 calendarWeeks: false,
18759 startDate: -Infinity,
18763 daysOfWeekDisabled: [],
18767 singleMode : false,
18769 UTCDate: function()
18771 return new Date(Date.UTC.apply(Date, arguments));
18774 UTCToday: function()
18776 var today = new Date();
18777 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18780 getDate: function() {
18781 var d = this.getUTCDate();
18782 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18785 getUTCDate: function() {
18789 setDate: function(d) {
18790 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18793 setUTCDate: function(d) {
18795 this.setValue(this.formatDate(this.date));
18798 onRender: function(ct, position)
18801 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18803 this.language = this.language || 'en';
18804 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18805 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18807 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18808 this.format = this.format || 'm/d/y';
18809 this.isInline = false;
18810 this.isInput = true;
18811 this.component = this.el.select('.add-on', true).first() || false;
18812 this.component = (this.component && this.component.length === 0) ? false : this.component;
18813 this.hasInput = this.component && this.inputEl().length;
18815 if (typeof(this.minViewMode === 'string')) {
18816 switch (this.minViewMode) {
18818 this.minViewMode = 1;
18821 this.minViewMode = 2;
18824 this.minViewMode = 0;
18829 if (typeof(this.viewMode === 'string')) {
18830 switch (this.viewMode) {
18843 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18845 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18847 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18849 this.picker().on('mousedown', this.onMousedown, this);
18850 this.picker().on('click', this.onClick, this);
18852 this.picker().addClass('datepicker-dropdown');
18854 this.startViewMode = this.viewMode;
18856 if(this.singleMode){
18857 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18858 v.setVisibilityMode(Roo.Element.DISPLAY);
18862 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18863 v.setStyle('width', '189px');
18867 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18868 if(!this.calendarWeeks){
18873 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18874 v.attr('colspan', function(i, val){
18875 return parseInt(val) + 1;
18880 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18882 this.setStartDate(this.startDate);
18883 this.setEndDate(this.endDate);
18885 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18892 if(this.isInline) {
18897 picker : function()
18899 return this.pickerEl;
18900 // return this.el.select('.datepicker', true).first();
18903 fillDow: function()
18905 var dowCnt = this.weekStart;
18914 if(this.calendarWeeks){
18922 while (dowCnt < this.weekStart + 7) {
18926 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18930 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18933 fillMonths: function()
18936 var months = this.picker().select('>.datepicker-months td', true).first();
18938 months.dom.innerHTML = '';
18944 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18947 months.createChild(month);
18954 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;
18956 if (this.date < this.startDate) {
18957 this.viewDate = new Date(this.startDate);
18958 } else if (this.date > this.endDate) {
18959 this.viewDate = new Date(this.endDate);
18961 this.viewDate = new Date(this.date);
18969 var d = new Date(this.viewDate),
18970 year = d.getUTCFullYear(),
18971 month = d.getUTCMonth(),
18972 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18973 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18974 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18975 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18976 currentDate = this.date && this.date.valueOf(),
18977 today = this.UTCToday();
18979 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18981 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18983 // this.picker.select('>tfoot th.today').
18984 // .text(dates[this.language].today)
18985 // .toggle(this.todayBtn !== false);
18987 this.updateNavArrows();
18990 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
18992 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
18994 prevMonth.setUTCDate(day);
18996 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
18998 var nextMonth = new Date(prevMonth);
19000 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19002 nextMonth = nextMonth.valueOf();
19004 var fillMonths = false;
19006 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19008 while(prevMonth.valueOf() <= nextMonth) {
19011 if (prevMonth.getUTCDay() === this.weekStart) {
19013 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19021 if(this.calendarWeeks){
19022 // ISO 8601: First week contains first thursday.
19023 // ISO also states week starts on Monday, but we can be more abstract here.
19025 // Start of current week: based on weekstart/current date
19026 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19027 // Thursday of this week
19028 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19029 // First Thursday of year, year from thursday
19030 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19031 // Calendar week: ms between thursdays, div ms per day, div 7 days
19032 calWeek = (th - yth) / 864e5 / 7 + 1;
19034 fillMonths.cn.push({
19042 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19044 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19047 if (this.todayHighlight &&
19048 prevMonth.getUTCFullYear() == today.getFullYear() &&
19049 prevMonth.getUTCMonth() == today.getMonth() &&
19050 prevMonth.getUTCDate() == today.getDate()) {
19051 clsName += ' today';
19054 if (currentDate && prevMonth.valueOf() === currentDate) {
19055 clsName += ' active';
19058 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19059 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19060 clsName += ' disabled';
19063 fillMonths.cn.push({
19065 cls: 'day ' + clsName,
19066 html: prevMonth.getDate()
19069 prevMonth.setDate(prevMonth.getDate()+1);
19072 var currentYear = this.date && this.date.getUTCFullYear();
19073 var currentMonth = this.date && this.date.getUTCMonth();
19075 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19077 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19078 v.removeClass('active');
19080 if(currentYear === year && k === currentMonth){
19081 v.addClass('active');
19084 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19085 v.addClass('disabled');
19091 year = parseInt(year/10, 10) * 10;
19093 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19095 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19098 for (var i = -1; i < 11; i++) {
19099 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19101 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19109 showMode: function(dir)
19112 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19115 Roo.each(this.picker().select('>div',true).elements, function(v){
19116 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19119 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19124 if(this.isInline) {
19128 this.picker().removeClass(['bottom', 'top']);
19130 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19132 * place to the top of element!
19136 this.picker().addClass('top');
19137 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19142 this.picker().addClass('bottom');
19144 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19147 parseDate : function(value)
19149 if(!value || value instanceof Date){
19152 var v = Date.parseDate(value, this.format);
19153 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19154 v = Date.parseDate(value, 'Y-m-d');
19156 if(!v && this.altFormats){
19157 if(!this.altFormatsArray){
19158 this.altFormatsArray = this.altFormats.split("|");
19160 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19161 v = Date.parseDate(value, this.altFormatsArray[i]);
19167 formatDate : function(date, fmt)
19169 return (!date || !(date instanceof Date)) ?
19170 date : date.dateFormat(fmt || this.format);
19173 onFocus : function()
19175 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19179 onBlur : function()
19181 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19183 var d = this.inputEl().getValue();
19190 showPopup : function()
19192 this.picker().show();
19196 this.fireEvent('showpopup', this, this.date);
19199 hidePopup : function()
19201 if(this.isInline) {
19204 this.picker().hide();
19205 this.viewMode = this.startViewMode;
19208 this.fireEvent('hidepopup', this, this.date);
19212 onMousedown: function(e)
19214 e.stopPropagation();
19215 e.preventDefault();
19220 Roo.bootstrap.DateField.superclass.keyup.call(this);
19224 setValue: function(v)
19226 if(this.fireEvent('beforeselect', this, v) !== false){
19227 var d = new Date(this.parseDate(v) ).clearTime();
19229 if(isNaN(d.getTime())){
19230 this.date = this.viewDate = '';
19231 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19235 v = this.formatDate(d);
19237 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19239 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19243 this.fireEvent('select', this, this.date);
19247 getValue: function()
19249 return this.formatDate(this.date);
19252 fireKey: function(e)
19254 if (!this.picker().isVisible()){
19255 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19261 var dateChanged = false,
19263 newDate, newViewDate;
19268 e.preventDefault();
19272 if (!this.keyboardNavigation) {
19275 dir = e.keyCode == 37 ? -1 : 1;
19278 newDate = this.moveYear(this.date, dir);
19279 newViewDate = this.moveYear(this.viewDate, dir);
19280 } else if (e.shiftKey){
19281 newDate = this.moveMonth(this.date, dir);
19282 newViewDate = this.moveMonth(this.viewDate, dir);
19284 newDate = new Date(this.date);
19285 newDate.setUTCDate(this.date.getUTCDate() + dir);
19286 newViewDate = new Date(this.viewDate);
19287 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19289 if (this.dateWithinRange(newDate)){
19290 this.date = newDate;
19291 this.viewDate = newViewDate;
19292 this.setValue(this.formatDate(this.date));
19294 e.preventDefault();
19295 dateChanged = true;
19300 if (!this.keyboardNavigation) {
19303 dir = e.keyCode == 38 ? -1 : 1;
19305 newDate = this.moveYear(this.date, dir);
19306 newViewDate = this.moveYear(this.viewDate, dir);
19307 } else if (e.shiftKey){
19308 newDate = this.moveMonth(this.date, dir);
19309 newViewDate = this.moveMonth(this.viewDate, dir);
19311 newDate = new Date(this.date);
19312 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19313 newViewDate = new Date(this.viewDate);
19314 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19316 if (this.dateWithinRange(newDate)){
19317 this.date = newDate;
19318 this.viewDate = newViewDate;
19319 this.setValue(this.formatDate(this.date));
19321 e.preventDefault();
19322 dateChanged = true;
19326 this.setValue(this.formatDate(this.date));
19328 e.preventDefault();
19331 this.setValue(this.formatDate(this.date));
19345 onClick: function(e)
19347 e.stopPropagation();
19348 e.preventDefault();
19350 var target = e.getTarget();
19352 if(target.nodeName.toLowerCase() === 'i'){
19353 target = Roo.get(target).dom.parentNode;
19356 var nodeName = target.nodeName;
19357 var className = target.className;
19358 var html = target.innerHTML;
19359 //Roo.log(nodeName);
19361 switch(nodeName.toLowerCase()) {
19363 switch(className) {
19369 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19370 switch(this.viewMode){
19372 this.viewDate = this.moveMonth(this.viewDate, dir);
19376 this.viewDate = this.moveYear(this.viewDate, dir);
19382 var date = new Date();
19383 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19385 this.setValue(this.formatDate(this.date));
19392 if (className.indexOf('disabled') < 0) {
19393 this.viewDate.setUTCDate(1);
19394 if (className.indexOf('month') > -1) {
19395 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19397 var year = parseInt(html, 10) || 0;
19398 this.viewDate.setUTCFullYear(year);
19402 if(this.singleMode){
19403 this.setValue(this.formatDate(this.viewDate));
19414 //Roo.log(className);
19415 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19416 var day = parseInt(html, 10) || 1;
19417 var year = this.viewDate.getUTCFullYear(),
19418 month = this.viewDate.getUTCMonth();
19420 if (className.indexOf('old') > -1) {
19427 } else if (className.indexOf('new') > -1) {
19435 //Roo.log([year,month,day]);
19436 this.date = this.UTCDate(year, month, day,0,0,0,0);
19437 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19439 //Roo.log(this.formatDate(this.date));
19440 this.setValue(this.formatDate(this.date));
19447 setStartDate: function(startDate)
19449 this.startDate = startDate || -Infinity;
19450 if (this.startDate !== -Infinity) {
19451 this.startDate = this.parseDate(this.startDate);
19454 this.updateNavArrows();
19457 setEndDate: function(endDate)
19459 this.endDate = endDate || Infinity;
19460 if (this.endDate !== Infinity) {
19461 this.endDate = this.parseDate(this.endDate);
19464 this.updateNavArrows();
19467 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19469 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19470 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19471 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19473 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19474 return parseInt(d, 10);
19477 this.updateNavArrows();
19480 updateNavArrows: function()
19482 if(this.singleMode){
19486 var d = new Date(this.viewDate),
19487 year = d.getUTCFullYear(),
19488 month = d.getUTCMonth();
19490 Roo.each(this.picker().select('.prev', true).elements, function(v){
19492 switch (this.viewMode) {
19495 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19501 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19508 Roo.each(this.picker().select('.next', true).elements, function(v){
19510 switch (this.viewMode) {
19513 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19519 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19527 moveMonth: function(date, dir)
19532 var new_date = new Date(date.valueOf()),
19533 day = new_date.getUTCDate(),
19534 month = new_date.getUTCMonth(),
19535 mag = Math.abs(dir),
19537 dir = dir > 0 ? 1 : -1;
19540 // If going back one month, make sure month is not current month
19541 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19543 return new_date.getUTCMonth() == month;
19545 // If going forward one month, make sure month is as expected
19546 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19548 return new_date.getUTCMonth() != new_month;
19550 new_month = month + dir;
19551 new_date.setUTCMonth(new_month);
19552 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19553 if (new_month < 0 || new_month > 11) {
19554 new_month = (new_month + 12) % 12;
19557 // For magnitudes >1, move one month at a time...
19558 for (var i=0; i<mag; i++) {
19559 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19560 new_date = this.moveMonth(new_date, dir);
19562 // ...then reset the day, keeping it in the new month
19563 new_month = new_date.getUTCMonth();
19564 new_date.setUTCDate(day);
19566 return new_month != new_date.getUTCMonth();
19569 // Common date-resetting loop -- if date is beyond end of month, make it
19572 new_date.setUTCDate(--day);
19573 new_date.setUTCMonth(new_month);
19578 moveYear: function(date, dir)
19580 return this.moveMonth(date, dir*12);
19583 dateWithinRange: function(date)
19585 return date >= this.startDate && date <= this.endDate;
19591 this.picker().remove();
19594 validateValue : function(value)
19596 if(this.getVisibilityEl().hasClass('hidden')){
19600 if(value.length < 1) {
19601 if(this.allowBlank){
19607 if(value.length < this.minLength){
19610 if(value.length > this.maxLength){
19614 var vt = Roo.form.VTypes;
19615 if(!vt[this.vtype](value, this)){
19619 if(typeof this.validator == "function"){
19620 var msg = this.validator(value);
19626 if(this.regex && !this.regex.test(value)){
19630 if(typeof(this.parseDate(value)) == 'undefined'){
19634 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19638 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19648 this.date = this.viewDate = '';
19650 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19655 Roo.apply(Roo.bootstrap.DateField, {
19666 html: '<i class="fa fa-arrow-left"/>'
19676 html: '<i class="fa fa-arrow-right"/>'
19718 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19719 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19720 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19721 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19722 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19735 navFnc: 'FullYear',
19740 navFnc: 'FullYear',
19745 Roo.apply(Roo.bootstrap.DateField, {
19749 cls: 'datepicker dropdown-menu roo-dynamic',
19753 cls: 'datepicker-days',
19757 cls: 'table-condensed',
19759 Roo.bootstrap.DateField.head,
19763 Roo.bootstrap.DateField.footer
19770 cls: 'datepicker-months',
19774 cls: 'table-condensed',
19776 Roo.bootstrap.DateField.head,
19777 Roo.bootstrap.DateField.content,
19778 Roo.bootstrap.DateField.footer
19785 cls: 'datepicker-years',
19789 cls: 'table-condensed',
19791 Roo.bootstrap.DateField.head,
19792 Roo.bootstrap.DateField.content,
19793 Roo.bootstrap.DateField.footer
19812 * @class Roo.bootstrap.TimeField
19813 * @extends Roo.bootstrap.Input
19814 * Bootstrap DateField class
19818 * Create a new TimeField
19819 * @param {Object} config The config object
19822 Roo.bootstrap.TimeField = function(config){
19823 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19827 * Fires when this field show.
19828 * @param {Roo.bootstrap.DateField} thisthis
19829 * @param {Mixed} date The date value
19834 * Fires when this field hide.
19835 * @param {Roo.bootstrap.DateField} this
19836 * @param {Mixed} date The date value
19841 * Fires when select a date.
19842 * @param {Roo.bootstrap.DateField} this
19843 * @param {Mixed} date The date value
19849 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19852 * @cfg {String} format
19853 * The default time format string which can be overriden for localization support. The format must be
19854 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19858 onRender: function(ct, position)
19861 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19863 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19865 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19867 this.pop = this.picker().select('>.datepicker-time',true).first();
19868 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19870 this.picker().on('mousedown', this.onMousedown, this);
19871 this.picker().on('click', this.onClick, this);
19873 this.picker().addClass('datepicker-dropdown');
19878 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19879 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19880 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19881 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19882 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19883 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19887 fireKey: function(e){
19888 if (!this.picker().isVisible()){
19889 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19895 e.preventDefault();
19903 this.onTogglePeriod();
19906 this.onIncrementMinutes();
19909 this.onDecrementMinutes();
19918 onClick: function(e) {
19919 e.stopPropagation();
19920 e.preventDefault();
19923 picker : function()
19925 return this.el.select('.datepicker', true).first();
19928 fillTime: function()
19930 var time = this.pop.select('tbody', true).first();
19932 time.dom.innerHTML = '';
19947 cls: 'hours-up glyphicon glyphicon-chevron-up'
19967 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19988 cls: 'timepicker-hour',
20003 cls: 'timepicker-minute',
20018 cls: 'btn btn-primary period',
20040 cls: 'hours-down glyphicon glyphicon-chevron-down'
20060 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20078 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20085 var hours = this.time.getHours();
20086 var minutes = this.time.getMinutes();
20099 hours = hours - 12;
20103 hours = '0' + hours;
20107 minutes = '0' + minutes;
20110 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20111 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20112 this.pop.select('button', true).first().dom.innerHTML = period;
20118 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20120 var cls = ['bottom'];
20122 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20129 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20134 this.picker().addClass(cls.join('-'));
20138 Roo.each(cls, function(c){
20140 _this.picker().setTop(_this.inputEl().getHeight());
20144 _this.picker().setTop(0 - _this.picker().getHeight());
20149 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20153 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20160 onFocus : function()
20162 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20166 onBlur : function()
20168 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20174 this.picker().show();
20179 this.fireEvent('show', this, this.date);
20184 this.picker().hide();
20187 this.fireEvent('hide', this, this.date);
20190 setTime : function()
20193 this.setValue(this.time.format(this.format));
20195 this.fireEvent('select', this, this.date);
20200 onMousedown: function(e){
20201 e.stopPropagation();
20202 e.preventDefault();
20205 onIncrementHours: function()
20207 Roo.log('onIncrementHours');
20208 this.time = this.time.add(Date.HOUR, 1);
20213 onDecrementHours: function()
20215 Roo.log('onDecrementHours');
20216 this.time = this.time.add(Date.HOUR, -1);
20220 onIncrementMinutes: function()
20222 Roo.log('onIncrementMinutes');
20223 this.time = this.time.add(Date.MINUTE, 1);
20227 onDecrementMinutes: function()
20229 Roo.log('onDecrementMinutes');
20230 this.time = this.time.add(Date.MINUTE, -1);
20234 onTogglePeriod: function()
20236 Roo.log('onTogglePeriod');
20237 this.time = this.time.add(Date.HOUR, 12);
20244 Roo.apply(Roo.bootstrap.TimeField, {
20274 cls: 'btn btn-info ok',
20286 Roo.apply(Roo.bootstrap.TimeField, {
20290 cls: 'datepicker dropdown-menu',
20294 cls: 'datepicker-time',
20298 cls: 'table-condensed',
20300 Roo.bootstrap.TimeField.content,
20301 Roo.bootstrap.TimeField.footer
20320 * @class Roo.bootstrap.MonthField
20321 * @extends Roo.bootstrap.Input
20322 * Bootstrap MonthField class
20324 * @cfg {String} language default en
20327 * Create a new MonthField
20328 * @param {Object} config The config object
20331 Roo.bootstrap.MonthField = function(config){
20332 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20337 * Fires when this field show.
20338 * @param {Roo.bootstrap.MonthField} this
20339 * @param {Mixed} date The date value
20344 * Fires when this field hide.
20345 * @param {Roo.bootstrap.MonthField} this
20346 * @param {Mixed} date The date value
20351 * Fires when select a date.
20352 * @param {Roo.bootstrap.MonthField} this
20353 * @param {String} oldvalue The old value
20354 * @param {String} newvalue The new value
20360 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20362 onRender: function(ct, position)
20365 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20367 this.language = this.language || 'en';
20368 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20369 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20371 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20372 this.isInline = false;
20373 this.isInput = true;
20374 this.component = this.el.select('.add-on', true).first() || false;
20375 this.component = (this.component && this.component.length === 0) ? false : this.component;
20376 this.hasInput = this.component && this.inputEL().length;
20378 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20380 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20382 this.picker().on('mousedown', this.onMousedown, this);
20383 this.picker().on('click', this.onClick, this);
20385 this.picker().addClass('datepicker-dropdown');
20387 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20388 v.setStyle('width', '189px');
20395 if(this.isInline) {
20401 setValue: function(v, suppressEvent)
20403 var o = this.getValue();
20405 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20409 if(suppressEvent !== true){
20410 this.fireEvent('select', this, o, v);
20415 getValue: function()
20420 onClick: function(e)
20422 e.stopPropagation();
20423 e.preventDefault();
20425 var target = e.getTarget();
20427 if(target.nodeName.toLowerCase() === 'i'){
20428 target = Roo.get(target).dom.parentNode;
20431 var nodeName = target.nodeName;
20432 var className = target.className;
20433 var html = target.innerHTML;
20435 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20439 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20441 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20447 picker : function()
20449 return this.pickerEl;
20452 fillMonths: function()
20455 var months = this.picker().select('>.datepicker-months td', true).first();
20457 months.dom.innerHTML = '';
20463 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20466 months.createChild(month);
20475 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20476 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20479 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20480 e.removeClass('active');
20482 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20483 e.addClass('active');
20490 if(this.isInline) {
20494 this.picker().removeClass(['bottom', 'top']);
20496 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20498 * place to the top of element!
20502 this.picker().addClass('top');
20503 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20508 this.picker().addClass('bottom');
20510 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20513 onFocus : function()
20515 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20519 onBlur : function()
20521 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20523 var d = this.inputEl().getValue();
20532 this.picker().show();
20533 this.picker().select('>.datepicker-months', true).first().show();
20537 this.fireEvent('show', this, this.date);
20542 if(this.isInline) {
20545 this.picker().hide();
20546 this.fireEvent('hide', this, this.date);
20550 onMousedown: function(e)
20552 e.stopPropagation();
20553 e.preventDefault();
20558 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20562 fireKey: function(e)
20564 if (!this.picker().isVisible()){
20565 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20576 e.preventDefault();
20580 dir = e.keyCode == 37 ? -1 : 1;
20582 this.vIndex = this.vIndex + dir;
20584 if(this.vIndex < 0){
20588 if(this.vIndex > 11){
20592 if(isNaN(this.vIndex)){
20596 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20602 dir = e.keyCode == 38 ? -1 : 1;
20604 this.vIndex = this.vIndex + dir * 4;
20606 if(this.vIndex < 0){
20610 if(this.vIndex > 11){
20614 if(isNaN(this.vIndex)){
20618 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20623 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20624 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20628 e.preventDefault();
20631 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20632 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20648 this.picker().remove();
20653 Roo.apply(Roo.bootstrap.MonthField, {
20672 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20673 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20678 Roo.apply(Roo.bootstrap.MonthField, {
20682 cls: 'datepicker dropdown-menu roo-dynamic',
20686 cls: 'datepicker-months',
20690 cls: 'table-condensed',
20692 Roo.bootstrap.DateField.content
20712 * @class Roo.bootstrap.CheckBox
20713 * @extends Roo.bootstrap.Input
20714 * Bootstrap CheckBox class
20716 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20717 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20718 * @cfg {String} boxLabel The text that appears beside the checkbox
20719 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20720 * @cfg {Boolean} checked initnal the element
20721 * @cfg {Boolean} inline inline the element (default false)
20722 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20723 * @cfg {String} tooltip label tooltip
20726 * Create a new CheckBox
20727 * @param {Object} config The config object
20730 Roo.bootstrap.CheckBox = function(config){
20731 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20736 * Fires when the element is checked or unchecked.
20737 * @param {Roo.bootstrap.CheckBox} this This input
20738 * @param {Boolean} checked The new checked value
20743 * Fires when the element is click.
20744 * @param {Roo.bootstrap.CheckBox} this This input
20751 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20753 inputType: 'checkbox',
20762 getAutoCreate : function()
20764 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20770 cfg.cls = 'form-group ' + this.inputType; //input-group
20773 cfg.cls += ' ' + this.inputType + '-inline';
20779 type : this.inputType,
20780 value : this.inputValue,
20781 cls : 'roo-' + this.inputType, //'form-box',
20782 placeholder : this.placeholder || ''
20786 if(this.inputType != 'radio'){
20790 cls : 'roo-hidden-value',
20791 value : this.checked ? this.inputValue : this.valueOff
20796 if (this.weight) { // Validity check?
20797 cfg.cls += " " + this.inputType + "-" + this.weight;
20800 if (this.disabled) {
20801 input.disabled=true;
20805 input.checked = this.checked;
20810 input.name = this.name;
20812 if(this.inputType != 'radio'){
20813 hidden.name = this.name;
20814 input.name = '_hidden_' + this.name;
20819 input.cls += ' input-' + this.size;
20824 ['xs','sm','md','lg'].map(function(size){
20825 if (settings[size]) {
20826 cfg.cls += ' col-' + size + '-' + settings[size];
20830 var inputblock = input;
20832 if (this.before || this.after) {
20835 cls : 'input-group',
20840 inputblock.cn.push({
20842 cls : 'input-group-addon',
20847 inputblock.cn.push(input);
20849 if(this.inputType != 'radio'){
20850 inputblock.cn.push(hidden);
20854 inputblock.cn.push({
20856 cls : 'input-group-addon',
20863 if (align ==='left' && this.fieldLabel.length) {
20864 // Roo.log("left and has label");
20869 cls : 'control-label',
20870 html : this.fieldLabel
20880 if(this.labelWidth > 12){
20881 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20884 if(this.labelWidth < 13 && this.labelmd == 0){
20885 this.labelmd = this.labelWidth;
20888 if(this.labellg > 0){
20889 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20890 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20893 if(this.labelmd > 0){
20894 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20895 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20898 if(this.labelsm > 0){
20899 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20900 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20903 if(this.labelxs > 0){
20904 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20905 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20908 } else if ( this.fieldLabel.length) {
20909 // Roo.log(" label");
20913 tag: this.boxLabel ? 'span' : 'label',
20915 cls: 'control-label box-input-label',
20916 //cls : 'input-group-addon',
20917 html : this.fieldLabel
20926 // Roo.log(" no label && no align");
20927 cfg.cn = [ inputblock ] ;
20933 var boxLabelCfg = {
20935 //'for': id, // box label is handled by onclick - so no for...
20937 html: this.boxLabel
20941 boxLabelCfg.tooltip = this.tooltip;
20944 cfg.cn.push(boxLabelCfg);
20947 if(this.inputType != 'radio'){
20948 cfg.cn.push(hidden);
20956 * return the real input element.
20958 inputEl: function ()
20960 return this.el.select('input.roo-' + this.inputType,true).first();
20962 hiddenEl: function ()
20964 return this.el.select('input.roo-hidden-value',true).first();
20967 labelEl: function()
20969 return this.el.select('label.control-label',true).first();
20971 /* depricated... */
20975 return this.labelEl();
20978 boxLabelEl: function()
20980 return this.el.select('label.box-label',true).first();
20983 initEvents : function()
20985 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20987 this.inputEl().on('click', this.onClick, this);
20989 if (this.boxLabel) {
20990 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
20993 this.startValue = this.getValue();
20996 Roo.bootstrap.CheckBox.register(this);
21000 onClick : function(e)
21002 if(this.fireEvent('click', this, e) !== false){
21003 this.setChecked(!this.checked);
21008 setChecked : function(state,suppressEvent)
21010 this.startValue = this.getValue();
21012 if(this.inputType == 'radio'){
21014 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21015 e.dom.checked = false;
21018 this.inputEl().dom.checked = true;
21020 this.inputEl().dom.value = this.inputValue;
21022 if(suppressEvent !== true){
21023 this.fireEvent('check', this, true);
21031 this.checked = state;
21033 this.inputEl().dom.checked = state;
21036 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21038 if(suppressEvent !== true){
21039 this.fireEvent('check', this, state);
21045 getValue : function()
21047 if(this.inputType == 'radio'){
21048 return this.getGroupValue();
21051 return this.hiddenEl().dom.value;
21055 getGroupValue : function()
21057 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21061 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21064 setValue : function(v,suppressEvent)
21066 if(this.inputType == 'radio'){
21067 this.setGroupValue(v, suppressEvent);
21071 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21076 setGroupValue : function(v, suppressEvent)
21078 this.startValue = this.getValue();
21080 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21081 e.dom.checked = false;
21083 if(e.dom.value == v){
21084 e.dom.checked = true;
21088 if(suppressEvent !== true){
21089 this.fireEvent('check', this, true);
21097 validate : function()
21099 if(this.getVisibilityEl().hasClass('hidden')){
21105 (this.inputType == 'radio' && this.validateRadio()) ||
21106 (this.inputType == 'checkbox' && this.validateCheckbox())
21112 this.markInvalid();
21116 validateRadio : function()
21118 if(this.getVisibilityEl().hasClass('hidden')){
21122 if(this.allowBlank){
21128 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21129 if(!e.dom.checked){
21141 validateCheckbox : function()
21144 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21145 //return (this.getValue() == this.inputValue) ? true : false;
21148 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21156 for(var i in group){
21157 if(group[i].el.isVisible(true)){
21165 for(var i in group){
21170 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21177 * Mark this field as valid
21179 markValid : function()
21183 this.fireEvent('valid', this);
21185 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21188 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21195 if(this.inputType == 'radio'){
21196 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21197 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21198 e.findParent('.form-group', false, true).addClass(_this.validClass);
21205 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21206 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21210 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21216 for(var i in group){
21217 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21218 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21223 * Mark this field as invalid
21224 * @param {String} msg The validation message
21226 markInvalid : function(msg)
21228 if(this.allowBlank){
21234 this.fireEvent('invalid', this, msg);
21236 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21239 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21243 label.markInvalid();
21246 if(this.inputType == 'radio'){
21247 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21248 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21249 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21256 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21257 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21261 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21267 for(var i in group){
21268 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21269 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21274 clearInvalid : function()
21276 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21278 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21280 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21282 if (label && label.iconEl) {
21283 label.iconEl.removeClass(label.validClass);
21284 label.iconEl.removeClass(label.invalidClass);
21288 disable : function()
21290 if(this.inputType != 'radio'){
21291 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21298 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21299 _this.getActionEl().addClass(this.disabledClass);
21300 e.dom.disabled = true;
21304 this.disabled = true;
21305 this.fireEvent("disable", this);
21309 enable : function()
21311 if(this.inputType != 'radio'){
21312 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21319 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21320 _this.getActionEl().removeClass(this.disabledClass);
21321 e.dom.disabled = false;
21325 this.disabled = false;
21326 this.fireEvent("enable", this);
21330 setBoxLabel : function(v)
21335 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21341 Roo.apply(Roo.bootstrap.CheckBox, {
21346 * register a CheckBox Group
21347 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21349 register : function(checkbox)
21351 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21352 this.groups[checkbox.groupId] = {};
21355 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21359 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21363 * fetch a CheckBox Group based on the group ID
21364 * @param {string} the group ID
21365 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21367 get: function(groupId) {
21368 if (typeof(this.groups[groupId]) == 'undefined') {
21372 return this.groups[groupId] ;
21385 * @class Roo.bootstrap.Radio
21386 * @extends Roo.bootstrap.Component
21387 * Bootstrap Radio class
21388 * @cfg {String} boxLabel - the label associated
21389 * @cfg {String} value - the value of radio
21392 * Create a new Radio
21393 * @param {Object} config The config object
21395 Roo.bootstrap.Radio = function(config){
21396 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21400 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21406 getAutoCreate : function()
21410 cls : 'form-group radio',
21415 html : this.boxLabel
21423 initEvents : function()
21425 this.parent().register(this);
21427 this.el.on('click', this.onClick, this);
21431 onClick : function(e)
21433 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21434 this.setChecked(true);
21438 setChecked : function(state, suppressEvent)
21440 this.parent().setValue(this.value, suppressEvent);
21444 setBoxLabel : function(v)
21449 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21464 * @class Roo.bootstrap.SecurePass
21465 * @extends Roo.bootstrap.Input
21466 * Bootstrap SecurePass class
21470 * Create a new SecurePass
21471 * @param {Object} config The config object
21474 Roo.bootstrap.SecurePass = function (config) {
21475 // these go here, so the translation tool can replace them..
21477 PwdEmpty: "Please type a password, and then retype it to confirm.",
21478 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21479 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21480 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21481 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21482 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21483 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21484 TooWeak: "Your password is Too Weak."
21486 this.meterLabel = "Password strength:";
21487 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21488 this.meterClass = [
21489 "roo-password-meter-tooweak",
21490 "roo-password-meter-weak",
21491 "roo-password-meter-medium",
21492 "roo-password-meter-strong",
21493 "roo-password-meter-grey"
21498 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21501 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21503 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21505 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21506 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21507 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21508 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21509 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21510 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21511 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21521 * @cfg {String/Object} Label for the strength meter (defaults to
21522 * 'Password strength:')
21527 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21528 * ['Weak', 'Medium', 'Strong'])
21531 pwdStrengths: false,
21544 initEvents: function ()
21546 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21548 if (this.el.is('input[type=password]') && Roo.isSafari) {
21549 this.el.on('keydown', this.SafariOnKeyDown, this);
21552 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21555 onRender: function (ct, position)
21557 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21558 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21559 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21561 this.trigger.createChild({
21566 cls: 'roo-password-meter-grey col-xs-12',
21569 //width: this.meterWidth + 'px'
21573 cls: 'roo-password-meter-text'
21579 if (this.hideTrigger) {
21580 this.trigger.setDisplayed(false);
21582 this.setSize(this.width || '', this.height || '');
21585 onDestroy: function ()
21587 if (this.trigger) {
21588 this.trigger.removeAllListeners();
21589 this.trigger.remove();
21592 this.wrap.remove();
21594 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21597 checkStrength: function ()
21599 var pwd = this.inputEl().getValue();
21600 if (pwd == this._lastPwd) {
21605 if (this.ClientSideStrongPassword(pwd)) {
21607 } else if (this.ClientSideMediumPassword(pwd)) {
21609 } else if (this.ClientSideWeakPassword(pwd)) {
21615 Roo.log('strength1: ' + strength);
21617 //var pm = this.trigger.child('div/div/div').dom;
21618 var pm = this.trigger.child('div/div');
21619 pm.removeClass(this.meterClass);
21620 pm.addClass(this.meterClass[strength]);
21623 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21625 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21627 this._lastPwd = pwd;
21631 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21633 this._lastPwd = '';
21635 var pm = this.trigger.child('div/div');
21636 pm.removeClass(this.meterClass);
21637 pm.addClass('roo-password-meter-grey');
21640 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21643 this.inputEl().dom.type='password';
21646 validateValue: function (value)
21649 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21652 if (value.length == 0) {
21653 if (this.allowBlank) {
21654 this.clearInvalid();
21658 this.markInvalid(this.errors.PwdEmpty);
21659 this.errorMsg = this.errors.PwdEmpty;
21667 if ('[\x21-\x7e]*'.match(value)) {
21668 this.markInvalid(this.errors.PwdBadChar);
21669 this.errorMsg = this.errors.PwdBadChar;
21672 if (value.length < 6) {
21673 this.markInvalid(this.errors.PwdShort);
21674 this.errorMsg = this.errors.PwdShort;
21677 if (value.length > 16) {
21678 this.markInvalid(this.errors.PwdLong);
21679 this.errorMsg = this.errors.PwdLong;
21683 if (this.ClientSideStrongPassword(value)) {
21685 } else if (this.ClientSideMediumPassword(value)) {
21687 } else if (this.ClientSideWeakPassword(value)) {
21694 if (strength < 2) {
21695 //this.markInvalid(this.errors.TooWeak);
21696 this.errorMsg = this.errors.TooWeak;
21701 console.log('strength2: ' + strength);
21703 //var pm = this.trigger.child('div/div/div').dom;
21705 var pm = this.trigger.child('div/div');
21706 pm.removeClass(this.meterClass);
21707 pm.addClass(this.meterClass[strength]);
21709 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21711 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21713 this.errorMsg = '';
21717 CharacterSetChecks: function (type)
21720 this.fResult = false;
21723 isctype: function (character, type)
21726 case this.kCapitalLetter:
21727 if (character >= 'A' && character <= 'Z') {
21732 case this.kSmallLetter:
21733 if (character >= 'a' && character <= 'z') {
21739 if (character >= '0' && character <= '9') {
21744 case this.kPunctuation:
21745 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21756 IsLongEnough: function (pwd, size)
21758 return !(pwd == null || isNaN(size) || pwd.length < size);
21761 SpansEnoughCharacterSets: function (word, nb)
21763 if (!this.IsLongEnough(word, nb))
21768 var characterSetChecks = new Array(
21769 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21770 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21773 for (var index = 0; index < word.length; ++index) {
21774 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21775 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21776 characterSetChecks[nCharSet].fResult = true;
21783 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21784 if (characterSetChecks[nCharSet].fResult) {
21789 if (nCharSets < nb) {
21795 ClientSideStrongPassword: function (pwd)
21797 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21800 ClientSideMediumPassword: function (pwd)
21802 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21805 ClientSideWeakPassword: function (pwd)
21807 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21810 })//<script type="text/javascript">
21813 * Based Ext JS Library 1.1.1
21814 * Copyright(c) 2006-2007, Ext JS, LLC.
21820 * @class Roo.HtmlEditorCore
21821 * @extends Roo.Component
21822 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21824 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21827 Roo.HtmlEditorCore = function(config){
21830 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21835 * @event initialize
21836 * Fires when the editor is fully initialized (including the iframe)
21837 * @param {Roo.HtmlEditorCore} this
21842 * Fires when the editor is first receives the focus. Any insertion must wait
21843 * until after this event.
21844 * @param {Roo.HtmlEditorCore} this
21848 * @event beforesync
21849 * Fires before the textarea is updated with content from the editor iframe. Return false
21850 * to cancel the sync.
21851 * @param {Roo.HtmlEditorCore} this
21852 * @param {String} html
21856 * @event beforepush
21857 * Fires before the iframe editor is updated with content from the textarea. Return false
21858 * to cancel the push.
21859 * @param {Roo.HtmlEditorCore} this
21860 * @param {String} html
21865 * Fires when the textarea is updated with content from the editor iframe.
21866 * @param {Roo.HtmlEditorCore} this
21867 * @param {String} html
21872 * Fires when the iframe editor is updated with content from the textarea.
21873 * @param {Roo.HtmlEditorCore} this
21874 * @param {String} html
21879 * @event editorevent
21880 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21881 * @param {Roo.HtmlEditorCore} this
21887 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21889 // defaults : white / black...
21890 this.applyBlacklists();
21897 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21901 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21907 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21912 * @cfg {Number} height (in pixels)
21916 * @cfg {Number} width (in pixels)
21921 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21924 stylesheets: false,
21929 // private properties
21930 validationEvent : false,
21932 initialized : false,
21934 sourceEditMode : false,
21935 onFocus : Roo.emptyFn,
21937 hideMode:'offsets',
21941 // blacklist + whitelisted elements..
21948 * Protected method that will not generally be called directly. It
21949 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21950 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21952 getDocMarkup : function(){
21956 // inherit styels from page...??
21957 if (this.stylesheets === false) {
21959 Roo.get(document.head).select('style').each(function(node) {
21960 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21963 Roo.get(document.head).select('link').each(function(node) {
21964 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21967 } else if (!this.stylesheets.length) {
21969 st = '<style type="text/css">' +
21970 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21973 st = '<style type="text/css">' +
21978 st += '<style type="text/css">' +
21979 'IMG { cursor: pointer } ' +
21982 var cls = 'roo-htmleditor-body';
21984 if(this.bodyCls.length){
21985 cls += ' ' + this.bodyCls;
21988 return '<html><head>' + st +
21989 //<style type="text/css">' +
21990 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21992 ' </head><body class="' + cls + '"></body></html>';
21996 onRender : function(ct, position)
21999 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22000 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22003 this.el.dom.style.border = '0 none';
22004 this.el.dom.setAttribute('tabIndex', -1);
22005 this.el.addClass('x-hidden hide');
22009 if(Roo.isIE){ // fix IE 1px bogus margin
22010 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22014 this.frameId = Roo.id();
22018 var iframe = this.owner.wrap.createChild({
22020 cls: 'form-control', // bootstrap..
22022 name: this.frameId,
22023 frameBorder : 'no',
22024 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22029 this.iframe = iframe.dom;
22031 this.assignDocWin();
22033 this.doc.designMode = 'on';
22036 this.doc.write(this.getDocMarkup());
22040 var task = { // must defer to wait for browser to be ready
22042 //console.log("run task?" + this.doc.readyState);
22043 this.assignDocWin();
22044 if(this.doc.body || this.doc.readyState == 'complete'){
22046 this.doc.designMode="on";
22050 Roo.TaskMgr.stop(task);
22051 this.initEditor.defer(10, this);
22058 Roo.TaskMgr.start(task);
22063 onResize : function(w, h)
22065 Roo.log('resize: ' +w + ',' + h );
22066 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22070 if(typeof w == 'number'){
22072 this.iframe.style.width = w + 'px';
22074 if(typeof h == 'number'){
22076 this.iframe.style.height = h + 'px';
22078 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22085 * Toggles the editor between standard and source edit mode.
22086 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22088 toggleSourceEdit : function(sourceEditMode){
22090 this.sourceEditMode = sourceEditMode === true;
22092 if(this.sourceEditMode){
22094 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22097 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22098 //this.iframe.className = '';
22101 //this.setSize(this.owner.wrap.getSize());
22102 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22109 * Protected method that will not generally be called directly. If you need/want
22110 * custom HTML cleanup, this is the method you should override.
22111 * @param {String} html The HTML to be cleaned
22112 * return {String} The cleaned HTML
22114 cleanHtml : function(html){
22115 html = String(html);
22116 if(html.length > 5){
22117 if(Roo.isSafari){ // strip safari nonsense
22118 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22121 if(html == ' '){
22128 * HTML Editor -> Textarea
22129 * Protected method that will not generally be called directly. Syncs the contents
22130 * of the editor iframe with the textarea.
22132 syncValue : function(){
22133 if(this.initialized){
22134 var bd = (this.doc.body || this.doc.documentElement);
22135 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22136 var html = bd.innerHTML;
22138 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22139 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22141 html = '<div style="'+m[0]+'">' + html + '</div>';
22144 html = this.cleanHtml(html);
22145 // fix up the special chars.. normaly like back quotes in word...
22146 // however we do not want to do this with chinese..
22147 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22148 var cc = b.charCodeAt();
22150 (cc >= 0x4E00 && cc < 0xA000 ) ||
22151 (cc >= 0x3400 && cc < 0x4E00 ) ||
22152 (cc >= 0xf900 && cc < 0xfb00 )
22158 if(this.owner.fireEvent('beforesync', this, html) !== false){
22159 this.el.dom.value = html;
22160 this.owner.fireEvent('sync', this, html);
22166 * Protected method that will not generally be called directly. Pushes the value of the textarea
22167 * into the iframe editor.
22169 pushValue : function(){
22170 if(this.initialized){
22171 var v = this.el.dom.value.trim();
22173 // if(v.length < 1){
22177 if(this.owner.fireEvent('beforepush', this, v) !== false){
22178 var d = (this.doc.body || this.doc.documentElement);
22180 this.cleanUpPaste();
22181 this.el.dom.value = d.innerHTML;
22182 this.owner.fireEvent('push', this, v);
22188 deferFocus : function(){
22189 this.focus.defer(10, this);
22193 focus : function(){
22194 if(this.win && !this.sourceEditMode){
22201 assignDocWin: function()
22203 var iframe = this.iframe;
22206 this.doc = iframe.contentWindow.document;
22207 this.win = iframe.contentWindow;
22209 // if (!Roo.get(this.frameId)) {
22212 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22213 // this.win = Roo.get(this.frameId).dom.contentWindow;
22215 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22219 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22220 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22225 initEditor : function(){
22226 //console.log("INIT EDITOR");
22227 this.assignDocWin();
22231 this.doc.designMode="on";
22233 this.doc.write(this.getDocMarkup());
22236 var dbody = (this.doc.body || this.doc.documentElement);
22237 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22238 // this copies styles from the containing element into thsi one..
22239 // not sure why we need all of this..
22240 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22242 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22243 //ss['background-attachment'] = 'fixed'; // w3c
22244 dbody.bgProperties = 'fixed'; // ie
22245 //Roo.DomHelper.applyStyles(dbody, ss);
22246 Roo.EventManager.on(this.doc, {
22247 //'mousedown': this.onEditorEvent,
22248 'mouseup': this.onEditorEvent,
22249 'dblclick': this.onEditorEvent,
22250 'click': this.onEditorEvent,
22251 'keyup': this.onEditorEvent,
22256 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22258 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22259 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22261 this.initialized = true;
22263 this.owner.fireEvent('initialize', this);
22268 onDestroy : function(){
22274 //for (var i =0; i < this.toolbars.length;i++) {
22275 // // fixme - ask toolbars for heights?
22276 // this.toolbars[i].onDestroy();
22279 //this.wrap.dom.innerHTML = '';
22280 //this.wrap.remove();
22285 onFirstFocus : function(){
22287 this.assignDocWin();
22290 this.activated = true;
22293 if(Roo.isGecko){ // prevent silly gecko errors
22295 var s = this.win.getSelection();
22296 if(!s.focusNode || s.focusNode.nodeType != 3){
22297 var r = s.getRangeAt(0);
22298 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22303 this.execCmd('useCSS', true);
22304 this.execCmd('styleWithCSS', false);
22307 this.owner.fireEvent('activate', this);
22311 adjustFont: function(btn){
22312 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22313 //if(Roo.isSafari){ // safari
22316 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22317 if(Roo.isSafari){ // safari
22318 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22319 v = (v < 10) ? 10 : v;
22320 v = (v > 48) ? 48 : v;
22321 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22326 v = Math.max(1, v+adjust);
22328 this.execCmd('FontSize', v );
22331 onEditorEvent : function(e)
22333 this.owner.fireEvent('editorevent', this, e);
22334 // this.updateToolbar();
22335 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22338 insertTag : function(tg)
22340 // could be a bit smarter... -> wrap the current selected tRoo..
22341 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22343 range = this.createRange(this.getSelection());
22344 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22345 wrappingNode.appendChild(range.extractContents());
22346 range.insertNode(wrappingNode);
22353 this.execCmd("formatblock", tg);
22357 insertText : function(txt)
22361 var range = this.createRange();
22362 range.deleteContents();
22363 //alert(Sender.getAttribute('label'));
22365 range.insertNode(this.doc.createTextNode(txt));
22371 * Executes a Midas editor command on the editor document and performs necessary focus and
22372 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22373 * @param {String} cmd The Midas command
22374 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22376 relayCmd : function(cmd, value){
22378 this.execCmd(cmd, value);
22379 this.owner.fireEvent('editorevent', this);
22380 //this.updateToolbar();
22381 this.owner.deferFocus();
22385 * Executes a Midas editor command directly on the editor document.
22386 * For visual commands, you should use {@link #relayCmd} instead.
22387 * <b>This should only be called after the editor is initialized.</b>
22388 * @param {String} cmd The Midas command
22389 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22391 execCmd : function(cmd, value){
22392 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22399 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22401 * @param {String} text | dom node..
22403 insertAtCursor : function(text)
22406 if(!this.activated){
22412 var r = this.doc.selection.createRange();
22423 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22427 // from jquery ui (MIT licenced)
22429 var win = this.win;
22431 if (win.getSelection && win.getSelection().getRangeAt) {
22432 range = win.getSelection().getRangeAt(0);
22433 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22434 range.insertNode(node);
22435 } else if (win.document.selection && win.document.selection.createRange) {
22436 // no firefox support
22437 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22438 win.document.selection.createRange().pasteHTML(txt);
22440 // no firefox support
22441 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22442 this.execCmd('InsertHTML', txt);
22451 mozKeyPress : function(e){
22453 var c = e.getCharCode(), cmd;
22456 c = String.fromCharCode(c).toLowerCase();
22470 this.cleanUpPaste.defer(100, this);
22478 e.preventDefault();
22486 fixKeys : function(){ // load time branching for fastest keydown performance
22488 return function(e){
22489 var k = e.getKey(), r;
22492 r = this.doc.selection.createRange();
22495 r.pasteHTML('    ');
22502 r = this.doc.selection.createRange();
22504 var target = r.parentElement();
22505 if(!target || target.tagName.toLowerCase() != 'li'){
22507 r.pasteHTML('<br />');
22513 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22514 this.cleanUpPaste.defer(100, this);
22520 }else if(Roo.isOpera){
22521 return function(e){
22522 var k = e.getKey();
22526 this.execCmd('InsertHTML','    ');
22529 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22530 this.cleanUpPaste.defer(100, this);
22535 }else if(Roo.isSafari){
22536 return function(e){
22537 var k = e.getKey();
22541 this.execCmd('InsertText','\t');
22545 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22546 this.cleanUpPaste.defer(100, this);
22554 getAllAncestors: function()
22556 var p = this.getSelectedNode();
22559 a.push(p); // push blank onto stack..
22560 p = this.getParentElement();
22564 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22568 a.push(this.doc.body);
22572 lastSelNode : false,
22575 getSelection : function()
22577 this.assignDocWin();
22578 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22581 getSelectedNode: function()
22583 // this may only work on Gecko!!!
22585 // should we cache this!!!!
22590 var range = this.createRange(this.getSelection()).cloneRange();
22593 var parent = range.parentElement();
22595 var testRange = range.duplicate();
22596 testRange.moveToElementText(parent);
22597 if (testRange.inRange(range)) {
22600 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22603 parent = parent.parentElement;
22608 // is ancestor a text element.
22609 var ac = range.commonAncestorContainer;
22610 if (ac.nodeType == 3) {
22611 ac = ac.parentNode;
22614 var ar = ac.childNodes;
22617 var other_nodes = [];
22618 var has_other_nodes = false;
22619 for (var i=0;i<ar.length;i++) {
22620 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22623 // fullly contained node.
22625 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22630 // probably selected..
22631 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22632 other_nodes.push(ar[i]);
22636 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22641 has_other_nodes = true;
22643 if (!nodes.length && other_nodes.length) {
22644 nodes= other_nodes;
22646 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22652 createRange: function(sel)
22654 // this has strange effects when using with
22655 // top toolbar - not sure if it's a great idea.
22656 //this.editor.contentWindow.focus();
22657 if (typeof sel != "undefined") {
22659 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22661 return this.doc.createRange();
22664 return this.doc.createRange();
22667 getParentElement: function()
22670 this.assignDocWin();
22671 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22673 var range = this.createRange(sel);
22676 var p = range.commonAncestorContainer;
22677 while (p.nodeType == 3) { // text node
22688 * Range intersection.. the hard stuff...
22692 * [ -- selected range --- ]
22696 * if end is before start or hits it. fail.
22697 * if start is after end or hits it fail.
22699 * if either hits (but other is outside. - then it's not
22705 // @see http://www.thismuchiknow.co.uk/?p=64.
22706 rangeIntersectsNode : function(range, node)
22708 var nodeRange = node.ownerDocument.createRange();
22710 nodeRange.selectNode(node);
22712 nodeRange.selectNodeContents(node);
22715 var rangeStartRange = range.cloneRange();
22716 rangeStartRange.collapse(true);
22718 var rangeEndRange = range.cloneRange();
22719 rangeEndRange.collapse(false);
22721 var nodeStartRange = nodeRange.cloneRange();
22722 nodeStartRange.collapse(true);
22724 var nodeEndRange = nodeRange.cloneRange();
22725 nodeEndRange.collapse(false);
22727 return rangeStartRange.compareBoundaryPoints(
22728 Range.START_TO_START, nodeEndRange) == -1 &&
22729 rangeEndRange.compareBoundaryPoints(
22730 Range.START_TO_START, nodeStartRange) == 1;
22734 rangeCompareNode : function(range, node)
22736 var nodeRange = node.ownerDocument.createRange();
22738 nodeRange.selectNode(node);
22740 nodeRange.selectNodeContents(node);
22744 range.collapse(true);
22746 nodeRange.collapse(true);
22748 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22749 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22751 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22753 var nodeIsBefore = ss == 1;
22754 var nodeIsAfter = ee == -1;
22756 if (nodeIsBefore && nodeIsAfter) {
22759 if (!nodeIsBefore && nodeIsAfter) {
22760 return 1; //right trailed.
22763 if (nodeIsBefore && !nodeIsAfter) {
22764 return 2; // left trailed.
22770 // private? - in a new class?
22771 cleanUpPaste : function()
22773 // cleans up the whole document..
22774 Roo.log('cleanuppaste');
22776 this.cleanUpChildren(this.doc.body);
22777 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22778 if (clean != this.doc.body.innerHTML) {
22779 this.doc.body.innerHTML = clean;
22784 cleanWordChars : function(input) {// change the chars to hex code
22785 var he = Roo.HtmlEditorCore;
22787 var output = input;
22788 Roo.each(he.swapCodes, function(sw) {
22789 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22791 output = output.replace(swapper, sw[1]);
22798 cleanUpChildren : function (n)
22800 if (!n.childNodes.length) {
22803 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22804 this.cleanUpChild(n.childNodes[i]);
22811 cleanUpChild : function (node)
22814 //console.log(node);
22815 if (node.nodeName == "#text") {
22816 // clean up silly Windows -- stuff?
22819 if (node.nodeName == "#comment") {
22820 node.parentNode.removeChild(node);
22821 // clean up silly Windows -- stuff?
22824 var lcname = node.tagName.toLowerCase();
22825 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22826 // whitelist of tags..
22828 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22830 node.parentNode.removeChild(node);
22835 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22837 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22838 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22840 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22841 // remove_keep_children = true;
22844 if (remove_keep_children) {
22845 this.cleanUpChildren(node);
22846 // inserts everything just before this node...
22847 while (node.childNodes.length) {
22848 var cn = node.childNodes[0];
22849 node.removeChild(cn);
22850 node.parentNode.insertBefore(cn, node);
22852 node.parentNode.removeChild(node);
22856 if (!node.attributes || !node.attributes.length) {
22857 this.cleanUpChildren(node);
22861 function cleanAttr(n,v)
22864 if (v.match(/^\./) || v.match(/^\//)) {
22867 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22870 if (v.match(/^#/)) {
22873 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22874 node.removeAttribute(n);
22878 var cwhite = this.cwhite;
22879 var cblack = this.cblack;
22881 function cleanStyle(n,v)
22883 if (v.match(/expression/)) { //XSS?? should we even bother..
22884 node.removeAttribute(n);
22888 var parts = v.split(/;/);
22891 Roo.each(parts, function(p) {
22892 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22896 var l = p.split(':').shift().replace(/\s+/g,'');
22897 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22899 if ( cwhite.length && cblack.indexOf(l) > -1) {
22900 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22901 //node.removeAttribute(n);
22905 // only allow 'c whitelisted system attributes'
22906 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22907 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22908 //node.removeAttribute(n);
22918 if (clean.length) {
22919 node.setAttribute(n, clean.join(';'));
22921 node.removeAttribute(n);
22927 for (var i = node.attributes.length-1; i > -1 ; i--) {
22928 var a = node.attributes[i];
22931 if (a.name.toLowerCase().substr(0,2)=='on') {
22932 node.removeAttribute(a.name);
22935 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22936 node.removeAttribute(a.name);
22939 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22940 cleanAttr(a.name,a.value); // fixme..
22943 if (a.name == 'style') {
22944 cleanStyle(a.name,a.value);
22947 /// clean up MS crap..
22948 // tecnically this should be a list of valid class'es..
22951 if (a.name == 'class') {
22952 if (a.value.match(/^Mso/)) {
22953 node.className = '';
22956 if (a.value.match(/^body$/)) {
22957 node.className = '';
22968 this.cleanUpChildren(node);
22974 * Clean up MS wordisms...
22976 cleanWord : function(node)
22981 this.cleanWord(this.doc.body);
22984 if (node.nodeName == "#text") {
22985 // clean up silly Windows -- stuff?
22988 if (node.nodeName == "#comment") {
22989 node.parentNode.removeChild(node);
22990 // clean up silly Windows -- stuff?
22994 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
22995 node.parentNode.removeChild(node);
22999 // remove - but keep children..
23000 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23001 while (node.childNodes.length) {
23002 var cn = node.childNodes[0];
23003 node.removeChild(cn);
23004 node.parentNode.insertBefore(cn, node);
23006 node.parentNode.removeChild(node);
23007 this.iterateChildren(node, this.cleanWord);
23011 if (node.className.length) {
23013 var cn = node.className.split(/\W+/);
23015 Roo.each(cn, function(cls) {
23016 if (cls.match(/Mso[a-zA-Z]+/)) {
23021 node.className = cna.length ? cna.join(' ') : '';
23023 node.removeAttribute("class");
23027 if (node.hasAttribute("lang")) {
23028 node.removeAttribute("lang");
23031 if (node.hasAttribute("style")) {
23033 var styles = node.getAttribute("style").split(";");
23035 Roo.each(styles, function(s) {
23036 if (!s.match(/:/)) {
23039 var kv = s.split(":");
23040 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23043 // what ever is left... we allow.
23046 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23047 if (!nstyle.length) {
23048 node.removeAttribute('style');
23051 this.iterateChildren(node, this.cleanWord);
23057 * iterateChildren of a Node, calling fn each time, using this as the scole..
23058 * @param {DomNode} node node to iterate children of.
23059 * @param {Function} fn method of this class to call on each item.
23061 iterateChildren : function(node, fn)
23063 if (!node.childNodes.length) {
23066 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23067 fn.call(this, node.childNodes[i])
23073 * cleanTableWidths.
23075 * Quite often pasting from word etc.. results in tables with column and widths.
23076 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23079 cleanTableWidths : function(node)
23084 this.cleanTableWidths(this.doc.body);
23089 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23092 Roo.log(node.tagName);
23093 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23094 this.iterateChildren(node, this.cleanTableWidths);
23097 if (node.hasAttribute('width')) {
23098 node.removeAttribute('width');
23102 if (node.hasAttribute("style")) {
23105 var styles = node.getAttribute("style").split(";");
23107 Roo.each(styles, function(s) {
23108 if (!s.match(/:/)) {
23111 var kv = s.split(":");
23112 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23115 // what ever is left... we allow.
23118 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23119 if (!nstyle.length) {
23120 node.removeAttribute('style');
23124 this.iterateChildren(node, this.cleanTableWidths);
23132 domToHTML : function(currentElement, depth, nopadtext) {
23134 depth = depth || 0;
23135 nopadtext = nopadtext || false;
23137 if (!currentElement) {
23138 return this.domToHTML(this.doc.body);
23141 //Roo.log(currentElement);
23143 var allText = false;
23144 var nodeName = currentElement.nodeName;
23145 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23147 if (nodeName == '#text') {
23149 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23154 if (nodeName != 'BODY') {
23157 // Prints the node tagName, such as <A>, <IMG>, etc
23160 for(i = 0; i < currentElement.attributes.length;i++) {
23162 var aname = currentElement.attributes.item(i).name;
23163 if (!currentElement.attributes.item(i).value.length) {
23166 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23169 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23178 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23181 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23186 // Traverse the tree
23188 var currentElementChild = currentElement.childNodes.item(i);
23189 var allText = true;
23190 var innerHTML = '';
23192 while (currentElementChild) {
23193 // Formatting code (indent the tree so it looks nice on the screen)
23194 var nopad = nopadtext;
23195 if (lastnode == 'SPAN') {
23199 if (currentElementChild.nodeName == '#text') {
23200 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23201 toadd = nopadtext ? toadd : toadd.trim();
23202 if (!nopad && toadd.length > 80) {
23203 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23205 innerHTML += toadd;
23208 currentElementChild = currentElement.childNodes.item(i);
23214 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23216 // Recursively traverse the tree structure of the child node
23217 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23218 lastnode = currentElementChild.nodeName;
23220 currentElementChild=currentElement.childNodes.item(i);
23226 // The remaining code is mostly for formatting the tree
23227 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23232 ret+= "</"+tagName+">";
23238 applyBlacklists : function()
23240 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23241 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23245 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23246 if (b.indexOf(tag) > -1) {
23249 this.white.push(tag);
23253 Roo.each(w, function(tag) {
23254 if (b.indexOf(tag) > -1) {
23257 if (this.white.indexOf(tag) > -1) {
23260 this.white.push(tag);
23265 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23266 if (w.indexOf(tag) > -1) {
23269 this.black.push(tag);
23273 Roo.each(b, function(tag) {
23274 if (w.indexOf(tag) > -1) {
23277 if (this.black.indexOf(tag) > -1) {
23280 this.black.push(tag);
23285 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23286 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23290 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23291 if (b.indexOf(tag) > -1) {
23294 this.cwhite.push(tag);
23298 Roo.each(w, function(tag) {
23299 if (b.indexOf(tag) > -1) {
23302 if (this.cwhite.indexOf(tag) > -1) {
23305 this.cwhite.push(tag);
23310 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23311 if (w.indexOf(tag) > -1) {
23314 this.cblack.push(tag);
23318 Roo.each(b, function(tag) {
23319 if (w.indexOf(tag) > -1) {
23322 if (this.cblack.indexOf(tag) > -1) {
23325 this.cblack.push(tag);
23330 setStylesheets : function(stylesheets)
23332 if(typeof(stylesheets) == 'string'){
23333 Roo.get(this.iframe.contentDocument.head).createChild({
23335 rel : 'stylesheet',
23344 Roo.each(stylesheets, function(s) {
23349 Roo.get(_this.iframe.contentDocument.head).createChild({
23351 rel : 'stylesheet',
23360 removeStylesheets : function()
23364 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23369 setStyle : function(style)
23371 Roo.get(this.iframe.contentDocument.head).createChild({
23380 // hide stuff that is not compatible
23394 * @event specialkey
23398 * @cfg {String} fieldClass @hide
23401 * @cfg {String} focusClass @hide
23404 * @cfg {String} autoCreate @hide
23407 * @cfg {String} inputType @hide
23410 * @cfg {String} invalidClass @hide
23413 * @cfg {String} invalidText @hide
23416 * @cfg {String} msgFx @hide
23419 * @cfg {String} validateOnBlur @hide
23423 Roo.HtmlEditorCore.white = [
23424 'area', 'br', 'img', 'input', 'hr', 'wbr',
23426 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23427 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23428 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23429 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23430 'table', 'ul', 'xmp',
23432 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23435 'dir', 'menu', 'ol', 'ul', 'dl',
23441 Roo.HtmlEditorCore.black = [
23442 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23444 'base', 'basefont', 'bgsound', 'blink', 'body',
23445 'frame', 'frameset', 'head', 'html', 'ilayer',
23446 'iframe', 'layer', 'link', 'meta', 'object',
23447 'script', 'style' ,'title', 'xml' // clean later..
23449 Roo.HtmlEditorCore.clean = [
23450 'script', 'style', 'title', 'xml'
23452 Roo.HtmlEditorCore.remove = [
23457 Roo.HtmlEditorCore.ablack = [
23461 Roo.HtmlEditorCore.aclean = [
23462 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23466 Roo.HtmlEditorCore.pwhite= [
23467 'http', 'https', 'mailto'
23470 // white listed style attributes.
23471 Roo.HtmlEditorCore.cwhite= [
23472 // 'text-align', /// default is to allow most things..
23478 // black listed style attributes.
23479 Roo.HtmlEditorCore.cblack= [
23480 // 'font-size' -- this can be set by the project
23484 Roo.HtmlEditorCore.swapCodes =[
23503 * @class Roo.bootstrap.HtmlEditor
23504 * @extends Roo.bootstrap.TextArea
23505 * Bootstrap HtmlEditor class
23508 * Create a new HtmlEditor
23509 * @param {Object} config The config object
23512 Roo.bootstrap.HtmlEditor = function(config){
23513 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23514 if (!this.toolbars) {
23515 this.toolbars = [];
23518 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23521 * @event initialize
23522 * Fires when the editor is fully initialized (including the iframe)
23523 * @param {HtmlEditor} this
23528 * Fires when the editor is first receives the focus. Any insertion must wait
23529 * until after this event.
23530 * @param {HtmlEditor} this
23534 * @event beforesync
23535 * Fires before the textarea is updated with content from the editor iframe. Return false
23536 * to cancel the sync.
23537 * @param {HtmlEditor} this
23538 * @param {String} html
23542 * @event beforepush
23543 * Fires before the iframe editor is updated with content from the textarea. Return false
23544 * to cancel the push.
23545 * @param {HtmlEditor} this
23546 * @param {String} html
23551 * Fires when the textarea is updated with content from the editor iframe.
23552 * @param {HtmlEditor} this
23553 * @param {String} html
23558 * Fires when the iframe editor is updated with content from the textarea.
23559 * @param {HtmlEditor} this
23560 * @param {String} html
23564 * @event editmodechange
23565 * Fires when the editor switches edit modes
23566 * @param {HtmlEditor} this
23567 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23569 editmodechange: true,
23571 * @event editorevent
23572 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23573 * @param {HtmlEditor} this
23577 * @event firstfocus
23578 * Fires when on first focus - needed by toolbars..
23579 * @param {HtmlEditor} this
23584 * Auto save the htmlEditor value as a file into Events
23585 * @param {HtmlEditor} this
23589 * @event savedpreview
23590 * preview the saved version of htmlEditor
23591 * @param {HtmlEditor} this
23598 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23602 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23607 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23612 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23617 * @cfg {Number} height (in pixels)
23621 * @cfg {Number} width (in pixels)
23626 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23629 stylesheets: false,
23634 // private properties
23635 validationEvent : false,
23637 initialized : false,
23640 onFocus : Roo.emptyFn,
23642 hideMode:'offsets',
23644 tbContainer : false,
23648 toolbarContainer :function() {
23649 return this.wrap.select('.x-html-editor-tb',true).first();
23653 * Protected method that will not generally be called directly. It
23654 * is called when the editor creates its toolbar. Override this method if you need to
23655 * add custom toolbar buttons.
23656 * @param {HtmlEditor} editor
23658 createToolbar : function(){
23659 Roo.log('renewing');
23660 Roo.log("create toolbars");
23662 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23663 this.toolbars[0].render(this.toolbarContainer());
23667 // if (!editor.toolbars || !editor.toolbars.length) {
23668 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23671 // for (var i =0 ; i < editor.toolbars.length;i++) {
23672 // editor.toolbars[i] = Roo.factory(
23673 // typeof(editor.toolbars[i]) == 'string' ?
23674 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23675 // Roo.bootstrap.HtmlEditor);
23676 // editor.toolbars[i].init(editor);
23682 onRender : function(ct, position)
23684 // Roo.log("Call onRender: " + this.xtype);
23686 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23688 this.wrap = this.inputEl().wrap({
23689 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23692 this.editorcore.onRender(ct, position);
23694 if (this.resizable) {
23695 this.resizeEl = new Roo.Resizable(this.wrap, {
23699 minHeight : this.height,
23700 height: this.height,
23701 handles : this.resizable,
23704 resize : function(r, w, h) {
23705 _t.onResize(w,h); // -something
23711 this.createToolbar(this);
23714 if(!this.width && this.resizable){
23715 this.setSize(this.wrap.getSize());
23717 if (this.resizeEl) {
23718 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23719 // should trigger onReize..
23725 onResize : function(w, h)
23727 Roo.log('resize: ' +w + ',' + h );
23728 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23732 if(this.inputEl() ){
23733 if(typeof w == 'number'){
23734 var aw = w - this.wrap.getFrameWidth('lr');
23735 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23738 if(typeof h == 'number'){
23739 var tbh = -11; // fixme it needs to tool bar size!
23740 for (var i =0; i < this.toolbars.length;i++) {
23741 // fixme - ask toolbars for heights?
23742 tbh += this.toolbars[i].el.getHeight();
23743 //if (this.toolbars[i].footer) {
23744 // tbh += this.toolbars[i].footer.el.getHeight();
23752 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23753 ah -= 5; // knock a few pixes off for look..
23754 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23758 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23759 this.editorcore.onResize(ew,eh);
23764 * Toggles the editor between standard and source edit mode.
23765 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23767 toggleSourceEdit : function(sourceEditMode)
23769 this.editorcore.toggleSourceEdit(sourceEditMode);
23771 if(this.editorcore.sourceEditMode){
23772 Roo.log('editor - showing textarea');
23775 // Roo.log(this.syncValue());
23777 this.inputEl().removeClass(['hide', 'x-hidden']);
23778 this.inputEl().dom.removeAttribute('tabIndex');
23779 this.inputEl().focus();
23781 Roo.log('editor - hiding textarea');
23783 // Roo.log(this.pushValue());
23786 this.inputEl().addClass(['hide', 'x-hidden']);
23787 this.inputEl().dom.setAttribute('tabIndex', -1);
23788 //this.deferFocus();
23791 if(this.resizable){
23792 this.setSize(this.wrap.getSize());
23795 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23798 // private (for BoxComponent)
23799 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23801 // private (for BoxComponent)
23802 getResizeEl : function(){
23806 // private (for BoxComponent)
23807 getPositionEl : function(){
23812 initEvents : function(){
23813 this.originalValue = this.getValue();
23817 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23820 // markInvalid : Roo.emptyFn,
23822 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23825 // clearInvalid : Roo.emptyFn,
23827 setValue : function(v){
23828 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23829 this.editorcore.pushValue();
23834 deferFocus : function(){
23835 this.focus.defer(10, this);
23839 focus : function(){
23840 this.editorcore.focus();
23846 onDestroy : function(){
23852 for (var i =0; i < this.toolbars.length;i++) {
23853 // fixme - ask toolbars for heights?
23854 this.toolbars[i].onDestroy();
23857 this.wrap.dom.innerHTML = '';
23858 this.wrap.remove();
23863 onFirstFocus : function(){
23864 //Roo.log("onFirstFocus");
23865 this.editorcore.onFirstFocus();
23866 for (var i =0; i < this.toolbars.length;i++) {
23867 this.toolbars[i].onFirstFocus();
23873 syncValue : function()
23875 this.editorcore.syncValue();
23878 pushValue : function()
23880 this.editorcore.pushValue();
23884 // hide stuff that is not compatible
23898 * @event specialkey
23902 * @cfg {String} fieldClass @hide
23905 * @cfg {String} focusClass @hide
23908 * @cfg {String} autoCreate @hide
23911 * @cfg {String} inputType @hide
23914 * @cfg {String} invalidClass @hide
23917 * @cfg {String} invalidText @hide
23920 * @cfg {String} msgFx @hide
23923 * @cfg {String} validateOnBlur @hide
23932 Roo.namespace('Roo.bootstrap.htmleditor');
23934 * @class Roo.bootstrap.HtmlEditorToolbar1
23939 new Roo.bootstrap.HtmlEditor({
23942 new Roo.bootstrap.HtmlEditorToolbar1({
23943 disable : { fonts: 1 , format: 1, ..., ... , ...],
23949 * @cfg {Object} disable List of elements to disable..
23950 * @cfg {Array} btns List of additional buttons.
23954 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23957 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23960 Roo.apply(this, config);
23962 // default disabled, based on 'good practice'..
23963 this.disable = this.disable || {};
23964 Roo.applyIf(this.disable, {
23967 specialElements : true
23969 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23971 this.editor = config.editor;
23972 this.editorcore = config.editor.editorcore;
23974 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23976 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23977 // dont call parent... till later.
23979 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23984 editorcore : false,
23989 "h1","h2","h3","h4","h5","h6",
23991 "abbr", "acronym", "address", "cite", "samp", "var",
23995 onRender : function(ct, position)
23997 // Roo.log("Call onRender: " + this.xtype);
23999 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24001 this.el.dom.style.marginBottom = '0';
24003 var editorcore = this.editorcore;
24004 var editor= this.editor;
24007 var btn = function(id,cmd , toggle, handler, html){
24009 var event = toggle ? 'toggle' : 'click';
24014 xns: Roo.bootstrap,
24018 enableToggle:toggle !== false,
24020 pressed : toggle ? false : null,
24023 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24024 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24030 // var cb_box = function...
24035 xns: Roo.bootstrap,
24040 xns: Roo.bootstrap,
24044 Roo.each(this.formats, function(f) {
24045 style.menu.items.push({
24047 xns: Roo.bootstrap,
24048 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24053 editorcore.insertTag(this.tagname);
24060 children.push(style);
24062 btn('bold',false,true);
24063 btn('italic',false,true);
24064 btn('align-left', 'justifyleft',true);
24065 btn('align-center', 'justifycenter',true);
24066 btn('align-right' , 'justifyright',true);
24067 btn('link', false, false, function(btn) {
24068 //Roo.log("create link?");
24069 var url = prompt(this.createLinkText, this.defaultLinkValue);
24070 if(url && url != 'http:/'+'/'){
24071 this.editorcore.relayCmd('createlink', url);
24074 btn('list','insertunorderedlist',true);
24075 btn('pencil', false,true, function(btn){
24077 this.toggleSourceEdit(btn.pressed);
24080 if (this.editor.btns.length > 0) {
24081 for (var i = 0; i<this.editor.btns.length; i++) {
24082 children.push(this.editor.btns[i]);
24090 xns: Roo.bootstrap,
24095 xns: Roo.bootstrap,
24100 cog.menu.items.push({
24102 xns: Roo.bootstrap,
24103 html : Clean styles,
24108 editorcore.insertTag(this.tagname);
24117 this.xtype = 'NavSimplebar';
24119 for(var i=0;i< children.length;i++) {
24121 this.buttons.add(this.addxtypeChild(children[i]));
24125 editor.on('editorevent', this.updateToolbar, this);
24127 onBtnClick : function(id)
24129 this.editorcore.relayCmd(id);
24130 this.editorcore.focus();
24134 * Protected method that will not generally be called directly. It triggers
24135 * a toolbar update by reading the markup state of the current selection in the editor.
24137 updateToolbar: function(){
24139 if(!this.editorcore.activated){
24140 this.editor.onFirstFocus(); // is this neeed?
24144 var btns = this.buttons;
24145 var doc = this.editorcore.doc;
24146 btns.get('bold').setActive(doc.queryCommandState('bold'));
24147 btns.get('italic').setActive(doc.queryCommandState('italic'));
24148 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24150 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24151 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24152 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24154 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24155 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24158 var ans = this.editorcore.getAllAncestors();
24159 if (this.formatCombo) {
24162 var store = this.formatCombo.store;
24163 this.formatCombo.setValue("");
24164 for (var i =0; i < ans.length;i++) {
24165 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24167 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24175 // hides menus... - so this cant be on a menu...
24176 Roo.bootstrap.MenuMgr.hideAll();
24178 Roo.bootstrap.MenuMgr.hideAll();
24179 //this.editorsyncValue();
24181 onFirstFocus: function() {
24182 this.buttons.each(function(item){
24186 toggleSourceEdit : function(sourceEditMode){
24189 if(sourceEditMode){
24190 Roo.log("disabling buttons");
24191 this.buttons.each( function(item){
24192 if(item.cmd != 'pencil'){
24198 Roo.log("enabling buttons");
24199 if(this.editorcore.initialized){
24200 this.buttons.each( function(item){
24206 Roo.log("calling toggole on editor");
24207 // tell the editor that it's been pressed..
24208 this.editor.toggleSourceEdit(sourceEditMode);
24218 * @class Roo.bootstrap.Table.AbstractSelectionModel
24219 * @extends Roo.util.Observable
24220 * Abstract base class for grid SelectionModels. It provides the interface that should be
24221 * implemented by descendant classes. This class should not be directly instantiated.
24224 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24225 this.locked = false;
24226 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24230 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24231 /** @ignore Called by the grid automatically. Do not call directly. */
24232 init : function(grid){
24238 * Locks the selections.
24241 this.locked = true;
24245 * Unlocks the selections.
24247 unlock : function(){
24248 this.locked = false;
24252 * Returns true if the selections are locked.
24253 * @return {Boolean}
24255 isLocked : function(){
24256 return this.locked;
24260 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24261 * @class Roo.bootstrap.Table.RowSelectionModel
24262 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24263 * It supports multiple selections and keyboard selection/navigation.
24265 * @param {Object} config
24268 Roo.bootstrap.Table.RowSelectionModel = function(config){
24269 Roo.apply(this, config);
24270 this.selections = new Roo.util.MixedCollection(false, function(o){
24275 this.lastActive = false;
24279 * @event selectionchange
24280 * Fires when the selection changes
24281 * @param {SelectionModel} this
24283 "selectionchange" : true,
24285 * @event afterselectionchange
24286 * Fires after the selection changes (eg. by key press or clicking)
24287 * @param {SelectionModel} this
24289 "afterselectionchange" : true,
24291 * @event beforerowselect
24292 * Fires when a row is selected being selected, return false to cancel.
24293 * @param {SelectionModel} this
24294 * @param {Number} rowIndex The selected index
24295 * @param {Boolean} keepExisting False if other selections will be cleared
24297 "beforerowselect" : true,
24300 * Fires when a row is selected.
24301 * @param {SelectionModel} this
24302 * @param {Number} rowIndex The selected index
24303 * @param {Roo.data.Record} r The record
24305 "rowselect" : true,
24307 * @event rowdeselect
24308 * Fires when a row is deselected.
24309 * @param {SelectionModel} this
24310 * @param {Number} rowIndex The selected index
24312 "rowdeselect" : true
24314 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24315 this.locked = false;
24318 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24320 * @cfg {Boolean} singleSelect
24321 * True to allow selection of only one row at a time (defaults to false)
24323 singleSelect : false,
24326 initEvents : function()
24329 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24330 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24331 //}else{ // allow click to work like normal
24332 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24334 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24335 this.grid.on("rowclick", this.handleMouseDown, this);
24337 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24338 "up" : function(e){
24340 this.selectPrevious(e.shiftKey);
24341 }else if(this.last !== false && this.lastActive !== false){
24342 var last = this.last;
24343 this.selectRange(this.last, this.lastActive-1);
24344 this.grid.getView().focusRow(this.lastActive);
24345 if(last !== false){
24349 this.selectFirstRow();
24351 this.fireEvent("afterselectionchange", this);
24353 "down" : function(e){
24355 this.selectNext(e.shiftKey);
24356 }else if(this.last !== false && this.lastActive !== false){
24357 var last = this.last;
24358 this.selectRange(this.last, this.lastActive+1);
24359 this.grid.getView().focusRow(this.lastActive);
24360 if(last !== false){
24364 this.selectFirstRow();
24366 this.fireEvent("afterselectionchange", this);
24370 this.grid.store.on('load', function(){
24371 this.selections.clear();
24374 var view = this.grid.view;
24375 view.on("refresh", this.onRefresh, this);
24376 view.on("rowupdated", this.onRowUpdated, this);
24377 view.on("rowremoved", this.onRemove, this);
24382 onRefresh : function()
24384 var ds = this.grid.store, i, v = this.grid.view;
24385 var s = this.selections;
24386 s.each(function(r){
24387 if((i = ds.indexOfId(r.id)) != -1){
24396 onRemove : function(v, index, r){
24397 this.selections.remove(r);
24401 onRowUpdated : function(v, index, r){
24402 if(this.isSelected(r)){
24403 v.onRowSelect(index);
24409 * @param {Array} records The records to select
24410 * @param {Boolean} keepExisting (optional) True to keep existing selections
24412 selectRecords : function(records, keepExisting)
24415 this.clearSelections();
24417 var ds = this.grid.store;
24418 for(var i = 0, len = records.length; i < len; i++){
24419 this.selectRow(ds.indexOf(records[i]), true);
24424 * Gets the number of selected rows.
24427 getCount : function(){
24428 return this.selections.length;
24432 * Selects the first row in the grid.
24434 selectFirstRow : function(){
24439 * Select the last row.
24440 * @param {Boolean} keepExisting (optional) True to keep existing selections
24442 selectLastRow : function(keepExisting){
24443 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24444 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24448 * Selects the row immediately following the last selected row.
24449 * @param {Boolean} keepExisting (optional) True to keep existing selections
24451 selectNext : function(keepExisting)
24453 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24454 this.selectRow(this.last+1, keepExisting);
24455 this.grid.getView().focusRow(this.last);
24460 * Selects the row that precedes the last selected row.
24461 * @param {Boolean} keepExisting (optional) True to keep existing selections
24463 selectPrevious : function(keepExisting){
24465 this.selectRow(this.last-1, keepExisting);
24466 this.grid.getView().focusRow(this.last);
24471 * Returns the selected records
24472 * @return {Array} Array of selected records
24474 getSelections : function(){
24475 return [].concat(this.selections.items);
24479 * Returns the first selected record.
24482 getSelected : function(){
24483 return this.selections.itemAt(0);
24488 * Clears all selections.
24490 clearSelections : function(fast)
24496 var ds = this.grid.store;
24497 var s = this.selections;
24498 s.each(function(r){
24499 this.deselectRow(ds.indexOfId(r.id));
24503 this.selections.clear();
24510 * Selects all rows.
24512 selectAll : function(){
24516 this.selections.clear();
24517 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24518 this.selectRow(i, true);
24523 * Returns True if there is a selection.
24524 * @return {Boolean}
24526 hasSelection : function(){
24527 return this.selections.length > 0;
24531 * Returns True if the specified row is selected.
24532 * @param {Number/Record} record The record or index of the record to check
24533 * @return {Boolean}
24535 isSelected : function(index){
24536 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24537 return (r && this.selections.key(r.id) ? true : false);
24541 * Returns True if the specified record id is selected.
24542 * @param {String} id The id of record to check
24543 * @return {Boolean}
24545 isIdSelected : function(id){
24546 return (this.selections.key(id) ? true : false);
24551 handleMouseDBClick : function(e, t){
24555 handleMouseDown : function(e, t)
24557 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24558 if(this.isLocked() || rowIndex < 0 ){
24561 if(e.shiftKey && this.last !== false){
24562 var last = this.last;
24563 this.selectRange(last, rowIndex, e.ctrlKey);
24564 this.last = last; // reset the last
24568 var isSelected = this.isSelected(rowIndex);
24569 //Roo.log("select row:" + rowIndex);
24571 this.deselectRow(rowIndex);
24573 this.selectRow(rowIndex, true);
24577 if(e.button !== 0 && isSelected){
24578 alert('rowIndex 2: ' + rowIndex);
24579 view.focusRow(rowIndex);
24580 }else if(e.ctrlKey && isSelected){
24581 this.deselectRow(rowIndex);
24582 }else if(!isSelected){
24583 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24584 view.focusRow(rowIndex);
24588 this.fireEvent("afterselectionchange", this);
24591 handleDragableRowClick : function(grid, rowIndex, e)
24593 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24594 this.selectRow(rowIndex, false);
24595 grid.view.focusRow(rowIndex);
24596 this.fireEvent("afterselectionchange", this);
24601 * Selects multiple rows.
24602 * @param {Array} rows Array of the indexes of the row to select
24603 * @param {Boolean} keepExisting (optional) True to keep existing selections
24605 selectRows : function(rows, keepExisting){
24607 this.clearSelections();
24609 for(var i = 0, len = rows.length; i < len; i++){
24610 this.selectRow(rows[i], true);
24615 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24616 * @param {Number} startRow The index of the first row in the range
24617 * @param {Number} endRow The index of the last row in the range
24618 * @param {Boolean} keepExisting (optional) True to retain existing selections
24620 selectRange : function(startRow, endRow, keepExisting){
24625 this.clearSelections();
24627 if(startRow <= endRow){
24628 for(var i = startRow; i <= endRow; i++){
24629 this.selectRow(i, true);
24632 for(var i = startRow; i >= endRow; i--){
24633 this.selectRow(i, true);
24639 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24640 * @param {Number} startRow The index of the first row in the range
24641 * @param {Number} endRow The index of the last row in the range
24643 deselectRange : function(startRow, endRow, preventViewNotify){
24647 for(var i = startRow; i <= endRow; i++){
24648 this.deselectRow(i, preventViewNotify);
24654 * @param {Number} row The index of the row to select
24655 * @param {Boolean} keepExisting (optional) True to keep existing selections
24657 selectRow : function(index, keepExisting, preventViewNotify)
24659 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24662 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24663 if(!keepExisting || this.singleSelect){
24664 this.clearSelections();
24667 var r = this.grid.store.getAt(index);
24668 //console.log('selectRow - record id :' + r.id);
24670 this.selections.add(r);
24671 this.last = this.lastActive = index;
24672 if(!preventViewNotify){
24673 var proxy = new Roo.Element(
24674 this.grid.getRowDom(index)
24676 proxy.addClass('bg-info info');
24678 this.fireEvent("rowselect", this, index, r);
24679 this.fireEvent("selectionchange", this);
24685 * @param {Number} row The index of the row to deselect
24687 deselectRow : function(index, preventViewNotify)
24692 if(this.last == index){
24695 if(this.lastActive == index){
24696 this.lastActive = false;
24699 var r = this.grid.store.getAt(index);
24704 this.selections.remove(r);
24705 //.console.log('deselectRow - record id :' + r.id);
24706 if(!preventViewNotify){
24708 var proxy = new Roo.Element(
24709 this.grid.getRowDom(index)
24711 proxy.removeClass('bg-info info');
24713 this.fireEvent("rowdeselect", this, index);
24714 this.fireEvent("selectionchange", this);
24718 restoreLast : function(){
24720 this.last = this._last;
24725 acceptsNav : function(row, col, cm){
24726 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24730 onEditorKey : function(field, e){
24731 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24736 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24738 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24740 }else if(k == e.ENTER && !e.ctrlKey){
24744 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24746 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24748 }else if(k == e.ESC){
24752 g.startEditing(newCell[0], newCell[1]);
24758 * Ext JS Library 1.1.1
24759 * Copyright(c) 2006-2007, Ext JS, LLC.
24761 * Originally Released Under LGPL - original licence link has changed is not relivant.
24764 * <script type="text/javascript">
24768 * @class Roo.bootstrap.PagingToolbar
24769 * @extends Roo.bootstrap.NavSimplebar
24770 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24772 * Create a new PagingToolbar
24773 * @param {Object} config The config object
24774 * @param {Roo.data.Store} store
24776 Roo.bootstrap.PagingToolbar = function(config)
24778 // old args format still supported... - xtype is prefered..
24779 // created from xtype...
24781 this.ds = config.dataSource;
24783 if (config.store && !this.ds) {
24784 this.store= Roo.factory(config.store, Roo.data);
24785 this.ds = this.store;
24786 this.ds.xmodule = this.xmodule || false;
24789 this.toolbarItems = [];
24790 if (config.items) {
24791 this.toolbarItems = config.items;
24794 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24799 this.bind(this.ds);
24802 if (Roo.bootstrap.version == 4) {
24803 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24805 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24810 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24812 * @cfg {Roo.data.Store} dataSource
24813 * The underlying data store providing the paged data
24816 * @cfg {String/HTMLElement/Element} container
24817 * container The id or element that will contain the toolbar
24820 * @cfg {Boolean} displayInfo
24821 * True to display the displayMsg (defaults to false)
24824 * @cfg {Number} pageSize
24825 * The number of records to display per page (defaults to 20)
24829 * @cfg {String} displayMsg
24830 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24832 displayMsg : 'Displaying {0} - {1} of {2}',
24834 * @cfg {String} emptyMsg
24835 * The message to display when no records are found (defaults to "No data to display")
24837 emptyMsg : 'No data to display',
24839 * Customizable piece of the default paging text (defaults to "Page")
24842 beforePageText : "Page",
24844 * Customizable piece of the default paging text (defaults to "of %0")
24847 afterPageText : "of {0}",
24849 * Customizable piece of the default paging text (defaults to "First Page")
24852 firstText : "First Page",
24854 * Customizable piece of the default paging text (defaults to "Previous Page")
24857 prevText : "Previous Page",
24859 * Customizable piece of the default paging text (defaults to "Next Page")
24862 nextText : "Next Page",
24864 * Customizable piece of the default paging text (defaults to "Last Page")
24867 lastText : "Last Page",
24869 * Customizable piece of the default paging text (defaults to "Refresh")
24872 refreshText : "Refresh",
24876 onRender : function(ct, position)
24878 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24879 this.navgroup.parentId = this.id;
24880 this.navgroup.onRender(this.el, null);
24881 // add the buttons to the navgroup
24883 if(this.displayInfo){
24884 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24885 this.displayEl = this.el.select('.x-paging-info', true).first();
24886 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24887 // this.displayEl = navel.el.select('span',true).first();
24893 Roo.each(_this.buttons, function(e){ // this might need to use render????
24894 Roo.factory(e).render(_this.el);
24898 Roo.each(_this.toolbarItems, function(e) {
24899 _this.navgroup.addItem(e);
24903 this.first = this.navgroup.addItem({
24904 tooltip: this.firstText,
24905 cls: "prev btn-outline-secondary",
24906 html : ' <i class="fa fa-step-backward"></i>',
24908 preventDefault: true,
24909 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24912 this.prev = this.navgroup.addItem({
24913 tooltip: this.prevText,
24914 cls: "prev btn-outline-secondary",
24915 html : ' <i class="fa fa-backward"></i>',
24917 preventDefault: true,
24918 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24920 //this.addSeparator();
24923 var field = this.navgroup.addItem( {
24925 cls : 'x-paging-position btn-outline-secondary',
24927 html : this.beforePageText +
24928 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24929 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24932 this.field = field.el.select('input', true).first();
24933 this.field.on("keydown", this.onPagingKeydown, this);
24934 this.field.on("focus", function(){this.dom.select();});
24937 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24938 //this.field.setHeight(18);
24939 //this.addSeparator();
24940 this.next = this.navgroup.addItem({
24941 tooltip: this.nextText,
24942 cls: "next btn-outline-secondary",
24943 html : ' <i class="fa fa-forward"></i>',
24945 preventDefault: true,
24946 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24948 this.last = this.navgroup.addItem({
24949 tooltip: this.lastText,
24950 html : ' <i class="fa fa-step-forward"></i>',
24951 cls: "next btn-outline-secondary",
24953 preventDefault: true,
24954 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24956 //this.addSeparator();
24957 this.loading = this.navgroup.addItem({
24958 tooltip: this.refreshText,
24959 cls: "btn-outline-secondary",
24960 html : ' <i class="fa fa-refresh"></i>',
24961 preventDefault: true,
24962 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24968 updateInfo : function(){
24969 if(this.displayEl){
24970 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24971 var msg = count == 0 ?
24975 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24977 this.displayEl.update(msg);
24982 onLoad : function(ds, r, o)
24984 this.cursor = o.params.start ? o.params.start : 0;
24986 var d = this.getPageData(),
24991 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
24992 this.field.dom.value = ap;
24993 this.first.setDisabled(ap == 1);
24994 this.prev.setDisabled(ap == 1);
24995 this.next.setDisabled(ap == ps);
24996 this.last.setDisabled(ap == ps);
24997 this.loading.enable();
25002 getPageData : function(){
25003 var total = this.ds.getTotalCount();
25006 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25007 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25012 onLoadError : function(){
25013 this.loading.enable();
25017 onPagingKeydown : function(e){
25018 var k = e.getKey();
25019 var d = this.getPageData();
25021 var v = this.field.dom.value, pageNum;
25022 if(!v || isNaN(pageNum = parseInt(v, 10))){
25023 this.field.dom.value = d.activePage;
25026 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25027 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25030 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))
25032 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25033 this.field.dom.value = pageNum;
25034 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25037 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25039 var v = this.field.dom.value, pageNum;
25040 var increment = (e.shiftKey) ? 10 : 1;
25041 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25044 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25045 this.field.dom.value = d.activePage;
25048 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25050 this.field.dom.value = parseInt(v, 10) + increment;
25051 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25052 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25059 beforeLoad : function(){
25061 this.loading.disable();
25066 onClick : function(which){
25075 ds.load({params:{start: 0, limit: this.pageSize}});
25078 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25081 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25084 var total = ds.getTotalCount();
25085 var extra = total % this.pageSize;
25086 var lastStart = extra ? (total - extra) : total-this.pageSize;
25087 ds.load({params:{start: lastStart, limit: this.pageSize}});
25090 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25096 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25097 * @param {Roo.data.Store} store The data store to unbind
25099 unbind : function(ds){
25100 ds.un("beforeload", this.beforeLoad, this);
25101 ds.un("load", this.onLoad, this);
25102 ds.un("loadexception", this.onLoadError, this);
25103 ds.un("remove", this.updateInfo, this);
25104 ds.un("add", this.updateInfo, this);
25105 this.ds = undefined;
25109 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25110 * @param {Roo.data.Store} store The data store to bind
25112 bind : function(ds){
25113 ds.on("beforeload", this.beforeLoad, this);
25114 ds.on("load", this.onLoad, this);
25115 ds.on("loadexception", this.onLoadError, this);
25116 ds.on("remove", this.updateInfo, this);
25117 ds.on("add", this.updateInfo, this);
25128 * @class Roo.bootstrap.MessageBar
25129 * @extends Roo.bootstrap.Component
25130 * Bootstrap MessageBar class
25131 * @cfg {String} html contents of the MessageBar
25132 * @cfg {String} weight (info | success | warning | danger) default info
25133 * @cfg {String} beforeClass insert the bar before the given class
25134 * @cfg {Boolean} closable (true | false) default false
25135 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25138 * Create a new Element
25139 * @param {Object} config The config object
25142 Roo.bootstrap.MessageBar = function(config){
25143 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25146 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25152 beforeClass: 'bootstrap-sticky-wrap',
25154 getAutoCreate : function(){
25158 cls: 'alert alert-dismissable alert-' + this.weight,
25163 html: this.html || ''
25169 cfg.cls += ' alert-messages-fixed';
25183 onRender : function(ct, position)
25185 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25188 var cfg = Roo.apply({}, this.getAutoCreate());
25192 cfg.cls += ' ' + this.cls;
25195 cfg.style = this.style;
25197 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25199 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25202 this.el.select('>button.close').on('click', this.hide, this);
25208 if (!this.rendered) {
25214 this.fireEvent('show', this);
25220 if (!this.rendered) {
25226 this.fireEvent('hide', this);
25229 update : function()
25231 // var e = this.el.dom.firstChild;
25233 // if(this.closable){
25234 // e = e.nextSibling;
25237 // e.data = this.html || '';
25239 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25255 * @class Roo.bootstrap.Graph
25256 * @extends Roo.bootstrap.Component
25257 * Bootstrap Graph class
25261 @cfg {String} graphtype bar | vbar | pie
25262 @cfg {number} g_x coodinator | centre x (pie)
25263 @cfg {number} g_y coodinator | centre y (pie)
25264 @cfg {number} g_r radius (pie)
25265 @cfg {number} g_height height of the chart (respected by all elements in the set)
25266 @cfg {number} g_width width of the chart (respected by all elements in the set)
25267 @cfg {Object} title The title of the chart
25270 -opts (object) options for the chart
25272 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25273 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25275 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.
25276 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25278 o stretch (boolean)
25280 -opts (object) options for the pie
25283 o startAngle (number)
25284 o endAngle (number)
25288 * Create a new Input
25289 * @param {Object} config The config object
25292 Roo.bootstrap.Graph = function(config){
25293 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25299 * The img click event for the img.
25300 * @param {Roo.EventObject} e
25306 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25317 //g_colors: this.colors,
25324 getAutoCreate : function(){
25335 onRender : function(ct,position){
25338 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25340 if (typeof(Raphael) == 'undefined') {
25341 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25345 this.raphael = Raphael(this.el.dom);
25347 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25348 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25349 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25350 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25352 r.text(160, 10, "Single Series Chart").attr(txtattr);
25353 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25354 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25355 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25357 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25358 r.barchart(330, 10, 300, 220, data1);
25359 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25360 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25363 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25364 // r.barchart(30, 30, 560, 250, xdata, {
25365 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25366 // axis : "0 0 1 1",
25367 // axisxlabels : xdata
25368 // //yvalues : cols,
25371 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25373 // this.load(null,xdata,{
25374 // axis : "0 0 1 1",
25375 // axisxlabels : xdata
25380 load : function(graphtype,xdata,opts)
25382 this.raphael.clear();
25384 graphtype = this.graphtype;
25389 var r = this.raphael,
25390 fin = function () {
25391 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25393 fout = function () {
25394 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25396 pfin = function() {
25397 this.sector.stop();
25398 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25401 this.label[0].stop();
25402 this.label[0].attr({ r: 7.5 });
25403 this.label[1].attr({ "font-weight": 800 });
25406 pfout = function() {
25407 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25410 this.label[0].animate({ r: 5 }, 500, "bounce");
25411 this.label[1].attr({ "font-weight": 400 });
25417 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25420 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25423 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25424 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25426 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25433 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25438 setTitle: function(o)
25443 initEvents: function() {
25446 this.el.on('click', this.onClick, this);
25450 onClick : function(e)
25452 Roo.log('img onclick');
25453 this.fireEvent('click', this, e);
25465 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25468 * @class Roo.bootstrap.dash.NumberBox
25469 * @extends Roo.bootstrap.Component
25470 * Bootstrap NumberBox class
25471 * @cfg {String} headline Box headline
25472 * @cfg {String} content Box content
25473 * @cfg {String} icon Box icon
25474 * @cfg {String} footer Footer text
25475 * @cfg {String} fhref Footer href
25478 * Create a new NumberBox
25479 * @param {Object} config The config object
25483 Roo.bootstrap.dash.NumberBox = function(config){
25484 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25488 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25497 getAutoCreate : function(){
25501 cls : 'small-box ',
25509 cls : 'roo-headline',
25510 html : this.headline
25514 cls : 'roo-content',
25515 html : this.content
25529 cls : 'ion ' + this.icon
25538 cls : 'small-box-footer',
25539 href : this.fhref || '#',
25543 cfg.cn.push(footer);
25550 onRender : function(ct,position){
25551 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25558 setHeadline: function (value)
25560 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25563 setFooter: function (value, href)
25565 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25568 this.el.select('a.small-box-footer',true).first().attr('href', href);
25573 setContent: function (value)
25575 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25578 initEvents: function()
25592 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25595 * @class Roo.bootstrap.dash.TabBox
25596 * @extends Roo.bootstrap.Component
25597 * Bootstrap TabBox class
25598 * @cfg {String} title Title of the TabBox
25599 * @cfg {String} icon Icon of the TabBox
25600 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25601 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25604 * Create a new TabBox
25605 * @param {Object} config The config object
25609 Roo.bootstrap.dash.TabBox = function(config){
25610 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25615 * When a pane is added
25616 * @param {Roo.bootstrap.dash.TabPane} pane
25620 * @event activatepane
25621 * When a pane is activated
25622 * @param {Roo.bootstrap.dash.TabPane} pane
25624 "activatepane" : true
25632 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25637 tabScrollable : false,
25639 getChildContainer : function()
25641 return this.el.select('.tab-content', true).first();
25644 getAutoCreate : function(){
25648 cls: 'pull-left header',
25656 cls: 'fa ' + this.icon
25662 cls: 'nav nav-tabs pull-right',
25668 if(this.tabScrollable){
25675 cls: 'nav nav-tabs pull-right',
25686 cls: 'nav-tabs-custom',
25691 cls: 'tab-content no-padding',
25699 initEvents : function()
25701 //Roo.log('add add pane handler');
25702 this.on('addpane', this.onAddPane, this);
25705 * Updates the box title
25706 * @param {String} html to set the title to.
25708 setTitle : function(value)
25710 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25712 onAddPane : function(pane)
25714 this.panes.push(pane);
25715 //Roo.log('addpane');
25717 // tabs are rendere left to right..
25718 if(!this.showtabs){
25722 var ctr = this.el.select('.nav-tabs', true).first();
25725 var existing = ctr.select('.nav-tab',true);
25726 var qty = existing.getCount();;
25729 var tab = ctr.createChild({
25731 cls : 'nav-tab' + (qty ? '' : ' active'),
25739 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25742 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25744 pane.el.addClass('active');
25749 onTabClick : function(ev,un,ob,pane)
25751 //Roo.log('tab - prev default');
25752 ev.preventDefault();
25755 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25756 pane.tab.addClass('active');
25757 //Roo.log(pane.title);
25758 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25759 // technically we should have a deactivate event.. but maybe add later.
25760 // and it should not de-activate the selected tab...
25761 this.fireEvent('activatepane', pane);
25762 pane.el.addClass('active');
25763 pane.fireEvent('activate');
25768 getActivePane : function()
25771 Roo.each(this.panes, function(p) {
25772 if(p.el.hasClass('active')){
25793 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25795 * @class Roo.bootstrap.TabPane
25796 * @extends Roo.bootstrap.Component
25797 * Bootstrap TabPane class
25798 * @cfg {Boolean} active (false | true) Default false
25799 * @cfg {String} title title of panel
25803 * Create a new TabPane
25804 * @param {Object} config The config object
25807 Roo.bootstrap.dash.TabPane = function(config){
25808 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25814 * When a pane is activated
25815 * @param {Roo.bootstrap.dash.TabPane} pane
25822 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25827 // the tabBox that this is attached to.
25830 getAutoCreate : function()
25838 cfg.cls += ' active';
25843 initEvents : function()
25845 //Roo.log('trigger add pane handler');
25846 this.parent().fireEvent('addpane', this)
25850 * Updates the tab title
25851 * @param {String} html to set the title to.
25853 setTitle: function(str)
25859 this.tab.select('a', true).first().dom.innerHTML = str;
25876 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25879 * @class Roo.bootstrap.menu.Menu
25880 * @extends Roo.bootstrap.Component
25881 * Bootstrap Menu class - container for Menu
25882 * @cfg {String} html Text of the menu
25883 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25884 * @cfg {String} icon Font awesome icon
25885 * @cfg {String} pos Menu align to (top | bottom) default bottom
25889 * Create a new Menu
25890 * @param {Object} config The config object
25894 Roo.bootstrap.menu.Menu = function(config){
25895 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25899 * @event beforeshow
25900 * Fires before this menu is displayed
25901 * @param {Roo.bootstrap.menu.Menu} this
25905 * @event beforehide
25906 * Fires before this menu is hidden
25907 * @param {Roo.bootstrap.menu.Menu} this
25912 * Fires after this menu is displayed
25913 * @param {Roo.bootstrap.menu.Menu} this
25918 * Fires after this menu is hidden
25919 * @param {Roo.bootstrap.menu.Menu} this
25924 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25925 * @param {Roo.bootstrap.menu.Menu} this
25926 * @param {Roo.EventObject} e
25933 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25937 weight : 'default',
25942 getChildContainer : function() {
25943 if(this.isSubMenu){
25947 return this.el.select('ul.dropdown-menu', true).first();
25950 getAutoCreate : function()
25955 cls : 'roo-menu-text',
25963 cls : 'fa ' + this.icon
25974 cls : 'dropdown-button btn btn-' + this.weight,
25979 cls : 'dropdown-toggle btn btn-' + this.weight,
25989 cls : 'dropdown-menu'
25995 if(this.pos == 'top'){
25996 cfg.cls += ' dropup';
25999 if(this.isSubMenu){
26002 cls : 'dropdown-menu'
26009 onRender : function(ct, position)
26011 this.isSubMenu = ct.hasClass('dropdown-submenu');
26013 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26016 initEvents : function()
26018 if(this.isSubMenu){
26022 this.hidden = true;
26024 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26025 this.triggerEl.on('click', this.onTriggerPress, this);
26027 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26028 this.buttonEl.on('click', this.onClick, this);
26034 if(this.isSubMenu){
26038 return this.el.select('ul.dropdown-menu', true).first();
26041 onClick : function(e)
26043 this.fireEvent("click", this, e);
26046 onTriggerPress : function(e)
26048 if (this.isVisible()) {
26055 isVisible : function(){
26056 return !this.hidden;
26061 this.fireEvent("beforeshow", this);
26063 this.hidden = false;
26064 this.el.addClass('open');
26066 Roo.get(document).on("mouseup", this.onMouseUp, this);
26068 this.fireEvent("show", this);
26075 this.fireEvent("beforehide", this);
26077 this.hidden = true;
26078 this.el.removeClass('open');
26080 Roo.get(document).un("mouseup", this.onMouseUp);
26082 this.fireEvent("hide", this);
26085 onMouseUp : function()
26099 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26102 * @class Roo.bootstrap.menu.Item
26103 * @extends Roo.bootstrap.Component
26104 * Bootstrap MenuItem class
26105 * @cfg {Boolean} submenu (true | false) default false
26106 * @cfg {String} html text of the item
26107 * @cfg {String} href the link
26108 * @cfg {Boolean} disable (true | false) default false
26109 * @cfg {Boolean} preventDefault (true | false) default true
26110 * @cfg {String} icon Font awesome icon
26111 * @cfg {String} pos Submenu align to (left | right) default right
26115 * Create a new Item
26116 * @param {Object} config The config object
26120 Roo.bootstrap.menu.Item = function(config){
26121 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26125 * Fires when the mouse is hovering over this menu
26126 * @param {Roo.bootstrap.menu.Item} this
26127 * @param {Roo.EventObject} e
26132 * Fires when the mouse exits this menu
26133 * @param {Roo.bootstrap.menu.Item} this
26134 * @param {Roo.EventObject} e
26140 * The raw click event for the entire grid.
26141 * @param {Roo.EventObject} e
26147 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26152 preventDefault: true,
26157 getAutoCreate : function()
26162 cls : 'roo-menu-item-text',
26170 cls : 'fa ' + this.icon
26179 href : this.href || '#',
26186 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26190 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26192 if(this.pos == 'left'){
26193 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26200 initEvents : function()
26202 this.el.on('mouseover', this.onMouseOver, this);
26203 this.el.on('mouseout', this.onMouseOut, this);
26205 this.el.select('a', true).first().on('click', this.onClick, this);
26209 onClick : function(e)
26211 if(this.preventDefault){
26212 e.preventDefault();
26215 this.fireEvent("click", this, e);
26218 onMouseOver : function(e)
26220 if(this.submenu && this.pos == 'left'){
26221 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26224 this.fireEvent("mouseover", this, e);
26227 onMouseOut : function(e)
26229 this.fireEvent("mouseout", this, e);
26241 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26244 * @class Roo.bootstrap.menu.Separator
26245 * @extends Roo.bootstrap.Component
26246 * Bootstrap Separator class
26249 * Create a new Separator
26250 * @param {Object} config The config object
26254 Roo.bootstrap.menu.Separator = function(config){
26255 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26258 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26260 getAutoCreate : function(){
26281 * @class Roo.bootstrap.Tooltip
26282 * Bootstrap Tooltip class
26283 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26284 * to determine which dom element triggers the tooltip.
26286 * It needs to add support for additional attributes like tooltip-position
26289 * Create a new Toolti
26290 * @param {Object} config The config object
26293 Roo.bootstrap.Tooltip = function(config){
26294 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26296 this.alignment = Roo.bootstrap.Tooltip.alignment;
26298 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26299 this.alignment = config.alignment;
26304 Roo.apply(Roo.bootstrap.Tooltip, {
26306 * @function init initialize tooltip monitoring.
26310 currentTip : false,
26311 currentRegion : false,
26317 Roo.get(document).on('mouseover', this.enter ,this);
26318 Roo.get(document).on('mouseout', this.leave, this);
26321 this.currentTip = new Roo.bootstrap.Tooltip();
26324 enter : function(ev)
26326 var dom = ev.getTarget();
26328 //Roo.log(['enter',dom]);
26329 var el = Roo.fly(dom);
26330 if (this.currentEl) {
26332 //Roo.log(this.currentEl);
26333 //Roo.log(this.currentEl.contains(dom));
26334 if (this.currentEl == el) {
26337 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26343 if (this.currentTip.el) {
26344 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26348 if(!el || el.dom == document){
26354 // you can not look for children, as if el is the body.. then everythign is the child..
26355 if (!el.attr('tooltip')) { //
26356 if (!el.select("[tooltip]").elements.length) {
26359 // is the mouse over this child...?
26360 bindEl = el.select("[tooltip]").first();
26361 var xy = ev.getXY();
26362 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26363 //Roo.log("not in region.");
26366 //Roo.log("child element over..");
26369 this.currentEl = bindEl;
26370 this.currentTip.bind(bindEl);
26371 this.currentRegion = Roo.lib.Region.getRegion(dom);
26372 this.currentTip.enter();
26375 leave : function(ev)
26377 var dom = ev.getTarget();
26378 //Roo.log(['leave',dom]);
26379 if (!this.currentEl) {
26384 if (dom != this.currentEl.dom) {
26387 var xy = ev.getXY();
26388 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26391 // only activate leave if mouse cursor is outside... bounding box..
26396 if (this.currentTip) {
26397 this.currentTip.leave();
26399 //Roo.log('clear currentEl');
26400 this.currentEl = false;
26405 'left' : ['r-l', [-2,0], 'right'],
26406 'right' : ['l-r', [2,0], 'left'],
26407 'bottom' : ['t-b', [0,2], 'top'],
26408 'top' : [ 'b-t', [0,-2], 'bottom']
26414 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26419 delay : null, // can be { show : 300 , hide: 500}
26423 hoverState : null, //???
26425 placement : 'bottom',
26429 getAutoCreate : function(){
26436 cls : 'tooltip-arrow'
26439 cls : 'tooltip-inner'
26446 bind : function(el)
26452 enter : function () {
26454 if (this.timeout != null) {
26455 clearTimeout(this.timeout);
26458 this.hoverState = 'in';
26459 //Roo.log("enter - show");
26460 if (!this.delay || !this.delay.show) {
26465 this.timeout = setTimeout(function () {
26466 if (_t.hoverState == 'in') {
26469 }, this.delay.show);
26473 clearTimeout(this.timeout);
26475 this.hoverState = 'out';
26476 if (!this.delay || !this.delay.hide) {
26482 this.timeout = setTimeout(function () {
26483 //Roo.log("leave - timeout");
26485 if (_t.hoverState == 'out') {
26487 Roo.bootstrap.Tooltip.currentEl = false;
26492 show : function (msg)
26495 this.render(document.body);
26498 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26500 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26502 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26504 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26506 var placement = typeof this.placement == 'function' ?
26507 this.placement.call(this, this.el, on_el) :
26510 var autoToken = /\s?auto?\s?/i;
26511 var autoPlace = autoToken.test(placement);
26513 placement = placement.replace(autoToken, '') || 'top';
26517 //this.el.setXY([0,0]);
26519 //this.el.dom.style.display='block';
26521 //this.el.appendTo(on_el);
26523 var p = this.getPosition();
26524 var box = this.el.getBox();
26530 var align = this.alignment[placement];
26532 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26534 if(placement == 'top' || placement == 'bottom'){
26536 placement = 'right';
26539 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26540 placement = 'left';
26543 var scroll = Roo.select('body', true).first().getScroll();
26545 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26549 align = this.alignment[placement];
26552 this.el.alignTo(this.bindEl, align[0],align[1]);
26553 //var arrow = this.el.select('.arrow',true).first();
26554 //arrow.set(align[2],
26556 this.el.addClass(placement);
26558 this.el.addClass('in fade');
26560 this.hoverState = null;
26562 if (this.el.hasClass('fade')) {
26573 //this.el.setXY([0,0]);
26574 this.el.removeClass('in');
26590 * @class Roo.bootstrap.LocationPicker
26591 * @extends Roo.bootstrap.Component
26592 * Bootstrap LocationPicker class
26593 * @cfg {Number} latitude Position when init default 0
26594 * @cfg {Number} longitude Position when init default 0
26595 * @cfg {Number} zoom default 15
26596 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26597 * @cfg {Boolean} mapTypeControl default false
26598 * @cfg {Boolean} disableDoubleClickZoom default false
26599 * @cfg {Boolean} scrollwheel default true
26600 * @cfg {Boolean} streetViewControl default false
26601 * @cfg {Number} radius default 0
26602 * @cfg {String} locationName
26603 * @cfg {Boolean} draggable default true
26604 * @cfg {Boolean} enableAutocomplete default false
26605 * @cfg {Boolean} enableReverseGeocode default true
26606 * @cfg {String} markerTitle
26609 * Create a new LocationPicker
26610 * @param {Object} config The config object
26614 Roo.bootstrap.LocationPicker = function(config){
26616 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26621 * Fires when the picker initialized.
26622 * @param {Roo.bootstrap.LocationPicker} this
26623 * @param {Google Location} location
26627 * @event positionchanged
26628 * Fires when the picker position changed.
26629 * @param {Roo.bootstrap.LocationPicker} this
26630 * @param {Google Location} location
26632 positionchanged : true,
26635 * Fires when the map resize.
26636 * @param {Roo.bootstrap.LocationPicker} this
26641 * Fires when the map show.
26642 * @param {Roo.bootstrap.LocationPicker} this
26647 * Fires when the map hide.
26648 * @param {Roo.bootstrap.LocationPicker} this
26653 * Fires when click the map.
26654 * @param {Roo.bootstrap.LocationPicker} this
26655 * @param {Map event} e
26659 * @event mapRightClick
26660 * Fires when right click the map.
26661 * @param {Roo.bootstrap.LocationPicker} this
26662 * @param {Map event} e
26664 mapRightClick : true,
26666 * @event markerClick
26667 * Fires when click the marker.
26668 * @param {Roo.bootstrap.LocationPicker} this
26669 * @param {Map event} e
26671 markerClick : true,
26673 * @event markerRightClick
26674 * Fires when right click the marker.
26675 * @param {Roo.bootstrap.LocationPicker} this
26676 * @param {Map event} e
26678 markerRightClick : true,
26680 * @event OverlayViewDraw
26681 * Fires when OverlayView Draw
26682 * @param {Roo.bootstrap.LocationPicker} this
26684 OverlayViewDraw : true,
26686 * @event OverlayViewOnAdd
26687 * Fires when OverlayView Draw
26688 * @param {Roo.bootstrap.LocationPicker} this
26690 OverlayViewOnAdd : true,
26692 * @event OverlayViewOnRemove
26693 * Fires when OverlayView Draw
26694 * @param {Roo.bootstrap.LocationPicker} this
26696 OverlayViewOnRemove : true,
26698 * @event OverlayViewShow
26699 * Fires when OverlayView Draw
26700 * @param {Roo.bootstrap.LocationPicker} this
26701 * @param {Pixel} cpx
26703 OverlayViewShow : true,
26705 * @event OverlayViewHide
26706 * Fires when OverlayView Draw
26707 * @param {Roo.bootstrap.LocationPicker} this
26709 OverlayViewHide : true,
26711 * @event loadexception
26712 * Fires when load google lib failed.
26713 * @param {Roo.bootstrap.LocationPicker} this
26715 loadexception : true
26720 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26722 gMapContext: false,
26728 mapTypeControl: false,
26729 disableDoubleClickZoom: false,
26731 streetViewControl: false,
26735 enableAutocomplete: false,
26736 enableReverseGeocode: true,
26739 getAutoCreate: function()
26744 cls: 'roo-location-picker'
26750 initEvents: function(ct, position)
26752 if(!this.el.getWidth() || this.isApplied()){
26756 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26761 initial: function()
26763 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26764 this.fireEvent('loadexception', this);
26768 if(!this.mapTypeId){
26769 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26772 this.gMapContext = this.GMapContext();
26774 this.initOverlayView();
26776 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26780 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26781 _this.setPosition(_this.gMapContext.marker.position);
26784 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26785 _this.fireEvent('mapClick', this, event);
26789 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26790 _this.fireEvent('mapRightClick', this, event);
26794 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26795 _this.fireEvent('markerClick', this, event);
26799 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26800 _this.fireEvent('markerRightClick', this, event);
26804 this.setPosition(this.gMapContext.location);
26806 this.fireEvent('initial', this, this.gMapContext.location);
26809 initOverlayView: function()
26813 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26817 _this.fireEvent('OverlayViewDraw', _this);
26822 _this.fireEvent('OverlayViewOnAdd', _this);
26825 onRemove: function()
26827 _this.fireEvent('OverlayViewOnRemove', _this);
26830 show: function(cpx)
26832 _this.fireEvent('OverlayViewShow', _this, cpx);
26837 _this.fireEvent('OverlayViewHide', _this);
26843 fromLatLngToContainerPixel: function(event)
26845 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26848 isApplied: function()
26850 return this.getGmapContext() == false ? false : true;
26853 getGmapContext: function()
26855 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26858 GMapContext: function()
26860 var position = new google.maps.LatLng(this.latitude, this.longitude);
26862 var _map = new google.maps.Map(this.el.dom, {
26865 mapTypeId: this.mapTypeId,
26866 mapTypeControl: this.mapTypeControl,
26867 disableDoubleClickZoom: this.disableDoubleClickZoom,
26868 scrollwheel: this.scrollwheel,
26869 streetViewControl: this.streetViewControl,
26870 locationName: this.locationName,
26871 draggable: this.draggable,
26872 enableAutocomplete: this.enableAutocomplete,
26873 enableReverseGeocode: this.enableReverseGeocode
26876 var _marker = new google.maps.Marker({
26877 position: position,
26879 title: this.markerTitle,
26880 draggable: this.draggable
26887 location: position,
26888 radius: this.radius,
26889 locationName: this.locationName,
26890 addressComponents: {
26891 formatted_address: null,
26892 addressLine1: null,
26893 addressLine2: null,
26895 streetNumber: null,
26899 stateOrProvince: null
26902 domContainer: this.el.dom,
26903 geodecoder: new google.maps.Geocoder()
26907 drawCircle: function(center, radius, options)
26909 if (this.gMapContext.circle != null) {
26910 this.gMapContext.circle.setMap(null);
26914 options = Roo.apply({}, options, {
26915 strokeColor: "#0000FF",
26916 strokeOpacity: .35,
26918 fillColor: "#0000FF",
26922 options.map = this.gMapContext.map;
26923 options.radius = radius;
26924 options.center = center;
26925 this.gMapContext.circle = new google.maps.Circle(options);
26926 return this.gMapContext.circle;
26932 setPosition: function(location)
26934 this.gMapContext.location = location;
26935 this.gMapContext.marker.setPosition(location);
26936 this.gMapContext.map.panTo(location);
26937 this.drawCircle(location, this.gMapContext.radius, {});
26941 if (this.gMapContext.settings.enableReverseGeocode) {
26942 this.gMapContext.geodecoder.geocode({
26943 latLng: this.gMapContext.location
26944 }, function(results, status) {
26946 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26947 _this.gMapContext.locationName = results[0].formatted_address;
26948 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26950 _this.fireEvent('positionchanged', this, location);
26957 this.fireEvent('positionchanged', this, location);
26962 google.maps.event.trigger(this.gMapContext.map, "resize");
26964 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26966 this.fireEvent('resize', this);
26969 setPositionByLatLng: function(latitude, longitude)
26971 this.setPosition(new google.maps.LatLng(latitude, longitude));
26974 getCurrentPosition: function()
26977 latitude: this.gMapContext.location.lat(),
26978 longitude: this.gMapContext.location.lng()
26982 getAddressName: function()
26984 return this.gMapContext.locationName;
26987 getAddressComponents: function()
26989 return this.gMapContext.addressComponents;
26992 address_component_from_google_geocode: function(address_components)
26996 for (var i = 0; i < address_components.length; i++) {
26997 var component = address_components[i];
26998 if (component.types.indexOf("postal_code") >= 0) {
26999 result.postalCode = component.short_name;
27000 } else if (component.types.indexOf("street_number") >= 0) {
27001 result.streetNumber = component.short_name;
27002 } else if (component.types.indexOf("route") >= 0) {
27003 result.streetName = component.short_name;
27004 } else if (component.types.indexOf("neighborhood") >= 0) {
27005 result.city = component.short_name;
27006 } else if (component.types.indexOf("locality") >= 0) {
27007 result.city = component.short_name;
27008 } else if (component.types.indexOf("sublocality") >= 0) {
27009 result.district = component.short_name;
27010 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27011 result.stateOrProvince = component.short_name;
27012 } else if (component.types.indexOf("country") >= 0) {
27013 result.country = component.short_name;
27017 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27018 result.addressLine2 = "";
27022 setZoomLevel: function(zoom)
27024 this.gMapContext.map.setZoom(zoom);
27037 this.fireEvent('show', this);
27048 this.fireEvent('hide', this);
27053 Roo.apply(Roo.bootstrap.LocationPicker, {
27055 OverlayView : function(map, options)
27057 options = options || {};
27071 * @class Roo.bootstrap.Alert
27072 * @extends Roo.bootstrap.Component
27073 * Bootstrap Alert class
27074 * @cfg {String} title The title of alert
27075 * @cfg {String} html The content of alert
27076 * @cfg {String} weight ( success | info | warning | danger )
27077 * @cfg {String} faicon font-awesomeicon
27080 * Create a new alert
27081 * @param {Object} config The config object
27085 Roo.bootstrap.Alert = function(config){
27086 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27090 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27097 getAutoCreate : function()
27106 cls : 'roo-alert-icon'
27111 cls : 'roo-alert-title',
27116 cls : 'roo-alert-text',
27123 cfg.cn[0].cls += ' fa ' + this.faicon;
27127 cfg.cls += ' alert-' + this.weight;
27133 initEvents: function()
27135 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27138 setTitle : function(str)
27140 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27143 setText : function(str)
27145 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27148 setWeight : function(weight)
27151 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27154 this.weight = weight;
27156 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27159 setIcon : function(icon)
27162 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27165 this.faicon = icon;
27167 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27188 * @class Roo.bootstrap.UploadCropbox
27189 * @extends Roo.bootstrap.Component
27190 * Bootstrap UploadCropbox class
27191 * @cfg {String} emptyText show when image has been loaded
27192 * @cfg {String} rotateNotify show when image too small to rotate
27193 * @cfg {Number} errorTimeout default 3000
27194 * @cfg {Number} minWidth default 300
27195 * @cfg {Number} minHeight default 300
27196 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27197 * @cfg {Boolean} isDocument (true|false) default false
27198 * @cfg {String} url action url
27199 * @cfg {String} paramName default 'imageUpload'
27200 * @cfg {String} method default POST
27201 * @cfg {Boolean} loadMask (true|false) default true
27202 * @cfg {Boolean} loadingText default 'Loading...'
27205 * Create a new UploadCropbox
27206 * @param {Object} config The config object
27209 Roo.bootstrap.UploadCropbox = function(config){
27210 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27214 * @event beforeselectfile
27215 * Fire before select file
27216 * @param {Roo.bootstrap.UploadCropbox} this
27218 "beforeselectfile" : true,
27221 * Fire after initEvent
27222 * @param {Roo.bootstrap.UploadCropbox} this
27227 * Fire after initEvent
27228 * @param {Roo.bootstrap.UploadCropbox} this
27229 * @param {String} data
27234 * Fire when preparing the file data
27235 * @param {Roo.bootstrap.UploadCropbox} this
27236 * @param {Object} file
27241 * Fire when get exception
27242 * @param {Roo.bootstrap.UploadCropbox} this
27243 * @param {XMLHttpRequest} xhr
27245 "exception" : true,
27247 * @event beforeloadcanvas
27248 * Fire before load the canvas
27249 * @param {Roo.bootstrap.UploadCropbox} this
27250 * @param {String} src
27252 "beforeloadcanvas" : true,
27255 * Fire when trash image
27256 * @param {Roo.bootstrap.UploadCropbox} this
27261 * Fire when download the image
27262 * @param {Roo.bootstrap.UploadCropbox} this
27266 * @event footerbuttonclick
27267 * Fire when footerbuttonclick
27268 * @param {Roo.bootstrap.UploadCropbox} this
27269 * @param {String} type
27271 "footerbuttonclick" : true,
27275 * @param {Roo.bootstrap.UploadCropbox} this
27280 * Fire when rotate the image
27281 * @param {Roo.bootstrap.UploadCropbox} this
27282 * @param {String} pos
27287 * Fire when inspect the file
27288 * @param {Roo.bootstrap.UploadCropbox} this
27289 * @param {Object} file
27294 * Fire when xhr upload the file
27295 * @param {Roo.bootstrap.UploadCropbox} this
27296 * @param {Object} data
27301 * Fire when arrange the file data
27302 * @param {Roo.bootstrap.UploadCropbox} this
27303 * @param {Object} formData
27308 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27311 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27313 emptyText : 'Click to upload image',
27314 rotateNotify : 'Image is too small to rotate',
27315 errorTimeout : 3000,
27329 cropType : 'image/jpeg',
27331 canvasLoaded : false,
27332 isDocument : false,
27334 paramName : 'imageUpload',
27336 loadingText : 'Loading...',
27339 getAutoCreate : function()
27343 cls : 'roo-upload-cropbox',
27347 cls : 'roo-upload-cropbox-selector',
27352 cls : 'roo-upload-cropbox-body',
27353 style : 'cursor:pointer',
27357 cls : 'roo-upload-cropbox-preview'
27361 cls : 'roo-upload-cropbox-thumb'
27365 cls : 'roo-upload-cropbox-empty-notify',
27366 html : this.emptyText
27370 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27371 html : this.rotateNotify
27377 cls : 'roo-upload-cropbox-footer',
27380 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27390 onRender : function(ct, position)
27392 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27394 if (this.buttons.length) {
27396 Roo.each(this.buttons, function(bb) {
27398 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27400 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27406 this.maskEl = this.el;
27410 initEvents : function()
27412 this.urlAPI = (window.createObjectURL && window) ||
27413 (window.URL && URL.revokeObjectURL && URL) ||
27414 (window.webkitURL && webkitURL);
27416 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27417 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27419 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27420 this.selectorEl.hide();
27422 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27423 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27425 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27426 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27427 this.thumbEl.hide();
27429 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27430 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27432 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27433 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27434 this.errorEl.hide();
27436 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27437 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27438 this.footerEl.hide();
27440 this.setThumbBoxSize();
27446 this.fireEvent('initial', this);
27453 window.addEventListener("resize", function() { _this.resize(); } );
27455 this.bodyEl.on('click', this.beforeSelectFile, this);
27458 this.bodyEl.on('touchstart', this.onTouchStart, this);
27459 this.bodyEl.on('touchmove', this.onTouchMove, this);
27460 this.bodyEl.on('touchend', this.onTouchEnd, this);
27464 this.bodyEl.on('mousedown', this.onMouseDown, this);
27465 this.bodyEl.on('mousemove', this.onMouseMove, this);
27466 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27467 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27468 Roo.get(document).on('mouseup', this.onMouseUp, this);
27471 this.selectorEl.on('change', this.onFileSelected, this);
27477 this.baseScale = 1;
27479 this.baseRotate = 1;
27480 this.dragable = false;
27481 this.pinching = false;
27484 this.cropData = false;
27485 this.notifyEl.dom.innerHTML = this.emptyText;
27487 this.selectorEl.dom.value = '';
27491 resize : function()
27493 if(this.fireEvent('resize', this) != false){
27494 this.setThumbBoxPosition();
27495 this.setCanvasPosition();
27499 onFooterButtonClick : function(e, el, o, type)
27502 case 'rotate-left' :
27503 this.onRotateLeft(e);
27505 case 'rotate-right' :
27506 this.onRotateRight(e);
27509 this.beforeSelectFile(e);
27524 this.fireEvent('footerbuttonclick', this, type);
27527 beforeSelectFile : function(e)
27529 e.preventDefault();
27531 if(this.fireEvent('beforeselectfile', this) != false){
27532 this.selectorEl.dom.click();
27536 onFileSelected : function(e)
27538 e.preventDefault();
27540 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27544 var file = this.selectorEl.dom.files[0];
27546 if(this.fireEvent('inspect', this, file) != false){
27547 this.prepare(file);
27552 trash : function(e)
27554 this.fireEvent('trash', this);
27557 download : function(e)
27559 this.fireEvent('download', this);
27562 loadCanvas : function(src)
27564 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27568 this.imageEl = document.createElement('img');
27572 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27574 this.imageEl.src = src;
27578 onLoadCanvas : function()
27580 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27581 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27583 this.bodyEl.un('click', this.beforeSelectFile, this);
27585 this.notifyEl.hide();
27586 this.thumbEl.show();
27587 this.footerEl.show();
27589 this.baseRotateLevel();
27591 if(this.isDocument){
27592 this.setThumbBoxSize();
27595 this.setThumbBoxPosition();
27597 this.baseScaleLevel();
27603 this.canvasLoaded = true;
27606 this.maskEl.unmask();
27611 setCanvasPosition : function()
27613 if(!this.canvasEl){
27617 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27618 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27620 this.previewEl.setLeft(pw);
27621 this.previewEl.setTop(ph);
27625 onMouseDown : function(e)
27629 this.dragable = true;
27630 this.pinching = false;
27632 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27633 this.dragable = false;
27637 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27638 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27642 onMouseMove : function(e)
27646 if(!this.canvasLoaded){
27650 if (!this.dragable){
27654 var minX = Math.ceil(this.thumbEl.getLeft(true));
27655 var minY = Math.ceil(this.thumbEl.getTop(true));
27657 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27658 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27660 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27661 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27663 x = x - this.mouseX;
27664 y = y - this.mouseY;
27666 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27667 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27669 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27670 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27672 this.previewEl.setLeft(bgX);
27673 this.previewEl.setTop(bgY);
27675 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27676 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27679 onMouseUp : function(e)
27683 this.dragable = false;
27686 onMouseWheel : function(e)
27690 this.startScale = this.scale;
27692 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27694 if(!this.zoomable()){
27695 this.scale = this.startScale;
27704 zoomable : function()
27706 var minScale = this.thumbEl.getWidth() / this.minWidth;
27708 if(this.minWidth < this.minHeight){
27709 minScale = this.thumbEl.getHeight() / this.minHeight;
27712 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27713 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27717 (this.rotate == 0 || this.rotate == 180) &&
27719 width > this.imageEl.OriginWidth ||
27720 height > this.imageEl.OriginHeight ||
27721 (width < this.minWidth && height < this.minHeight)
27729 (this.rotate == 90 || this.rotate == 270) &&
27731 width > this.imageEl.OriginWidth ||
27732 height > this.imageEl.OriginHeight ||
27733 (width < this.minHeight && height < this.minWidth)
27740 !this.isDocument &&
27741 (this.rotate == 0 || this.rotate == 180) &&
27743 width < this.minWidth ||
27744 width > this.imageEl.OriginWidth ||
27745 height < this.minHeight ||
27746 height > this.imageEl.OriginHeight
27753 !this.isDocument &&
27754 (this.rotate == 90 || this.rotate == 270) &&
27756 width < this.minHeight ||
27757 width > this.imageEl.OriginWidth ||
27758 height < this.minWidth ||
27759 height > this.imageEl.OriginHeight
27769 onRotateLeft : function(e)
27771 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27773 var minScale = this.thumbEl.getWidth() / this.minWidth;
27775 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27776 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27778 this.startScale = this.scale;
27780 while (this.getScaleLevel() < minScale){
27782 this.scale = this.scale + 1;
27784 if(!this.zoomable()){
27789 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27790 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27795 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27802 this.scale = this.startScale;
27804 this.onRotateFail();
27809 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27811 if(this.isDocument){
27812 this.setThumbBoxSize();
27813 this.setThumbBoxPosition();
27814 this.setCanvasPosition();
27819 this.fireEvent('rotate', this, 'left');
27823 onRotateRight : function(e)
27825 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27827 var minScale = this.thumbEl.getWidth() / this.minWidth;
27829 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27830 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27832 this.startScale = this.scale;
27834 while (this.getScaleLevel() < minScale){
27836 this.scale = this.scale + 1;
27838 if(!this.zoomable()){
27843 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27844 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27849 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27856 this.scale = this.startScale;
27858 this.onRotateFail();
27863 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27865 if(this.isDocument){
27866 this.setThumbBoxSize();
27867 this.setThumbBoxPosition();
27868 this.setCanvasPosition();
27873 this.fireEvent('rotate', this, 'right');
27876 onRotateFail : function()
27878 this.errorEl.show(true);
27882 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27887 this.previewEl.dom.innerHTML = '';
27889 var canvasEl = document.createElement("canvas");
27891 var contextEl = canvasEl.getContext("2d");
27893 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27894 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27895 var center = this.imageEl.OriginWidth / 2;
27897 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27898 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27899 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27900 center = this.imageEl.OriginHeight / 2;
27903 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27905 contextEl.translate(center, center);
27906 contextEl.rotate(this.rotate * Math.PI / 180);
27908 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27910 this.canvasEl = document.createElement("canvas");
27912 this.contextEl = this.canvasEl.getContext("2d");
27914 switch (this.rotate) {
27917 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27918 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27920 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27925 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27926 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27928 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27929 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);
27933 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27938 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27939 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27941 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27942 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);
27946 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);
27951 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27952 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27954 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27955 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27959 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);
27966 this.previewEl.appendChild(this.canvasEl);
27968 this.setCanvasPosition();
27973 if(!this.canvasLoaded){
27977 var imageCanvas = document.createElement("canvas");
27979 var imageContext = imageCanvas.getContext("2d");
27981 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27982 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27984 var center = imageCanvas.width / 2;
27986 imageContext.translate(center, center);
27988 imageContext.rotate(this.rotate * Math.PI / 180);
27990 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27992 var canvas = document.createElement("canvas");
27994 var context = canvas.getContext("2d");
27996 canvas.width = this.minWidth;
27997 canvas.height = this.minHeight;
27999 switch (this.rotate) {
28002 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28003 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28005 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28006 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28008 var targetWidth = this.minWidth - 2 * x;
28009 var targetHeight = this.minHeight - 2 * y;
28013 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28014 scale = targetWidth / width;
28017 if(x > 0 && y == 0){
28018 scale = targetHeight / height;
28021 if(x > 0 && y > 0){
28022 scale = targetWidth / width;
28024 if(width < height){
28025 scale = targetHeight / height;
28029 context.scale(scale, scale);
28031 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28032 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28034 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28035 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28037 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28042 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28043 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28045 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28046 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28048 var targetWidth = this.minWidth - 2 * x;
28049 var targetHeight = this.minHeight - 2 * y;
28053 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28054 scale = targetWidth / width;
28057 if(x > 0 && y == 0){
28058 scale = targetHeight / height;
28061 if(x > 0 && y > 0){
28062 scale = targetWidth / width;
28064 if(width < height){
28065 scale = targetHeight / height;
28069 context.scale(scale, scale);
28071 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28072 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28074 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28075 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28077 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28079 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28084 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28085 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28087 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28088 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28090 var targetWidth = this.minWidth - 2 * x;
28091 var targetHeight = this.minHeight - 2 * y;
28095 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28096 scale = targetWidth / width;
28099 if(x > 0 && y == 0){
28100 scale = targetHeight / height;
28103 if(x > 0 && y > 0){
28104 scale = targetWidth / width;
28106 if(width < height){
28107 scale = targetHeight / height;
28111 context.scale(scale, scale);
28113 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28114 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28116 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28117 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28119 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28120 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28122 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28127 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28128 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28130 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28131 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28133 var targetWidth = this.minWidth - 2 * x;
28134 var targetHeight = this.minHeight - 2 * y;
28138 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28139 scale = targetWidth / width;
28142 if(x > 0 && y == 0){
28143 scale = targetHeight / height;
28146 if(x > 0 && y > 0){
28147 scale = targetWidth / width;
28149 if(width < height){
28150 scale = targetHeight / height;
28154 context.scale(scale, scale);
28156 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28157 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28159 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28160 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28162 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28164 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28171 this.cropData = canvas.toDataURL(this.cropType);
28173 if(this.fireEvent('crop', this, this.cropData) !== false){
28174 this.process(this.file, this.cropData);
28181 setThumbBoxSize : function()
28185 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28186 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28187 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28189 this.minWidth = width;
28190 this.minHeight = height;
28192 if(this.rotate == 90 || this.rotate == 270){
28193 this.minWidth = height;
28194 this.minHeight = width;
28199 width = Math.ceil(this.minWidth * height / this.minHeight);
28201 if(this.minWidth > this.minHeight){
28203 height = Math.ceil(this.minHeight * width / this.minWidth);
28206 this.thumbEl.setStyle({
28207 width : width + 'px',
28208 height : height + 'px'
28215 setThumbBoxPosition : function()
28217 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28218 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28220 this.thumbEl.setLeft(x);
28221 this.thumbEl.setTop(y);
28225 baseRotateLevel : function()
28227 this.baseRotate = 1;
28230 typeof(this.exif) != 'undefined' &&
28231 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28232 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28234 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28237 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28241 baseScaleLevel : function()
28245 if(this.isDocument){
28247 if(this.baseRotate == 6 || this.baseRotate == 8){
28249 height = this.thumbEl.getHeight();
28250 this.baseScale = height / this.imageEl.OriginWidth;
28252 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28253 width = this.thumbEl.getWidth();
28254 this.baseScale = width / this.imageEl.OriginHeight;
28260 height = this.thumbEl.getHeight();
28261 this.baseScale = height / this.imageEl.OriginHeight;
28263 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28264 width = this.thumbEl.getWidth();
28265 this.baseScale = width / this.imageEl.OriginWidth;
28271 if(this.baseRotate == 6 || this.baseRotate == 8){
28273 width = this.thumbEl.getHeight();
28274 this.baseScale = width / this.imageEl.OriginHeight;
28276 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28277 height = this.thumbEl.getWidth();
28278 this.baseScale = height / this.imageEl.OriginHeight;
28281 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28282 height = this.thumbEl.getWidth();
28283 this.baseScale = height / this.imageEl.OriginHeight;
28285 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28286 width = this.thumbEl.getHeight();
28287 this.baseScale = width / this.imageEl.OriginWidth;
28294 width = this.thumbEl.getWidth();
28295 this.baseScale = width / this.imageEl.OriginWidth;
28297 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28298 height = this.thumbEl.getHeight();
28299 this.baseScale = height / this.imageEl.OriginHeight;
28302 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28304 height = this.thumbEl.getHeight();
28305 this.baseScale = height / this.imageEl.OriginHeight;
28307 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28308 width = this.thumbEl.getWidth();
28309 this.baseScale = width / this.imageEl.OriginWidth;
28317 getScaleLevel : function()
28319 return this.baseScale * Math.pow(1.1, this.scale);
28322 onTouchStart : function(e)
28324 if(!this.canvasLoaded){
28325 this.beforeSelectFile(e);
28329 var touches = e.browserEvent.touches;
28335 if(touches.length == 1){
28336 this.onMouseDown(e);
28340 if(touches.length != 2){
28346 for(var i = 0, finger; finger = touches[i]; i++){
28347 coords.push(finger.pageX, finger.pageY);
28350 var x = Math.pow(coords[0] - coords[2], 2);
28351 var y = Math.pow(coords[1] - coords[3], 2);
28353 this.startDistance = Math.sqrt(x + y);
28355 this.startScale = this.scale;
28357 this.pinching = true;
28358 this.dragable = false;
28362 onTouchMove : function(e)
28364 if(!this.pinching && !this.dragable){
28368 var touches = e.browserEvent.touches;
28375 this.onMouseMove(e);
28381 for(var i = 0, finger; finger = touches[i]; i++){
28382 coords.push(finger.pageX, finger.pageY);
28385 var x = Math.pow(coords[0] - coords[2], 2);
28386 var y = Math.pow(coords[1] - coords[3], 2);
28388 this.endDistance = Math.sqrt(x + y);
28390 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28392 if(!this.zoomable()){
28393 this.scale = this.startScale;
28401 onTouchEnd : function(e)
28403 this.pinching = false;
28404 this.dragable = false;
28408 process : function(file, crop)
28411 this.maskEl.mask(this.loadingText);
28414 this.xhr = new XMLHttpRequest();
28416 file.xhr = this.xhr;
28418 this.xhr.open(this.method, this.url, true);
28421 "Accept": "application/json",
28422 "Cache-Control": "no-cache",
28423 "X-Requested-With": "XMLHttpRequest"
28426 for (var headerName in headers) {
28427 var headerValue = headers[headerName];
28429 this.xhr.setRequestHeader(headerName, headerValue);
28435 this.xhr.onload = function()
28437 _this.xhrOnLoad(_this.xhr);
28440 this.xhr.onerror = function()
28442 _this.xhrOnError(_this.xhr);
28445 var formData = new FormData();
28447 formData.append('returnHTML', 'NO');
28450 formData.append('crop', crop);
28453 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28454 formData.append(this.paramName, file, file.name);
28457 if(typeof(file.filename) != 'undefined'){
28458 formData.append('filename', file.filename);
28461 if(typeof(file.mimetype) != 'undefined'){
28462 formData.append('mimetype', file.mimetype);
28465 if(this.fireEvent('arrange', this, formData) != false){
28466 this.xhr.send(formData);
28470 xhrOnLoad : function(xhr)
28473 this.maskEl.unmask();
28476 if (xhr.readyState !== 4) {
28477 this.fireEvent('exception', this, xhr);
28481 var response = Roo.decode(xhr.responseText);
28483 if(!response.success){
28484 this.fireEvent('exception', this, xhr);
28488 var response = Roo.decode(xhr.responseText);
28490 this.fireEvent('upload', this, response);
28494 xhrOnError : function()
28497 this.maskEl.unmask();
28500 Roo.log('xhr on error');
28502 var response = Roo.decode(xhr.responseText);
28508 prepare : function(file)
28511 this.maskEl.mask(this.loadingText);
28517 if(typeof(file) === 'string'){
28518 this.loadCanvas(file);
28522 if(!file || !this.urlAPI){
28527 this.cropType = file.type;
28531 if(this.fireEvent('prepare', this, this.file) != false){
28533 var reader = new FileReader();
28535 reader.onload = function (e) {
28536 if (e.target.error) {
28537 Roo.log(e.target.error);
28541 var buffer = e.target.result,
28542 dataView = new DataView(buffer),
28544 maxOffset = dataView.byteLength - 4,
28548 if (dataView.getUint16(0) === 0xffd8) {
28549 while (offset < maxOffset) {
28550 markerBytes = dataView.getUint16(offset);
28552 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28553 markerLength = dataView.getUint16(offset + 2) + 2;
28554 if (offset + markerLength > dataView.byteLength) {
28555 Roo.log('Invalid meta data: Invalid segment size.');
28559 if(markerBytes == 0xffe1){
28560 _this.parseExifData(
28567 offset += markerLength;
28577 var url = _this.urlAPI.createObjectURL(_this.file);
28579 _this.loadCanvas(url);
28584 reader.readAsArrayBuffer(this.file);
28590 parseExifData : function(dataView, offset, length)
28592 var tiffOffset = offset + 10,
28596 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28597 // No Exif data, might be XMP data instead
28601 // Check for the ASCII code for "Exif" (0x45786966):
28602 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28603 // No Exif data, might be XMP data instead
28606 if (tiffOffset + 8 > dataView.byteLength) {
28607 Roo.log('Invalid Exif data: Invalid segment size.');
28610 // Check for the two null bytes:
28611 if (dataView.getUint16(offset + 8) !== 0x0000) {
28612 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28615 // Check the byte alignment:
28616 switch (dataView.getUint16(tiffOffset)) {
28618 littleEndian = true;
28621 littleEndian = false;
28624 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28627 // Check for the TIFF tag marker (0x002A):
28628 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28629 Roo.log('Invalid Exif data: Missing TIFF marker.');
28632 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28633 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28635 this.parseExifTags(
28638 tiffOffset + dirOffset,
28643 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28648 if (dirOffset + 6 > dataView.byteLength) {
28649 Roo.log('Invalid Exif data: Invalid directory offset.');
28652 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28653 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28654 if (dirEndOffset + 4 > dataView.byteLength) {
28655 Roo.log('Invalid Exif data: Invalid directory size.');
28658 for (i = 0; i < tagsNumber; i += 1) {
28662 dirOffset + 2 + 12 * i, // tag offset
28666 // Return the offset to the next directory:
28667 return dataView.getUint32(dirEndOffset, littleEndian);
28670 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28672 var tag = dataView.getUint16(offset, littleEndian);
28674 this.exif[tag] = this.getExifValue(
28678 dataView.getUint16(offset + 2, littleEndian), // tag type
28679 dataView.getUint32(offset + 4, littleEndian), // tag length
28684 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28686 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28695 Roo.log('Invalid Exif data: Invalid tag type.');
28699 tagSize = tagType.size * length;
28700 // Determine if the value is contained in the dataOffset bytes,
28701 // or if the value at the dataOffset is a pointer to the actual data:
28702 dataOffset = tagSize > 4 ?
28703 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28704 if (dataOffset + tagSize > dataView.byteLength) {
28705 Roo.log('Invalid Exif data: Invalid data offset.');
28708 if (length === 1) {
28709 return tagType.getValue(dataView, dataOffset, littleEndian);
28712 for (i = 0; i < length; i += 1) {
28713 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28716 if (tagType.ascii) {
28718 // Concatenate the chars:
28719 for (i = 0; i < values.length; i += 1) {
28721 // Ignore the terminating NULL byte(s):
28722 if (c === '\u0000') {
28734 Roo.apply(Roo.bootstrap.UploadCropbox, {
28736 'Orientation': 0x0112
28740 1: 0, //'top-left',
28742 3: 180, //'bottom-right',
28743 // 4: 'bottom-left',
28745 6: 90, //'right-top',
28746 // 7: 'right-bottom',
28747 8: 270 //'left-bottom'
28751 // byte, 8-bit unsigned int:
28753 getValue: function (dataView, dataOffset) {
28754 return dataView.getUint8(dataOffset);
28758 // ascii, 8-bit byte:
28760 getValue: function (dataView, dataOffset) {
28761 return String.fromCharCode(dataView.getUint8(dataOffset));
28766 // short, 16 bit int:
28768 getValue: function (dataView, dataOffset, littleEndian) {
28769 return dataView.getUint16(dataOffset, littleEndian);
28773 // long, 32 bit int:
28775 getValue: function (dataView, dataOffset, littleEndian) {
28776 return dataView.getUint32(dataOffset, littleEndian);
28780 // rational = two long values, first is numerator, second is denominator:
28782 getValue: function (dataView, dataOffset, littleEndian) {
28783 return dataView.getUint32(dataOffset, littleEndian) /
28784 dataView.getUint32(dataOffset + 4, littleEndian);
28788 // slong, 32 bit signed int:
28790 getValue: function (dataView, dataOffset, littleEndian) {
28791 return dataView.getInt32(dataOffset, littleEndian);
28795 // srational, two slongs, first is numerator, second is denominator:
28797 getValue: function (dataView, dataOffset, littleEndian) {
28798 return dataView.getInt32(dataOffset, littleEndian) /
28799 dataView.getInt32(dataOffset + 4, littleEndian);
28809 cls : 'btn-group roo-upload-cropbox-rotate-left',
28810 action : 'rotate-left',
28814 cls : 'btn btn-default',
28815 html : '<i class="fa fa-undo"></i>'
28821 cls : 'btn-group roo-upload-cropbox-picture',
28822 action : 'picture',
28826 cls : 'btn btn-default',
28827 html : '<i class="fa fa-picture-o"></i>'
28833 cls : 'btn-group roo-upload-cropbox-rotate-right',
28834 action : 'rotate-right',
28838 cls : 'btn btn-default',
28839 html : '<i class="fa fa-repeat"></i>'
28847 cls : 'btn-group roo-upload-cropbox-rotate-left',
28848 action : 'rotate-left',
28852 cls : 'btn btn-default',
28853 html : '<i class="fa fa-undo"></i>'
28859 cls : 'btn-group roo-upload-cropbox-download',
28860 action : 'download',
28864 cls : 'btn btn-default',
28865 html : '<i class="fa fa-download"></i>'
28871 cls : 'btn-group roo-upload-cropbox-crop',
28876 cls : 'btn btn-default',
28877 html : '<i class="fa fa-crop"></i>'
28883 cls : 'btn-group roo-upload-cropbox-trash',
28888 cls : 'btn btn-default',
28889 html : '<i class="fa fa-trash"></i>'
28895 cls : 'btn-group roo-upload-cropbox-rotate-right',
28896 action : 'rotate-right',
28900 cls : 'btn btn-default',
28901 html : '<i class="fa fa-repeat"></i>'
28909 cls : 'btn-group roo-upload-cropbox-rotate-left',
28910 action : 'rotate-left',
28914 cls : 'btn btn-default',
28915 html : '<i class="fa fa-undo"></i>'
28921 cls : 'btn-group roo-upload-cropbox-rotate-right',
28922 action : 'rotate-right',
28926 cls : 'btn btn-default',
28927 html : '<i class="fa fa-repeat"></i>'
28940 * @class Roo.bootstrap.DocumentManager
28941 * @extends Roo.bootstrap.Component
28942 * Bootstrap DocumentManager class
28943 * @cfg {String} paramName default 'imageUpload'
28944 * @cfg {String} toolTipName default 'filename'
28945 * @cfg {String} method default POST
28946 * @cfg {String} url action url
28947 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28948 * @cfg {Boolean} multiple multiple upload default true
28949 * @cfg {Number} thumbSize default 300
28950 * @cfg {String} fieldLabel
28951 * @cfg {Number} labelWidth default 4
28952 * @cfg {String} labelAlign (left|top) default left
28953 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28954 * @cfg {Number} labellg set the width of label (1-12)
28955 * @cfg {Number} labelmd set the width of label (1-12)
28956 * @cfg {Number} labelsm set the width of label (1-12)
28957 * @cfg {Number} labelxs set the width of label (1-12)
28960 * Create a new DocumentManager
28961 * @param {Object} config The config object
28964 Roo.bootstrap.DocumentManager = function(config){
28965 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28968 this.delegates = [];
28973 * Fire when initial the DocumentManager
28974 * @param {Roo.bootstrap.DocumentManager} this
28979 * inspect selected file
28980 * @param {Roo.bootstrap.DocumentManager} this
28981 * @param {File} file
28986 * Fire when xhr load exception
28987 * @param {Roo.bootstrap.DocumentManager} this
28988 * @param {XMLHttpRequest} xhr
28990 "exception" : true,
28992 * @event afterupload
28993 * Fire when xhr load exception
28994 * @param {Roo.bootstrap.DocumentManager} this
28995 * @param {XMLHttpRequest} xhr
28997 "afterupload" : true,
29000 * prepare the form data
29001 * @param {Roo.bootstrap.DocumentManager} this
29002 * @param {Object} formData
29007 * Fire when remove the file
29008 * @param {Roo.bootstrap.DocumentManager} this
29009 * @param {Object} file
29014 * Fire after refresh the file
29015 * @param {Roo.bootstrap.DocumentManager} this
29020 * Fire after click the image
29021 * @param {Roo.bootstrap.DocumentManager} this
29022 * @param {Object} file
29027 * Fire when upload a image and editable set to true
29028 * @param {Roo.bootstrap.DocumentManager} this
29029 * @param {Object} file
29033 * @event beforeselectfile
29034 * Fire before select file
29035 * @param {Roo.bootstrap.DocumentManager} this
29037 "beforeselectfile" : true,
29040 * Fire before process file
29041 * @param {Roo.bootstrap.DocumentManager} this
29042 * @param {Object} file
29046 * @event previewrendered
29047 * Fire when preview rendered
29048 * @param {Roo.bootstrap.DocumentManager} this
29049 * @param {Object} file
29051 "previewrendered" : true,
29054 "previewResize" : true
29059 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29068 paramName : 'imageUpload',
29069 toolTipName : 'filename',
29072 labelAlign : 'left',
29082 getAutoCreate : function()
29084 var managerWidget = {
29086 cls : 'roo-document-manager',
29090 cls : 'roo-document-manager-selector',
29095 cls : 'roo-document-manager-uploader',
29099 cls : 'roo-document-manager-upload-btn',
29100 html : '<i class="fa fa-plus"></i>'
29111 cls : 'column col-md-12',
29116 if(this.fieldLabel.length){
29121 cls : 'column col-md-12',
29122 html : this.fieldLabel
29126 cls : 'column col-md-12',
29131 if(this.labelAlign == 'left'){
29136 html : this.fieldLabel
29145 if(this.labelWidth > 12){
29146 content[0].style = "width: " + this.labelWidth + 'px';
29149 if(this.labelWidth < 13 && this.labelmd == 0){
29150 this.labelmd = this.labelWidth;
29153 if(this.labellg > 0){
29154 content[0].cls += ' col-lg-' + this.labellg;
29155 content[1].cls += ' col-lg-' + (12 - this.labellg);
29158 if(this.labelmd > 0){
29159 content[0].cls += ' col-md-' + this.labelmd;
29160 content[1].cls += ' col-md-' + (12 - this.labelmd);
29163 if(this.labelsm > 0){
29164 content[0].cls += ' col-sm-' + this.labelsm;
29165 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29168 if(this.labelxs > 0){
29169 content[0].cls += ' col-xs-' + this.labelxs;
29170 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29178 cls : 'row clearfix',
29186 initEvents : function()
29188 this.managerEl = this.el.select('.roo-document-manager', true).first();
29189 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29191 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29192 this.selectorEl.hide();
29195 this.selectorEl.attr('multiple', 'multiple');
29198 this.selectorEl.on('change', this.onFileSelected, this);
29200 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29201 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29203 this.uploader.on('click', this.onUploaderClick, this);
29205 this.renderProgressDialog();
29209 window.addEventListener("resize", function() { _this.refresh(); } );
29211 this.fireEvent('initial', this);
29214 renderProgressDialog : function()
29218 this.progressDialog = new Roo.bootstrap.Modal({
29219 cls : 'roo-document-manager-progress-dialog',
29220 allow_close : false,
29231 btnclick : function() {
29232 _this.uploadCancel();
29238 this.progressDialog.render(Roo.get(document.body));
29240 this.progress = new Roo.bootstrap.Progress({
29241 cls : 'roo-document-manager-progress',
29246 this.progress.render(this.progressDialog.getChildContainer());
29248 this.progressBar = new Roo.bootstrap.ProgressBar({
29249 cls : 'roo-document-manager-progress-bar',
29252 aria_valuemax : 12,
29256 this.progressBar.render(this.progress.getChildContainer());
29259 onUploaderClick : function(e)
29261 e.preventDefault();
29263 if(this.fireEvent('beforeselectfile', this) != false){
29264 this.selectorEl.dom.click();
29269 onFileSelected : function(e)
29271 e.preventDefault();
29273 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29277 Roo.each(this.selectorEl.dom.files, function(file){
29278 if(this.fireEvent('inspect', this, file) != false){
29279 this.files.push(file);
29289 this.selectorEl.dom.value = '';
29291 if(!this.files || !this.files.length){
29295 if(this.boxes > 0 && this.files.length > this.boxes){
29296 this.files = this.files.slice(0, this.boxes);
29299 this.uploader.show();
29301 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29302 this.uploader.hide();
29311 Roo.each(this.files, function(file){
29313 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29314 var f = this.renderPreview(file);
29319 if(file.type.indexOf('image') != -1){
29320 this.delegates.push(
29322 _this.process(file);
29323 }).createDelegate(this)
29331 _this.process(file);
29332 }).createDelegate(this)
29337 this.files = files;
29339 this.delegates = this.delegates.concat(docs);
29341 if(!this.delegates.length){
29346 this.progressBar.aria_valuemax = this.delegates.length;
29353 arrange : function()
29355 if(!this.delegates.length){
29356 this.progressDialog.hide();
29361 var delegate = this.delegates.shift();
29363 this.progressDialog.show();
29365 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29367 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29372 refresh : function()
29374 this.uploader.show();
29376 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29377 this.uploader.hide();
29380 Roo.isTouch ? this.closable(false) : this.closable(true);
29382 this.fireEvent('refresh', this);
29385 onRemove : function(e, el, o)
29387 e.preventDefault();
29389 this.fireEvent('remove', this, o);
29393 remove : function(o)
29397 Roo.each(this.files, function(file){
29398 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29407 this.files = files;
29414 Roo.each(this.files, function(file){
29419 file.target.remove();
29428 onClick : function(e, el, o)
29430 e.preventDefault();
29432 this.fireEvent('click', this, o);
29436 closable : function(closable)
29438 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29440 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29452 xhrOnLoad : function(xhr)
29454 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29458 if (xhr.readyState !== 4) {
29460 this.fireEvent('exception', this, xhr);
29464 var response = Roo.decode(xhr.responseText);
29466 if(!response.success){
29468 this.fireEvent('exception', this, xhr);
29472 var file = this.renderPreview(response.data);
29474 this.files.push(file);
29478 this.fireEvent('afterupload', this, xhr);
29482 xhrOnError : function(xhr)
29484 Roo.log('xhr on error');
29486 var response = Roo.decode(xhr.responseText);
29493 process : function(file)
29495 if(this.fireEvent('process', this, file) !== false){
29496 if(this.editable && file.type.indexOf('image') != -1){
29497 this.fireEvent('edit', this, file);
29501 this.uploadStart(file, false);
29508 uploadStart : function(file, crop)
29510 this.xhr = new XMLHttpRequest();
29512 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29517 file.xhr = this.xhr;
29519 this.managerEl.createChild({
29521 cls : 'roo-document-manager-loading',
29525 tooltip : file.name,
29526 cls : 'roo-document-manager-thumb',
29527 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29533 this.xhr.open(this.method, this.url, true);
29536 "Accept": "application/json",
29537 "Cache-Control": "no-cache",
29538 "X-Requested-With": "XMLHttpRequest"
29541 for (var headerName in headers) {
29542 var headerValue = headers[headerName];
29544 this.xhr.setRequestHeader(headerName, headerValue);
29550 this.xhr.onload = function()
29552 _this.xhrOnLoad(_this.xhr);
29555 this.xhr.onerror = function()
29557 _this.xhrOnError(_this.xhr);
29560 var formData = new FormData();
29562 formData.append('returnHTML', 'NO');
29565 formData.append('crop', crop);
29568 formData.append(this.paramName, file, file.name);
29575 if(this.fireEvent('prepare', this, formData, options) != false){
29577 if(options.manually){
29581 this.xhr.send(formData);
29585 this.uploadCancel();
29588 uploadCancel : function()
29594 this.delegates = [];
29596 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29603 renderPreview : function(file)
29605 if(typeof(file.target) != 'undefined' && file.target){
29609 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29611 var previewEl = this.managerEl.createChild({
29613 cls : 'roo-document-manager-preview',
29617 tooltip : file[this.toolTipName],
29618 cls : 'roo-document-manager-thumb',
29619 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29624 html : '<i class="fa fa-times-circle"></i>'
29629 var close = previewEl.select('button.close', true).first();
29631 close.on('click', this.onRemove, this, file);
29633 file.target = previewEl;
29635 var image = previewEl.select('img', true).first();
29639 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29641 image.on('click', this.onClick, this, file);
29643 this.fireEvent('previewrendered', this, file);
29649 onPreviewLoad : function(file, image)
29651 if(typeof(file.target) == 'undefined' || !file.target){
29655 var width = image.dom.naturalWidth || image.dom.width;
29656 var height = image.dom.naturalHeight || image.dom.height;
29658 if(!this.previewResize) {
29662 if(width > height){
29663 file.target.addClass('wide');
29667 file.target.addClass('tall');
29672 uploadFromSource : function(file, crop)
29674 this.xhr = new XMLHttpRequest();
29676 this.managerEl.createChild({
29678 cls : 'roo-document-manager-loading',
29682 tooltip : file.name,
29683 cls : 'roo-document-manager-thumb',
29684 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29690 this.xhr.open(this.method, this.url, true);
29693 "Accept": "application/json",
29694 "Cache-Control": "no-cache",
29695 "X-Requested-With": "XMLHttpRequest"
29698 for (var headerName in headers) {
29699 var headerValue = headers[headerName];
29701 this.xhr.setRequestHeader(headerName, headerValue);
29707 this.xhr.onload = function()
29709 _this.xhrOnLoad(_this.xhr);
29712 this.xhr.onerror = function()
29714 _this.xhrOnError(_this.xhr);
29717 var formData = new FormData();
29719 formData.append('returnHTML', 'NO');
29721 formData.append('crop', crop);
29723 if(typeof(file.filename) != 'undefined'){
29724 formData.append('filename', file.filename);
29727 if(typeof(file.mimetype) != 'undefined'){
29728 formData.append('mimetype', file.mimetype);
29733 if(this.fireEvent('prepare', this, formData) != false){
29734 this.xhr.send(formData);
29744 * @class Roo.bootstrap.DocumentViewer
29745 * @extends Roo.bootstrap.Component
29746 * Bootstrap DocumentViewer class
29747 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29748 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29751 * Create a new DocumentViewer
29752 * @param {Object} config The config object
29755 Roo.bootstrap.DocumentViewer = function(config){
29756 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29761 * Fire after initEvent
29762 * @param {Roo.bootstrap.DocumentViewer} this
29768 * @param {Roo.bootstrap.DocumentViewer} this
29773 * Fire after download button
29774 * @param {Roo.bootstrap.DocumentViewer} this
29779 * Fire after trash button
29780 * @param {Roo.bootstrap.DocumentViewer} this
29787 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29789 showDownload : true,
29793 getAutoCreate : function()
29797 cls : 'roo-document-viewer',
29801 cls : 'roo-document-viewer-body',
29805 cls : 'roo-document-viewer-thumb',
29809 cls : 'roo-document-viewer-image'
29817 cls : 'roo-document-viewer-footer',
29820 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29824 cls : 'btn-group roo-document-viewer-download',
29828 cls : 'btn btn-default',
29829 html : '<i class="fa fa-download"></i>'
29835 cls : 'btn-group roo-document-viewer-trash',
29839 cls : 'btn btn-default',
29840 html : '<i class="fa fa-trash"></i>'
29853 initEvents : function()
29855 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29856 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29858 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29859 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29861 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29862 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29864 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29865 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29867 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29868 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29870 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29871 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29873 this.bodyEl.on('click', this.onClick, this);
29874 this.downloadBtn.on('click', this.onDownload, this);
29875 this.trashBtn.on('click', this.onTrash, this);
29877 this.downloadBtn.hide();
29878 this.trashBtn.hide();
29880 if(this.showDownload){
29881 this.downloadBtn.show();
29884 if(this.showTrash){
29885 this.trashBtn.show();
29888 if(!this.showDownload && !this.showTrash) {
29889 this.footerEl.hide();
29894 initial : function()
29896 this.fireEvent('initial', this);
29900 onClick : function(e)
29902 e.preventDefault();
29904 this.fireEvent('click', this);
29907 onDownload : function(e)
29909 e.preventDefault();
29911 this.fireEvent('download', this);
29914 onTrash : function(e)
29916 e.preventDefault();
29918 this.fireEvent('trash', this);
29930 * @class Roo.bootstrap.NavProgressBar
29931 * @extends Roo.bootstrap.Component
29932 * Bootstrap NavProgressBar class
29935 * Create a new nav progress bar
29936 * @param {Object} config The config object
29939 Roo.bootstrap.NavProgressBar = function(config){
29940 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29942 this.bullets = this.bullets || [];
29944 // Roo.bootstrap.NavProgressBar.register(this);
29948 * Fires when the active item changes
29949 * @param {Roo.bootstrap.NavProgressBar} this
29950 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29951 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29958 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29963 getAutoCreate : function()
29965 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29969 cls : 'roo-navigation-bar-group',
29973 cls : 'roo-navigation-top-bar'
29977 cls : 'roo-navigation-bullets-bar',
29981 cls : 'roo-navigation-bar'
29988 cls : 'roo-navigation-bottom-bar'
29998 initEvents: function()
30003 onRender : function(ct, position)
30005 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30007 if(this.bullets.length){
30008 Roo.each(this.bullets, function(b){
30017 addItem : function(cfg)
30019 var item = new Roo.bootstrap.NavProgressItem(cfg);
30021 item.parentId = this.id;
30022 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30025 var top = new Roo.bootstrap.Element({
30027 cls : 'roo-navigation-bar-text'
30030 var bottom = new Roo.bootstrap.Element({
30032 cls : 'roo-navigation-bar-text'
30035 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30036 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30038 var topText = new Roo.bootstrap.Element({
30040 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30043 var bottomText = new Roo.bootstrap.Element({
30045 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30048 topText.onRender(top.el, null);
30049 bottomText.onRender(bottom.el, null);
30052 item.bottomEl = bottom;
30055 this.barItems.push(item);
30060 getActive : function()
30062 var active = false;
30064 Roo.each(this.barItems, function(v){
30066 if (!v.isActive()) {
30078 setActiveItem : function(item)
30082 Roo.each(this.barItems, function(v){
30083 if (v.rid == item.rid) {
30087 if (v.isActive()) {
30088 v.setActive(false);
30093 item.setActive(true);
30095 this.fireEvent('changed', this, item, prev);
30098 getBarItem: function(rid)
30102 Roo.each(this.barItems, function(e) {
30103 if (e.rid != rid) {
30114 indexOfItem : function(item)
30118 Roo.each(this.barItems, function(v, i){
30120 if (v.rid != item.rid) {
30131 setActiveNext : function()
30133 var i = this.indexOfItem(this.getActive());
30135 if (i > this.barItems.length) {
30139 this.setActiveItem(this.barItems[i+1]);
30142 setActivePrev : function()
30144 var i = this.indexOfItem(this.getActive());
30150 this.setActiveItem(this.barItems[i-1]);
30153 format : function()
30155 if(!this.barItems.length){
30159 var width = 100 / this.barItems.length;
30161 Roo.each(this.barItems, function(i){
30162 i.el.setStyle('width', width + '%');
30163 i.topEl.el.setStyle('width', width + '%');
30164 i.bottomEl.el.setStyle('width', width + '%');
30173 * Nav Progress Item
30178 * @class Roo.bootstrap.NavProgressItem
30179 * @extends Roo.bootstrap.Component
30180 * Bootstrap NavProgressItem class
30181 * @cfg {String} rid the reference id
30182 * @cfg {Boolean} active (true|false) Is item active default false
30183 * @cfg {Boolean} disabled (true|false) Is item active default false
30184 * @cfg {String} html
30185 * @cfg {String} position (top|bottom) text position default bottom
30186 * @cfg {String} icon show icon instead of number
30189 * Create a new NavProgressItem
30190 * @param {Object} config The config object
30192 Roo.bootstrap.NavProgressItem = function(config){
30193 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30198 * The raw click event for the entire grid.
30199 * @param {Roo.bootstrap.NavProgressItem} this
30200 * @param {Roo.EventObject} e
30207 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30213 position : 'bottom',
30216 getAutoCreate : function()
30218 var iconCls = 'roo-navigation-bar-item-icon';
30220 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30224 cls: 'roo-navigation-bar-item',
30234 cfg.cls += ' active';
30237 cfg.cls += ' disabled';
30243 disable : function()
30245 this.setDisabled(true);
30248 enable : function()
30250 this.setDisabled(false);
30253 initEvents: function()
30255 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30257 this.iconEl.on('click', this.onClick, this);
30260 onClick : function(e)
30262 e.preventDefault();
30268 if(this.fireEvent('click', this, e) === false){
30272 this.parent().setActiveItem(this);
30275 isActive: function ()
30277 return this.active;
30280 setActive : function(state)
30282 if(this.active == state){
30286 this.active = state;
30289 this.el.addClass('active');
30293 this.el.removeClass('active');
30298 setDisabled : function(state)
30300 if(this.disabled == state){
30304 this.disabled = state;
30307 this.el.addClass('disabled');
30311 this.el.removeClass('disabled');
30314 tooltipEl : function()
30316 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30329 * @class Roo.bootstrap.FieldLabel
30330 * @extends Roo.bootstrap.Component
30331 * Bootstrap FieldLabel class
30332 * @cfg {String} html contents of the element
30333 * @cfg {String} tag tag of the element default label
30334 * @cfg {String} cls class of the element
30335 * @cfg {String} target label target
30336 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30337 * @cfg {String} invalidClass default "text-warning"
30338 * @cfg {String} validClass default "text-success"
30339 * @cfg {String} iconTooltip default "This field is required"
30340 * @cfg {String} indicatorpos (left|right) default left
30343 * Create a new FieldLabel
30344 * @param {Object} config The config object
30347 Roo.bootstrap.FieldLabel = function(config){
30348 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30353 * Fires after the field has been marked as invalid.
30354 * @param {Roo.form.FieldLabel} this
30355 * @param {String} msg The validation message
30360 * Fires after the field has been validated with no errors.
30361 * @param {Roo.form.FieldLabel} this
30367 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30374 invalidClass : 'has-warning',
30375 validClass : 'has-success',
30376 iconTooltip : 'This field is required',
30377 indicatorpos : 'left',
30379 getAutoCreate : function(){
30382 if (!this.allowBlank) {
30388 cls : 'roo-bootstrap-field-label ' + this.cls,
30393 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30394 tooltip : this.iconTooltip
30403 if(this.indicatorpos == 'right'){
30406 cls : 'roo-bootstrap-field-label ' + this.cls,
30415 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30416 tooltip : this.iconTooltip
30425 initEvents: function()
30427 Roo.bootstrap.Element.superclass.initEvents.call(this);
30429 this.indicator = this.indicatorEl();
30431 if(this.indicator){
30432 this.indicator.removeClass('visible');
30433 this.indicator.addClass('invisible');
30436 Roo.bootstrap.FieldLabel.register(this);
30439 indicatorEl : function()
30441 var indicator = this.el.select('i.roo-required-indicator',true).first();
30452 * Mark this field as valid
30454 markValid : function()
30456 if(this.indicator){
30457 this.indicator.removeClass('visible');
30458 this.indicator.addClass('invisible');
30461 this.el.removeClass(this.invalidClass);
30463 this.el.addClass(this.validClass);
30465 this.fireEvent('valid', this);
30469 * Mark this field as invalid
30470 * @param {String} msg The validation message
30472 markInvalid : function(msg)
30474 if(this.indicator){
30475 this.indicator.removeClass('invisible');
30476 this.indicator.addClass('visible');
30479 this.el.removeClass(this.validClass);
30481 this.el.addClass(this.invalidClass);
30483 this.fireEvent('invalid', this, msg);
30489 Roo.apply(Roo.bootstrap.FieldLabel, {
30494 * register a FieldLabel Group
30495 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30497 register : function(label)
30499 if(this.groups.hasOwnProperty(label.target)){
30503 this.groups[label.target] = label;
30507 * fetch a FieldLabel Group based on the target
30508 * @param {string} target
30509 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30511 get: function(target) {
30512 if (typeof(this.groups[target]) == 'undefined') {
30516 return this.groups[target] ;
30525 * page DateSplitField.
30531 * @class Roo.bootstrap.DateSplitField
30532 * @extends Roo.bootstrap.Component
30533 * Bootstrap DateSplitField class
30534 * @cfg {string} fieldLabel - the label associated
30535 * @cfg {Number} labelWidth set the width of label (0-12)
30536 * @cfg {String} labelAlign (top|left)
30537 * @cfg {Boolean} dayAllowBlank (true|false) default false
30538 * @cfg {Boolean} monthAllowBlank (true|false) default false
30539 * @cfg {Boolean} yearAllowBlank (true|false) default false
30540 * @cfg {string} dayPlaceholder
30541 * @cfg {string} monthPlaceholder
30542 * @cfg {string} yearPlaceholder
30543 * @cfg {string} dayFormat default 'd'
30544 * @cfg {string} monthFormat default 'm'
30545 * @cfg {string} yearFormat default 'Y'
30546 * @cfg {Number} labellg set the width of label (1-12)
30547 * @cfg {Number} labelmd set the width of label (1-12)
30548 * @cfg {Number} labelsm set the width of label (1-12)
30549 * @cfg {Number} labelxs set the width of label (1-12)
30553 * Create a new DateSplitField
30554 * @param {Object} config The config object
30557 Roo.bootstrap.DateSplitField = function(config){
30558 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30564 * getting the data of years
30565 * @param {Roo.bootstrap.DateSplitField} this
30566 * @param {Object} years
30571 * getting the data of days
30572 * @param {Roo.bootstrap.DateSplitField} this
30573 * @param {Object} days
30578 * Fires after the field has been marked as invalid.
30579 * @param {Roo.form.Field} this
30580 * @param {String} msg The validation message
30585 * Fires after the field has been validated with no errors.
30586 * @param {Roo.form.Field} this
30592 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30595 labelAlign : 'top',
30597 dayAllowBlank : false,
30598 monthAllowBlank : false,
30599 yearAllowBlank : false,
30600 dayPlaceholder : '',
30601 monthPlaceholder : '',
30602 yearPlaceholder : '',
30606 isFormField : true,
30612 getAutoCreate : function()
30616 cls : 'row roo-date-split-field-group',
30621 cls : 'form-hidden-field roo-date-split-field-group-value',
30627 var labelCls = 'col-md-12';
30628 var contentCls = 'col-md-4';
30630 if(this.fieldLabel){
30634 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30638 html : this.fieldLabel
30643 if(this.labelAlign == 'left'){
30645 if(this.labelWidth > 12){
30646 label.style = "width: " + this.labelWidth + 'px';
30649 if(this.labelWidth < 13 && this.labelmd == 0){
30650 this.labelmd = this.labelWidth;
30653 if(this.labellg > 0){
30654 labelCls = ' col-lg-' + this.labellg;
30655 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30658 if(this.labelmd > 0){
30659 labelCls = ' col-md-' + this.labelmd;
30660 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30663 if(this.labelsm > 0){
30664 labelCls = ' col-sm-' + this.labelsm;
30665 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30668 if(this.labelxs > 0){
30669 labelCls = ' col-xs-' + this.labelxs;
30670 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30674 label.cls += ' ' + labelCls;
30676 cfg.cn.push(label);
30679 Roo.each(['day', 'month', 'year'], function(t){
30682 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30689 inputEl: function ()
30691 return this.el.select('.roo-date-split-field-group-value', true).first();
30694 onRender : function(ct, position)
30698 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30700 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30702 this.dayField = new Roo.bootstrap.ComboBox({
30703 allowBlank : this.dayAllowBlank,
30704 alwaysQuery : true,
30705 displayField : 'value',
30708 forceSelection : true,
30710 placeholder : this.dayPlaceholder,
30711 selectOnFocus : true,
30712 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30713 triggerAction : 'all',
30715 valueField : 'value',
30716 store : new Roo.data.SimpleStore({
30717 data : (function() {
30719 _this.fireEvent('days', _this, days);
30722 fields : [ 'value' ]
30725 select : function (_self, record, index)
30727 _this.setValue(_this.getValue());
30732 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30734 this.monthField = new Roo.bootstrap.MonthField({
30735 after : '<i class=\"fa fa-calendar\"></i>',
30736 allowBlank : this.monthAllowBlank,
30737 placeholder : this.monthPlaceholder,
30740 render : function (_self)
30742 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30743 e.preventDefault();
30747 select : function (_self, oldvalue, newvalue)
30749 _this.setValue(_this.getValue());
30754 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30756 this.yearField = new Roo.bootstrap.ComboBox({
30757 allowBlank : this.yearAllowBlank,
30758 alwaysQuery : true,
30759 displayField : 'value',
30762 forceSelection : true,
30764 placeholder : this.yearPlaceholder,
30765 selectOnFocus : true,
30766 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30767 triggerAction : 'all',
30769 valueField : 'value',
30770 store : new Roo.data.SimpleStore({
30771 data : (function() {
30773 _this.fireEvent('years', _this, years);
30776 fields : [ 'value' ]
30779 select : function (_self, record, index)
30781 _this.setValue(_this.getValue());
30786 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30789 setValue : function(v, format)
30791 this.inputEl.dom.value = v;
30793 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30795 var d = Date.parseDate(v, f);
30802 this.setDay(d.format(this.dayFormat));
30803 this.setMonth(d.format(this.monthFormat));
30804 this.setYear(d.format(this.yearFormat));
30811 setDay : function(v)
30813 this.dayField.setValue(v);
30814 this.inputEl.dom.value = this.getValue();
30819 setMonth : function(v)
30821 this.monthField.setValue(v, true);
30822 this.inputEl.dom.value = this.getValue();
30827 setYear : function(v)
30829 this.yearField.setValue(v);
30830 this.inputEl.dom.value = this.getValue();
30835 getDay : function()
30837 return this.dayField.getValue();
30840 getMonth : function()
30842 return this.monthField.getValue();
30845 getYear : function()
30847 return this.yearField.getValue();
30850 getValue : function()
30852 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30854 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30864 this.inputEl.dom.value = '';
30869 validate : function()
30871 var d = this.dayField.validate();
30872 var m = this.monthField.validate();
30873 var y = this.yearField.validate();
30878 (!this.dayAllowBlank && !d) ||
30879 (!this.monthAllowBlank && !m) ||
30880 (!this.yearAllowBlank && !y)
30885 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30894 this.markInvalid();
30899 markValid : function()
30902 var label = this.el.select('label', true).first();
30903 var icon = this.el.select('i.fa-star', true).first();
30909 this.fireEvent('valid', this);
30913 * Mark this field as invalid
30914 * @param {String} msg The validation message
30916 markInvalid : function(msg)
30919 var label = this.el.select('label', true).first();
30920 var icon = this.el.select('i.fa-star', true).first();
30922 if(label && !icon){
30923 this.el.select('.roo-date-split-field-label', true).createChild({
30925 cls : 'text-danger fa fa-lg fa-star',
30926 tooltip : 'This field is required',
30927 style : 'margin-right:5px;'
30931 this.fireEvent('invalid', this, msg);
30934 clearInvalid : function()
30936 var label = this.el.select('label', true).first();
30937 var icon = this.el.select('i.fa-star', true).first();
30943 this.fireEvent('valid', this);
30946 getName: function()
30956 * http://masonry.desandro.com
30958 * The idea is to render all the bricks based on vertical width...
30960 * The original code extends 'outlayer' - we might need to use that....
30966 * @class Roo.bootstrap.LayoutMasonry
30967 * @extends Roo.bootstrap.Component
30968 * Bootstrap Layout Masonry class
30971 * Create a new Element
30972 * @param {Object} config The config object
30975 Roo.bootstrap.LayoutMasonry = function(config){
30977 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30981 Roo.bootstrap.LayoutMasonry.register(this);
30987 * Fire after layout the items
30988 * @param {Roo.bootstrap.LayoutMasonry} this
30989 * @param {Roo.EventObject} e
30996 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
30999 * @cfg {Boolean} isLayoutInstant = no animation?
31001 isLayoutInstant : false, // needed?
31004 * @cfg {Number} boxWidth width of the columns
31009 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31014 * @cfg {Number} padWidth padding below box..
31019 * @cfg {Number} gutter gutter width..
31024 * @cfg {Number} maxCols maximum number of columns
31030 * @cfg {Boolean} isAutoInitial defalut true
31032 isAutoInitial : true,
31037 * @cfg {Boolean} isHorizontal defalut false
31039 isHorizontal : false,
31041 currentSize : null,
31047 bricks: null, //CompositeElement
31051 _isLayoutInited : false,
31053 // isAlternative : false, // only use for vertical layout...
31056 * @cfg {Number} alternativePadWidth padding below box..
31058 alternativePadWidth : 50,
31060 selectedBrick : [],
31062 getAutoCreate : function(){
31064 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31068 cls: 'blog-masonary-wrapper ' + this.cls,
31070 cls : 'mas-boxes masonary'
31077 getChildContainer: function( )
31079 if (this.boxesEl) {
31080 return this.boxesEl;
31083 this.boxesEl = this.el.select('.mas-boxes').first();
31085 return this.boxesEl;
31089 initEvents : function()
31093 if(this.isAutoInitial){
31094 Roo.log('hook children rendered');
31095 this.on('childrenrendered', function() {
31096 Roo.log('children rendered');
31102 initial : function()
31104 this.selectedBrick = [];
31106 this.currentSize = this.el.getBox(true);
31108 Roo.EventManager.onWindowResize(this.resize, this);
31110 if(!this.isAutoInitial){
31118 //this.layout.defer(500,this);
31122 resize : function()
31124 var cs = this.el.getBox(true);
31127 this.currentSize.width == cs.width &&
31128 this.currentSize.x == cs.x &&
31129 this.currentSize.height == cs.height &&
31130 this.currentSize.y == cs.y
31132 Roo.log("no change in with or X or Y");
31136 this.currentSize = cs;
31142 layout : function()
31144 this._resetLayout();
31146 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31148 this.layoutItems( isInstant );
31150 this._isLayoutInited = true;
31152 this.fireEvent('layout', this);
31156 _resetLayout : function()
31158 if(this.isHorizontal){
31159 this.horizontalMeasureColumns();
31163 this.verticalMeasureColumns();
31167 verticalMeasureColumns : function()
31169 this.getContainerWidth();
31171 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31172 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31176 var boxWidth = this.boxWidth + this.padWidth;
31178 if(this.containerWidth < this.boxWidth){
31179 boxWidth = this.containerWidth
31182 var containerWidth = this.containerWidth;
31184 var cols = Math.floor(containerWidth / boxWidth);
31186 this.cols = Math.max( cols, 1 );
31188 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31190 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31192 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31194 this.colWidth = boxWidth + avail - this.padWidth;
31196 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31197 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31200 horizontalMeasureColumns : function()
31202 this.getContainerWidth();
31204 var boxWidth = this.boxWidth;
31206 if(this.containerWidth < boxWidth){
31207 boxWidth = this.containerWidth;
31210 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31212 this.el.setHeight(boxWidth);
31216 getContainerWidth : function()
31218 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31221 layoutItems : function( isInstant )
31223 Roo.log(this.bricks);
31225 var items = Roo.apply([], this.bricks);
31227 if(this.isHorizontal){
31228 this._horizontalLayoutItems( items , isInstant );
31232 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31233 // this._verticalAlternativeLayoutItems( items , isInstant );
31237 this._verticalLayoutItems( items , isInstant );
31241 _verticalLayoutItems : function ( items , isInstant)
31243 if ( !items || !items.length ) {
31248 ['xs', 'xs', 'xs', 'tall'],
31249 ['xs', 'xs', 'tall'],
31250 ['xs', 'xs', 'sm'],
31251 ['xs', 'xs', 'xs'],
31257 ['sm', 'xs', 'xs'],
31261 ['tall', 'xs', 'xs', 'xs'],
31262 ['tall', 'xs', 'xs'],
31274 Roo.each(items, function(item, k){
31276 switch (item.size) {
31277 // these layouts take up a full box,
31288 boxes.push([item]);
31311 var filterPattern = function(box, length)
31319 var pattern = box.slice(0, length);
31323 Roo.each(pattern, function(i){
31324 format.push(i.size);
31327 Roo.each(standard, function(s){
31329 if(String(s) != String(format)){
31338 if(!match && length == 1){
31343 filterPattern(box, length - 1);
31347 queue.push(pattern);
31349 box = box.slice(length, box.length);
31351 filterPattern(box, 4);
31357 Roo.each(boxes, function(box, k){
31363 if(box.length == 1){
31368 filterPattern(box, 4);
31372 this._processVerticalLayoutQueue( queue, isInstant );
31376 // _verticalAlternativeLayoutItems : function( items , isInstant )
31378 // if ( !items || !items.length ) {
31382 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31386 _horizontalLayoutItems : function ( items , isInstant)
31388 if ( !items || !items.length || items.length < 3) {
31394 var eItems = items.slice(0, 3);
31396 items = items.slice(3, items.length);
31399 ['xs', 'xs', 'xs', 'wide'],
31400 ['xs', 'xs', 'wide'],
31401 ['xs', 'xs', 'sm'],
31402 ['xs', 'xs', 'xs'],
31408 ['sm', 'xs', 'xs'],
31412 ['wide', 'xs', 'xs', 'xs'],
31413 ['wide', 'xs', 'xs'],
31426 Roo.each(items, function(item, k){
31428 switch (item.size) {
31439 boxes.push([item]);
31463 var filterPattern = function(box, length)
31471 var pattern = box.slice(0, length);
31475 Roo.each(pattern, function(i){
31476 format.push(i.size);
31479 Roo.each(standard, function(s){
31481 if(String(s) != String(format)){
31490 if(!match && length == 1){
31495 filterPattern(box, length - 1);
31499 queue.push(pattern);
31501 box = box.slice(length, box.length);
31503 filterPattern(box, 4);
31509 Roo.each(boxes, function(box, k){
31515 if(box.length == 1){
31520 filterPattern(box, 4);
31527 var pos = this.el.getBox(true);
31531 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31533 var hit_end = false;
31535 Roo.each(queue, function(box){
31539 Roo.each(box, function(b){
31541 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31551 Roo.each(box, function(b){
31553 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31556 mx = Math.max(mx, b.x);
31560 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31564 Roo.each(box, function(b){
31566 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31580 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31583 /** Sets position of item in DOM
31584 * @param {Element} item
31585 * @param {Number} x - horizontal position
31586 * @param {Number} y - vertical position
31587 * @param {Boolean} isInstant - disables transitions
31589 _processVerticalLayoutQueue : function( queue, isInstant )
31591 var pos = this.el.getBox(true);
31596 for (var i = 0; i < this.cols; i++){
31600 Roo.each(queue, function(box, k){
31602 var col = k % this.cols;
31604 Roo.each(box, function(b,kk){
31606 b.el.position('absolute');
31608 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31609 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31611 if(b.size == 'md-left' || b.size == 'md-right'){
31612 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31613 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31616 b.el.setWidth(width);
31617 b.el.setHeight(height);
31619 b.el.select('iframe',true).setSize(width,height);
31623 for (var i = 0; i < this.cols; i++){
31625 if(maxY[i] < maxY[col]){
31630 col = Math.min(col, i);
31634 x = pos.x + col * (this.colWidth + this.padWidth);
31638 var positions = [];
31640 switch (box.length){
31642 positions = this.getVerticalOneBoxColPositions(x, y, box);
31645 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31648 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31651 positions = this.getVerticalFourBoxColPositions(x, y, box);
31657 Roo.each(box, function(b,kk){
31659 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31661 var sz = b.el.getSize();
31663 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31671 for (var i = 0; i < this.cols; i++){
31672 mY = Math.max(mY, maxY[i]);
31675 this.el.setHeight(mY - pos.y);
31679 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31681 // var pos = this.el.getBox(true);
31684 // var maxX = pos.right;
31686 // var maxHeight = 0;
31688 // Roo.each(items, function(item, k){
31692 // item.el.position('absolute');
31694 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31696 // item.el.setWidth(width);
31698 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31700 // item.el.setHeight(height);
31703 // item.el.setXY([x, y], isInstant ? false : true);
31705 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31708 // y = y + height + this.alternativePadWidth;
31710 // maxHeight = maxHeight + height + this.alternativePadWidth;
31714 // this.el.setHeight(maxHeight);
31718 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31720 var pos = this.el.getBox(true);
31725 var maxX = pos.right;
31727 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31729 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31731 Roo.each(queue, function(box, k){
31733 Roo.each(box, function(b, kk){
31735 b.el.position('absolute');
31737 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31738 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31740 if(b.size == 'md-left' || b.size == 'md-right'){
31741 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31742 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31745 b.el.setWidth(width);
31746 b.el.setHeight(height);
31754 var positions = [];
31756 switch (box.length){
31758 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31761 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31764 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31767 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31773 Roo.each(box, function(b,kk){
31775 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31777 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31785 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31787 Roo.each(eItems, function(b,k){
31789 b.size = (k == 0) ? 'sm' : 'xs';
31790 b.x = (k == 0) ? 2 : 1;
31791 b.y = (k == 0) ? 2 : 1;
31793 b.el.position('absolute');
31795 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31797 b.el.setWidth(width);
31799 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31801 b.el.setHeight(height);
31805 var positions = [];
31808 x : maxX - this.unitWidth * 2 - this.gutter,
31813 x : maxX - this.unitWidth,
31814 y : minY + (this.unitWidth + this.gutter) * 2
31818 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31822 Roo.each(eItems, function(b,k){
31824 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31830 getVerticalOneBoxColPositions : function(x, y, box)
31834 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31836 if(box[0].size == 'md-left'){
31840 if(box[0].size == 'md-right'){
31845 x : x + (this.unitWidth + this.gutter) * rand,
31852 getVerticalTwoBoxColPositions : function(x, y, box)
31856 if(box[0].size == 'xs'){
31860 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31864 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31878 x : x + (this.unitWidth + this.gutter) * 2,
31879 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31886 getVerticalThreeBoxColPositions : function(x, y, box)
31890 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31898 x : x + (this.unitWidth + this.gutter) * 1,
31903 x : x + (this.unitWidth + this.gutter) * 2,
31911 if(box[0].size == 'xs' && box[1].size == 'xs'){
31920 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31924 x : x + (this.unitWidth + this.gutter) * 1,
31938 x : x + (this.unitWidth + this.gutter) * 2,
31943 x : x + (this.unitWidth + this.gutter) * 2,
31944 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31951 getVerticalFourBoxColPositions : function(x, y, box)
31955 if(box[0].size == 'xs'){
31964 y : y + (this.unitHeight + this.gutter) * 1
31969 y : y + (this.unitHeight + this.gutter) * 2
31973 x : x + (this.unitWidth + this.gutter) * 1,
31987 x : x + (this.unitWidth + this.gutter) * 2,
31992 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
31993 y : y + (this.unitHeight + this.gutter) * 1
31997 x : x + (this.unitWidth + this.gutter) * 2,
31998 y : y + (this.unitWidth + this.gutter) * 2
32005 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32009 if(box[0].size == 'md-left'){
32011 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32018 if(box[0].size == 'md-right'){
32020 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32021 y : minY + (this.unitWidth + this.gutter) * 1
32027 var rand = Math.floor(Math.random() * (4 - box[0].y));
32030 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32031 y : minY + (this.unitWidth + this.gutter) * rand
32038 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32042 if(box[0].size == 'xs'){
32045 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32050 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32051 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32059 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32064 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32065 y : minY + (this.unitWidth + this.gutter) * 2
32072 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32076 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32079 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32084 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32085 y : minY + (this.unitWidth + this.gutter) * 1
32089 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32090 y : minY + (this.unitWidth + this.gutter) * 2
32097 if(box[0].size == 'xs' && box[1].size == 'xs'){
32100 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32105 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32110 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32111 y : minY + (this.unitWidth + this.gutter) * 1
32119 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32124 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32125 y : minY + (this.unitWidth + this.gutter) * 2
32129 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32130 y : minY + (this.unitWidth + this.gutter) * 2
32137 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32141 if(box[0].size == 'xs'){
32144 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32149 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32154 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),
32159 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32160 y : minY + (this.unitWidth + this.gutter) * 1
32168 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32173 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32174 y : minY + (this.unitWidth + this.gutter) * 2
32178 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32179 y : minY + (this.unitWidth + this.gutter) * 2
32183 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),
32184 y : minY + (this.unitWidth + this.gutter) * 2
32192 * remove a Masonry Brick
32193 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32195 removeBrick : function(brick_id)
32201 for (var i = 0; i<this.bricks.length; i++) {
32202 if (this.bricks[i].id == brick_id) {
32203 this.bricks.splice(i,1);
32204 this.el.dom.removeChild(Roo.get(brick_id).dom);
32211 * adds a Masonry Brick
32212 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32214 addBrick : function(cfg)
32216 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32217 //this.register(cn);
32218 cn.parentId = this.id;
32219 cn.render(this.el);
32224 * register a Masonry Brick
32225 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32228 register : function(brick)
32230 this.bricks.push(brick);
32231 brick.masonryId = this.id;
32235 * clear all the Masonry Brick
32237 clearAll : function()
32240 //this.getChildContainer().dom.innerHTML = "";
32241 this.el.dom.innerHTML = '';
32244 getSelected : function()
32246 if (!this.selectedBrick) {
32250 return this.selectedBrick;
32254 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32258 * register a Masonry Layout
32259 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32262 register : function(layout)
32264 this.groups[layout.id] = layout;
32267 * fetch a Masonry Layout based on the masonry layout ID
32268 * @param {string} the masonry layout to add
32269 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32272 get: function(layout_id) {
32273 if (typeof(this.groups[layout_id]) == 'undefined') {
32276 return this.groups[layout_id] ;
32288 * http://masonry.desandro.com
32290 * The idea is to render all the bricks based on vertical width...
32292 * The original code extends 'outlayer' - we might need to use that....
32298 * @class Roo.bootstrap.LayoutMasonryAuto
32299 * @extends Roo.bootstrap.Component
32300 * Bootstrap Layout Masonry class
32303 * Create a new Element
32304 * @param {Object} config The config object
32307 Roo.bootstrap.LayoutMasonryAuto = function(config){
32308 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32311 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32314 * @cfg {Boolean} isFitWidth - resize the width..
32316 isFitWidth : false, // options..
32318 * @cfg {Boolean} isOriginLeft = left align?
32320 isOriginLeft : true,
32322 * @cfg {Boolean} isOriginTop = top align?
32324 isOriginTop : false,
32326 * @cfg {Boolean} isLayoutInstant = no animation?
32328 isLayoutInstant : false, // needed?
32330 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32332 isResizingContainer : true,
32334 * @cfg {Number} columnWidth width of the columns
32340 * @cfg {Number} maxCols maximum number of columns
32345 * @cfg {Number} padHeight padding below box..
32351 * @cfg {Boolean} isAutoInitial defalut true
32354 isAutoInitial : true,
32360 initialColumnWidth : 0,
32361 currentSize : null,
32363 colYs : null, // array.
32370 bricks: null, //CompositeElement
32371 cols : 0, // array?
32372 // element : null, // wrapped now this.el
32373 _isLayoutInited : null,
32376 getAutoCreate : function(){
32380 cls: 'blog-masonary-wrapper ' + this.cls,
32382 cls : 'mas-boxes masonary'
32389 getChildContainer: function( )
32391 if (this.boxesEl) {
32392 return this.boxesEl;
32395 this.boxesEl = this.el.select('.mas-boxes').first();
32397 return this.boxesEl;
32401 initEvents : function()
32405 if(this.isAutoInitial){
32406 Roo.log('hook children rendered');
32407 this.on('childrenrendered', function() {
32408 Roo.log('children rendered');
32415 initial : function()
32417 this.reloadItems();
32419 this.currentSize = this.el.getBox(true);
32421 /// was window resize... - let's see if this works..
32422 Roo.EventManager.onWindowResize(this.resize, this);
32424 if(!this.isAutoInitial){
32429 this.layout.defer(500,this);
32432 reloadItems: function()
32434 this.bricks = this.el.select('.masonry-brick', true);
32436 this.bricks.each(function(b) {
32437 //Roo.log(b.getSize());
32438 if (!b.attr('originalwidth')) {
32439 b.attr('originalwidth', b.getSize().width);
32444 Roo.log(this.bricks.elements.length);
32447 resize : function()
32450 var cs = this.el.getBox(true);
32452 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32453 Roo.log("no change in with or X");
32456 this.currentSize = cs;
32460 layout : function()
32463 this._resetLayout();
32464 //this._manageStamps();
32466 // don't animate first layout
32467 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32468 this.layoutItems( isInstant );
32470 // flag for initalized
32471 this._isLayoutInited = true;
32474 layoutItems : function( isInstant )
32476 //var items = this._getItemsForLayout( this.items );
32477 // original code supports filtering layout items.. we just ignore it..
32479 this._layoutItems( this.bricks , isInstant );
32481 this._postLayout();
32483 _layoutItems : function ( items , isInstant)
32485 //this.fireEvent( 'layout', this, items );
32488 if ( !items || !items.elements.length ) {
32489 // no items, emit event with empty array
32494 items.each(function(item) {
32495 Roo.log("layout item");
32497 // get x/y object from method
32498 var position = this._getItemLayoutPosition( item );
32500 position.item = item;
32501 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32502 queue.push( position );
32505 this._processLayoutQueue( queue );
32507 /** Sets position of item in DOM
32508 * @param {Element} item
32509 * @param {Number} x - horizontal position
32510 * @param {Number} y - vertical position
32511 * @param {Boolean} isInstant - disables transitions
32513 _processLayoutQueue : function( queue )
32515 for ( var i=0, len = queue.length; i < len; i++ ) {
32516 var obj = queue[i];
32517 obj.item.position('absolute');
32518 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32524 * Any logic you want to do after each layout,
32525 * i.e. size the container
32527 _postLayout : function()
32529 this.resizeContainer();
32532 resizeContainer : function()
32534 if ( !this.isResizingContainer ) {
32537 var size = this._getContainerSize();
32539 this.el.setSize(size.width,size.height);
32540 this.boxesEl.setSize(size.width,size.height);
32546 _resetLayout : function()
32548 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32549 this.colWidth = this.el.getWidth();
32550 //this.gutter = this.el.getWidth();
32552 this.measureColumns();
32558 this.colYs.push( 0 );
32564 measureColumns : function()
32566 this.getContainerWidth();
32567 // if columnWidth is 0, default to outerWidth of first item
32568 if ( !this.columnWidth ) {
32569 var firstItem = this.bricks.first();
32570 Roo.log(firstItem);
32571 this.columnWidth = this.containerWidth;
32572 if (firstItem && firstItem.attr('originalwidth') ) {
32573 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32575 // columnWidth fall back to item of first element
32576 Roo.log("set column width?");
32577 this.initialColumnWidth = this.columnWidth ;
32579 // if first elem has no width, default to size of container
32584 if (this.initialColumnWidth) {
32585 this.columnWidth = this.initialColumnWidth;
32590 // column width is fixed at the top - however if container width get's smaller we should
32593 // this bit calcs how man columns..
32595 var columnWidth = this.columnWidth += this.gutter;
32597 // calculate columns
32598 var containerWidth = this.containerWidth + this.gutter;
32600 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32601 // fix rounding errors, typically with gutters
32602 var excess = columnWidth - containerWidth % columnWidth;
32605 // if overshoot is less than a pixel, round up, otherwise floor it
32606 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32607 cols = Math[ mathMethod ]( cols );
32608 this.cols = Math.max( cols, 1 );
32609 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32611 // padding positioning..
32612 var totalColWidth = this.cols * this.columnWidth;
32613 var padavail = this.containerWidth - totalColWidth;
32614 // so for 2 columns - we need 3 'pads'
32616 var padNeeded = (1+this.cols) * this.padWidth;
32618 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32620 this.columnWidth += padExtra
32621 //this.padWidth = Math.floor(padavail / ( this.cols));
32623 // adjust colum width so that padding is fixed??
32625 // we have 3 columns ... total = width * 3
32626 // we have X left over... that should be used by
32628 //if (this.expandC) {
32636 getContainerWidth : function()
32638 /* // container is parent if fit width
32639 var container = this.isFitWidth ? this.element.parentNode : this.element;
32640 // check that this.size and size are there
32641 // IE8 triggers resize on body size change, so they might not be
32643 var size = getSize( container ); //FIXME
32644 this.containerWidth = size && size.innerWidth; //FIXME
32647 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32651 _getItemLayoutPosition : function( item ) // what is item?
32653 // we resize the item to our columnWidth..
32655 item.setWidth(this.columnWidth);
32656 item.autoBoxAdjust = false;
32658 var sz = item.getSize();
32660 // how many columns does this brick span
32661 var remainder = this.containerWidth % this.columnWidth;
32663 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32664 // round if off by 1 pixel, otherwise use ceil
32665 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32666 colSpan = Math.min( colSpan, this.cols );
32668 // normally this should be '1' as we dont' currently allow multi width columns..
32670 var colGroup = this._getColGroup( colSpan );
32671 // get the minimum Y value from the columns
32672 var minimumY = Math.min.apply( Math, colGroup );
32673 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32675 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32677 // position the brick
32679 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32680 y: this.currentSize.y + minimumY + this.padHeight
32684 // apply setHeight to necessary columns
32685 var setHeight = minimumY + sz.height + this.padHeight;
32686 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32688 var setSpan = this.cols + 1 - colGroup.length;
32689 for ( var i = 0; i < setSpan; i++ ) {
32690 this.colYs[ shortColIndex + i ] = setHeight ;
32697 * @param {Number} colSpan - number of columns the element spans
32698 * @returns {Array} colGroup
32700 _getColGroup : function( colSpan )
32702 if ( colSpan < 2 ) {
32703 // if brick spans only one column, use all the column Ys
32708 // how many different places could this brick fit horizontally
32709 var groupCount = this.cols + 1 - colSpan;
32710 // for each group potential horizontal position
32711 for ( var i = 0; i < groupCount; i++ ) {
32712 // make an array of colY values for that one group
32713 var groupColYs = this.colYs.slice( i, i + colSpan );
32714 // and get the max value of the array
32715 colGroup[i] = Math.max.apply( Math, groupColYs );
32720 _manageStamp : function( stamp )
32722 var stampSize = stamp.getSize();
32723 var offset = stamp.getBox();
32724 // get the columns that this stamp affects
32725 var firstX = this.isOriginLeft ? offset.x : offset.right;
32726 var lastX = firstX + stampSize.width;
32727 var firstCol = Math.floor( firstX / this.columnWidth );
32728 firstCol = Math.max( 0, firstCol );
32730 var lastCol = Math.floor( lastX / this.columnWidth );
32731 // lastCol should not go over if multiple of columnWidth #425
32732 lastCol -= lastX % this.columnWidth ? 0 : 1;
32733 lastCol = Math.min( this.cols - 1, lastCol );
32735 // set colYs to bottom of the stamp
32736 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32739 for ( var i = firstCol; i <= lastCol; i++ ) {
32740 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32745 _getContainerSize : function()
32747 this.maxY = Math.max.apply( Math, this.colYs );
32752 if ( this.isFitWidth ) {
32753 size.width = this._getContainerFitWidth();
32759 _getContainerFitWidth : function()
32761 var unusedCols = 0;
32762 // count unused columns
32765 if ( this.colYs[i] !== 0 ) {
32770 // fit container to columns that have been used
32771 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32774 needsResizeLayout : function()
32776 var previousWidth = this.containerWidth;
32777 this.getContainerWidth();
32778 return previousWidth !== this.containerWidth;
32793 * @class Roo.bootstrap.MasonryBrick
32794 * @extends Roo.bootstrap.Component
32795 * Bootstrap MasonryBrick class
32798 * Create a new MasonryBrick
32799 * @param {Object} config The config object
32802 Roo.bootstrap.MasonryBrick = function(config){
32804 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32806 Roo.bootstrap.MasonryBrick.register(this);
32812 * When a MasonryBrick is clcik
32813 * @param {Roo.bootstrap.MasonryBrick} this
32814 * @param {Roo.EventObject} e
32820 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32823 * @cfg {String} title
32827 * @cfg {String} html
32831 * @cfg {String} bgimage
32835 * @cfg {String} videourl
32839 * @cfg {String} cls
32843 * @cfg {String} href
32847 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32852 * @cfg {String} placetitle (center|bottom)
32857 * @cfg {Boolean} isFitContainer defalut true
32859 isFitContainer : true,
32862 * @cfg {Boolean} preventDefault defalut false
32864 preventDefault : false,
32867 * @cfg {Boolean} inverse defalut false
32869 maskInverse : false,
32871 getAutoCreate : function()
32873 if(!this.isFitContainer){
32874 return this.getSplitAutoCreate();
32877 var cls = 'masonry-brick masonry-brick-full';
32879 if(this.href.length){
32880 cls += ' masonry-brick-link';
32883 if(this.bgimage.length){
32884 cls += ' masonry-brick-image';
32887 if(this.maskInverse){
32888 cls += ' mask-inverse';
32891 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32892 cls += ' enable-mask';
32896 cls += ' masonry-' + this.size + '-brick';
32899 if(this.placetitle.length){
32901 switch (this.placetitle) {
32903 cls += ' masonry-center-title';
32906 cls += ' masonry-bottom-title';
32913 if(!this.html.length && !this.bgimage.length){
32914 cls += ' masonry-center-title';
32917 if(!this.html.length && this.bgimage.length){
32918 cls += ' masonry-bottom-title';
32923 cls += ' ' + this.cls;
32927 tag: (this.href.length) ? 'a' : 'div',
32932 cls: 'masonry-brick-mask'
32936 cls: 'masonry-brick-paragraph',
32942 if(this.href.length){
32943 cfg.href = this.href;
32946 var cn = cfg.cn[1].cn;
32948 if(this.title.length){
32951 cls: 'masonry-brick-title',
32956 if(this.html.length){
32959 cls: 'masonry-brick-text',
32964 if (!this.title.length && !this.html.length) {
32965 cfg.cn[1].cls += ' hide';
32968 if(this.bgimage.length){
32971 cls: 'masonry-brick-image-view',
32976 if(this.videourl.length){
32977 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32978 // youtube support only?
32981 cls: 'masonry-brick-image-view',
32984 allowfullscreen : true
32992 getSplitAutoCreate : function()
32994 var cls = 'masonry-brick masonry-brick-split';
32996 if(this.href.length){
32997 cls += ' masonry-brick-link';
33000 if(this.bgimage.length){
33001 cls += ' masonry-brick-image';
33005 cls += ' masonry-' + this.size + '-brick';
33008 switch (this.placetitle) {
33010 cls += ' masonry-center-title';
33013 cls += ' masonry-bottom-title';
33016 if(!this.bgimage.length){
33017 cls += ' masonry-center-title';
33020 if(this.bgimage.length){
33021 cls += ' masonry-bottom-title';
33027 cls += ' ' + this.cls;
33031 tag: (this.href.length) ? 'a' : 'div',
33036 cls: 'masonry-brick-split-head',
33040 cls: 'masonry-brick-paragraph',
33047 cls: 'masonry-brick-split-body',
33053 if(this.href.length){
33054 cfg.href = this.href;
33057 if(this.title.length){
33058 cfg.cn[0].cn[0].cn.push({
33060 cls: 'masonry-brick-title',
33065 if(this.html.length){
33066 cfg.cn[1].cn.push({
33068 cls: 'masonry-brick-text',
33073 if(this.bgimage.length){
33074 cfg.cn[0].cn.push({
33076 cls: 'masonry-brick-image-view',
33081 if(this.videourl.length){
33082 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33083 // youtube support only?
33084 cfg.cn[0].cn.cn.push({
33086 cls: 'masonry-brick-image-view',
33089 allowfullscreen : true
33096 initEvents: function()
33098 switch (this.size) {
33131 this.el.on('touchstart', this.onTouchStart, this);
33132 this.el.on('touchmove', this.onTouchMove, this);
33133 this.el.on('touchend', this.onTouchEnd, this);
33134 this.el.on('contextmenu', this.onContextMenu, this);
33136 this.el.on('mouseenter' ,this.enter, this);
33137 this.el.on('mouseleave', this.leave, this);
33138 this.el.on('click', this.onClick, this);
33141 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33142 this.parent().bricks.push(this);
33147 onClick: function(e, el)
33149 var time = this.endTimer - this.startTimer;
33150 // Roo.log(e.preventDefault());
33153 e.preventDefault();
33158 if(!this.preventDefault){
33162 e.preventDefault();
33164 if (this.activeClass != '') {
33165 this.selectBrick();
33168 this.fireEvent('click', this, e);
33171 enter: function(e, el)
33173 e.preventDefault();
33175 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33179 if(this.bgimage.length && this.html.length){
33180 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33184 leave: function(e, el)
33186 e.preventDefault();
33188 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33192 if(this.bgimage.length && this.html.length){
33193 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33197 onTouchStart: function(e, el)
33199 // e.preventDefault();
33201 this.touchmoved = false;
33203 if(!this.isFitContainer){
33207 if(!this.bgimage.length || !this.html.length){
33211 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33213 this.timer = new Date().getTime();
33217 onTouchMove: function(e, el)
33219 this.touchmoved = true;
33222 onContextMenu : function(e,el)
33224 e.preventDefault();
33225 e.stopPropagation();
33229 onTouchEnd: function(e, el)
33231 // e.preventDefault();
33233 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33240 if(!this.bgimage.length || !this.html.length){
33242 if(this.href.length){
33243 window.location.href = this.href;
33249 if(!this.isFitContainer){
33253 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33255 window.location.href = this.href;
33258 //selection on single brick only
33259 selectBrick : function() {
33261 if (!this.parentId) {
33265 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33266 var index = m.selectedBrick.indexOf(this.id);
33269 m.selectedBrick.splice(index,1);
33270 this.el.removeClass(this.activeClass);
33274 for(var i = 0; i < m.selectedBrick.length; i++) {
33275 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33276 b.el.removeClass(b.activeClass);
33279 m.selectedBrick = [];
33281 m.selectedBrick.push(this.id);
33282 this.el.addClass(this.activeClass);
33286 isSelected : function(){
33287 return this.el.hasClass(this.activeClass);
33292 Roo.apply(Roo.bootstrap.MasonryBrick, {
33295 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33297 * register a Masonry Brick
33298 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33301 register : function(brick)
33303 //this.groups[brick.id] = brick;
33304 this.groups.add(brick.id, brick);
33307 * fetch a masonry brick based on the masonry brick ID
33308 * @param {string} the masonry brick to add
33309 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33312 get: function(brick_id)
33314 // if (typeof(this.groups[brick_id]) == 'undefined') {
33317 // return this.groups[brick_id] ;
33319 if(this.groups.key(brick_id)) {
33320 return this.groups.key(brick_id);
33338 * @class Roo.bootstrap.Brick
33339 * @extends Roo.bootstrap.Component
33340 * Bootstrap Brick class
33343 * Create a new Brick
33344 * @param {Object} config The config object
33347 Roo.bootstrap.Brick = function(config){
33348 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33354 * When a Brick is click
33355 * @param {Roo.bootstrap.Brick} this
33356 * @param {Roo.EventObject} e
33362 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33365 * @cfg {String} title
33369 * @cfg {String} html
33373 * @cfg {String} bgimage
33377 * @cfg {String} cls
33381 * @cfg {String} href
33385 * @cfg {String} video
33389 * @cfg {Boolean} square
33393 getAutoCreate : function()
33395 var cls = 'roo-brick';
33397 if(this.href.length){
33398 cls += ' roo-brick-link';
33401 if(this.bgimage.length){
33402 cls += ' roo-brick-image';
33405 if(!this.html.length && !this.bgimage.length){
33406 cls += ' roo-brick-center-title';
33409 if(!this.html.length && this.bgimage.length){
33410 cls += ' roo-brick-bottom-title';
33414 cls += ' ' + this.cls;
33418 tag: (this.href.length) ? 'a' : 'div',
33423 cls: 'roo-brick-paragraph',
33429 if(this.href.length){
33430 cfg.href = this.href;
33433 var cn = cfg.cn[0].cn;
33435 if(this.title.length){
33438 cls: 'roo-brick-title',
33443 if(this.html.length){
33446 cls: 'roo-brick-text',
33453 if(this.bgimage.length){
33456 cls: 'roo-brick-image-view',
33464 initEvents: function()
33466 if(this.title.length || this.html.length){
33467 this.el.on('mouseenter' ,this.enter, this);
33468 this.el.on('mouseleave', this.leave, this);
33471 Roo.EventManager.onWindowResize(this.resize, this);
33473 if(this.bgimage.length){
33474 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33475 this.imageEl.on('load', this.onImageLoad, this);
33482 onImageLoad : function()
33487 resize : function()
33489 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33491 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33493 if(this.bgimage.length){
33494 var image = this.el.select('.roo-brick-image-view', true).first();
33496 image.setWidth(paragraph.getWidth());
33499 image.setHeight(paragraph.getWidth());
33502 this.el.setHeight(image.getHeight());
33503 paragraph.setHeight(image.getHeight());
33509 enter: function(e, el)
33511 e.preventDefault();
33513 if(this.bgimage.length){
33514 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33515 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33519 leave: function(e, el)
33521 e.preventDefault();
33523 if(this.bgimage.length){
33524 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33525 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33540 * @class Roo.bootstrap.NumberField
33541 * @extends Roo.bootstrap.Input
33542 * Bootstrap NumberField class
33548 * Create a new NumberField
33549 * @param {Object} config The config object
33552 Roo.bootstrap.NumberField = function(config){
33553 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33556 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33559 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33561 allowDecimals : true,
33563 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33565 decimalSeparator : ".",
33567 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33569 decimalPrecision : 2,
33571 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33573 allowNegative : true,
33576 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33580 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33582 minValue : Number.NEGATIVE_INFINITY,
33584 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33586 maxValue : Number.MAX_VALUE,
33588 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33590 minText : "The minimum value for this field is {0}",
33592 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33594 maxText : "The maximum value for this field is {0}",
33596 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33597 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33599 nanText : "{0} is not a valid number",
33601 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33603 thousandsDelimiter : false,
33605 * @cfg {String} valueAlign alignment of value
33607 valueAlign : "left",
33609 getAutoCreate : function()
33611 var hiddenInput = {
33615 cls: 'hidden-number-input'
33619 hiddenInput.name = this.name;
33624 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33626 this.name = hiddenInput.name;
33628 if(cfg.cn.length > 0) {
33629 cfg.cn.push(hiddenInput);
33636 initEvents : function()
33638 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33640 var allowed = "0123456789";
33642 if(this.allowDecimals){
33643 allowed += this.decimalSeparator;
33646 if(this.allowNegative){
33650 if(this.thousandsDelimiter) {
33654 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33656 var keyPress = function(e){
33658 var k = e.getKey();
33660 var c = e.getCharCode();
33663 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33664 allowed.indexOf(String.fromCharCode(c)) === -1
33670 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33674 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33679 this.el.on("keypress", keyPress, this);
33682 validateValue : function(value)
33685 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33689 var num = this.parseValue(value);
33692 this.markInvalid(String.format(this.nanText, value));
33696 if(num < this.minValue){
33697 this.markInvalid(String.format(this.minText, this.minValue));
33701 if(num > this.maxValue){
33702 this.markInvalid(String.format(this.maxText, this.maxValue));
33709 getValue : function()
33711 var v = this.hiddenEl().getValue();
33713 return this.fixPrecision(this.parseValue(v));
33716 parseValue : function(value)
33718 if(this.thousandsDelimiter) {
33720 r = new RegExp(",", "g");
33721 value = value.replace(r, "");
33724 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33725 return isNaN(value) ? '' : value;
33728 fixPrecision : function(value)
33730 if(this.thousandsDelimiter) {
33732 r = new RegExp(",", "g");
33733 value = value.replace(r, "");
33736 var nan = isNaN(value);
33738 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33739 return nan ? '' : value;
33741 return parseFloat(value).toFixed(this.decimalPrecision);
33744 setValue : function(v)
33746 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33752 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33754 this.inputEl().dom.value = (v == '') ? '' :
33755 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33757 if(!this.allowZero && v === '0') {
33758 this.hiddenEl().dom.value = '';
33759 this.inputEl().dom.value = '';
33766 decimalPrecisionFcn : function(v)
33768 return Math.floor(v);
33771 beforeBlur : function()
33773 var v = this.parseValue(this.getRawValue());
33775 if(v || v === 0 || v === ''){
33780 hiddenEl : function()
33782 return this.el.select('input.hidden-number-input',true).first();
33794 * @class Roo.bootstrap.DocumentSlider
33795 * @extends Roo.bootstrap.Component
33796 * Bootstrap DocumentSlider class
33799 * Create a new DocumentViewer
33800 * @param {Object} config The config object
33803 Roo.bootstrap.DocumentSlider = function(config){
33804 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33811 * Fire after initEvent
33812 * @param {Roo.bootstrap.DocumentSlider} this
33817 * Fire after update
33818 * @param {Roo.bootstrap.DocumentSlider} this
33824 * @param {Roo.bootstrap.DocumentSlider} this
33830 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33836 getAutoCreate : function()
33840 cls : 'roo-document-slider',
33844 cls : 'roo-document-slider-header',
33848 cls : 'roo-document-slider-header-title'
33854 cls : 'roo-document-slider-body',
33858 cls : 'roo-document-slider-prev',
33862 cls : 'fa fa-chevron-left'
33868 cls : 'roo-document-slider-thumb',
33872 cls : 'roo-document-slider-image'
33878 cls : 'roo-document-slider-next',
33882 cls : 'fa fa-chevron-right'
33894 initEvents : function()
33896 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33897 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33899 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33900 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33902 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33903 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33905 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33906 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33908 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33909 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33911 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33912 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33914 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33915 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33917 this.thumbEl.on('click', this.onClick, this);
33919 this.prevIndicator.on('click', this.prev, this);
33921 this.nextIndicator.on('click', this.next, this);
33925 initial : function()
33927 if(this.files.length){
33928 this.indicator = 1;
33932 this.fireEvent('initial', this);
33935 update : function()
33937 this.imageEl.attr('src', this.files[this.indicator - 1]);
33939 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33941 this.prevIndicator.show();
33943 if(this.indicator == 1){
33944 this.prevIndicator.hide();
33947 this.nextIndicator.show();
33949 if(this.indicator == this.files.length){
33950 this.nextIndicator.hide();
33953 this.thumbEl.scrollTo('top');
33955 this.fireEvent('update', this);
33958 onClick : function(e)
33960 e.preventDefault();
33962 this.fireEvent('click', this);
33967 e.preventDefault();
33969 this.indicator = Math.max(1, this.indicator - 1);
33976 e.preventDefault();
33978 this.indicator = Math.min(this.files.length, this.indicator + 1);
33992 * @class Roo.bootstrap.RadioSet
33993 * @extends Roo.bootstrap.Input
33994 * Bootstrap RadioSet class
33995 * @cfg {String} indicatorpos (left|right) default left
33996 * @cfg {Boolean} inline (true|false) inline the element (default true)
33997 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
33999 * Create a new RadioSet
34000 * @param {Object} config The config object
34003 Roo.bootstrap.RadioSet = function(config){
34005 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34009 Roo.bootstrap.RadioSet.register(this);
34014 * Fires when the element is checked or unchecked.
34015 * @param {Roo.bootstrap.RadioSet} this This radio
34016 * @param {Roo.bootstrap.Radio} item The checked item
34021 * Fires when the element is click.
34022 * @param {Roo.bootstrap.RadioSet} this This radio set
34023 * @param {Roo.bootstrap.Radio} item The checked item
34024 * @param {Roo.EventObject} e The event object
34031 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34039 indicatorpos : 'left',
34041 getAutoCreate : function()
34045 cls : 'roo-radio-set-label',
34049 html : this.fieldLabel
34054 if(this.indicatorpos == 'left'){
34057 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34058 tooltip : 'This field is required'
34063 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34064 tooltip : 'This field is required'
34070 cls : 'roo-radio-set-items'
34073 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34075 if (align === 'left' && this.fieldLabel.length) {
34078 cls : "roo-radio-set-right",
34084 if(this.labelWidth > 12){
34085 label.style = "width: " + this.labelWidth + 'px';
34088 if(this.labelWidth < 13 && this.labelmd == 0){
34089 this.labelmd = this.labelWidth;
34092 if(this.labellg > 0){
34093 label.cls += ' col-lg-' + this.labellg;
34094 items.cls += ' col-lg-' + (12 - this.labellg);
34097 if(this.labelmd > 0){
34098 label.cls += ' col-md-' + this.labelmd;
34099 items.cls += ' col-md-' + (12 - this.labelmd);
34102 if(this.labelsm > 0){
34103 label.cls += ' col-sm-' + this.labelsm;
34104 items.cls += ' col-sm-' + (12 - this.labelsm);
34107 if(this.labelxs > 0){
34108 label.cls += ' col-xs-' + this.labelxs;
34109 items.cls += ' col-xs-' + (12 - this.labelxs);
34115 cls : 'roo-radio-set',
34119 cls : 'roo-radio-set-input',
34122 value : this.value ? this.value : ''
34129 if(this.weight.length){
34130 cfg.cls += ' roo-radio-' + this.weight;
34134 cfg.cls += ' roo-radio-set-inline';
34138 ['xs','sm','md','lg'].map(function(size){
34139 if (settings[size]) {
34140 cfg.cls += ' col-' + size + '-' + settings[size];
34148 initEvents : function()
34150 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34151 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34153 if(!this.fieldLabel.length){
34154 this.labelEl.hide();
34157 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34158 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34160 this.indicator = this.indicatorEl();
34162 if(this.indicator){
34163 this.indicator.addClass('invisible');
34166 this.originalValue = this.getValue();
34170 inputEl: function ()
34172 return this.el.select('.roo-radio-set-input', true).first();
34175 getChildContainer : function()
34177 return this.itemsEl;
34180 register : function(item)
34182 this.radioes.push(item);
34186 validate : function()
34188 if(this.getVisibilityEl().hasClass('hidden')){
34194 Roo.each(this.radioes, function(i){
34203 if(this.allowBlank) {
34207 if(this.disabled || valid){
34212 this.markInvalid();
34217 markValid : function()
34219 if(this.labelEl.isVisible(true)){
34220 this.indicatorEl().removeClass('visible');
34221 this.indicatorEl().addClass('invisible');
34224 this.el.removeClass([this.invalidClass, this.validClass]);
34225 this.el.addClass(this.validClass);
34227 this.fireEvent('valid', this);
34230 markInvalid : function(msg)
34232 if(this.allowBlank || this.disabled){
34236 if(this.labelEl.isVisible(true)){
34237 this.indicatorEl().removeClass('invisible');
34238 this.indicatorEl().addClass('visible');
34241 this.el.removeClass([this.invalidClass, this.validClass]);
34242 this.el.addClass(this.invalidClass);
34244 this.fireEvent('invalid', this, msg);
34248 setValue : function(v, suppressEvent)
34250 if(this.value === v){
34257 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34260 Roo.each(this.radioes, function(i){
34262 i.el.removeClass('checked');
34265 Roo.each(this.radioes, function(i){
34267 if(i.value === v || i.value.toString() === v.toString()){
34269 i.el.addClass('checked');
34271 if(suppressEvent !== true){
34272 this.fireEvent('check', this, i);
34283 clearInvalid : function(){
34285 if(!this.el || this.preventMark){
34289 this.el.removeClass([this.invalidClass]);
34291 this.fireEvent('valid', this);
34296 Roo.apply(Roo.bootstrap.RadioSet, {
34300 register : function(set)
34302 this.groups[set.name] = set;
34305 get: function(name)
34307 if (typeof(this.groups[name]) == 'undefined') {
34311 return this.groups[name] ;
34317 * Ext JS Library 1.1.1
34318 * Copyright(c) 2006-2007, Ext JS, LLC.
34320 * Originally Released Under LGPL - original licence link has changed is not relivant.
34323 * <script type="text/javascript">
34328 * @class Roo.bootstrap.SplitBar
34329 * @extends Roo.util.Observable
34330 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34334 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34335 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34336 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34337 split.minSize = 100;
34338 split.maxSize = 600;
34339 split.animate = true;
34340 split.on('moved', splitterMoved);
34343 * Create a new SplitBar
34344 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34345 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34346 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34347 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34348 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34349 position of the SplitBar).
34351 Roo.bootstrap.SplitBar = function(cfg){
34356 // dragElement : elm
34357 // resizingElement: el,
34359 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34360 // placement : Roo.bootstrap.SplitBar.LEFT ,
34361 // existingProxy ???
34364 this.el = Roo.get(cfg.dragElement, true);
34365 this.el.dom.unselectable = "on";
34367 this.resizingEl = Roo.get(cfg.resizingElement, true);
34371 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34372 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34375 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34378 * The minimum size of the resizing element. (Defaults to 0)
34384 * The maximum size of the resizing element. (Defaults to 2000)
34387 this.maxSize = 2000;
34390 * Whether to animate the transition to the new size
34393 this.animate = false;
34396 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34399 this.useShim = false;
34404 if(!cfg.existingProxy){
34406 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34408 this.proxy = Roo.get(cfg.existingProxy).dom;
34411 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34414 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34417 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34420 this.dragSpecs = {};
34423 * @private The adapter to use to positon and resize elements
34425 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34426 this.adapter.init(this);
34428 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34430 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34431 this.el.addClass("roo-splitbar-h");
34434 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34435 this.el.addClass("roo-splitbar-v");
34441 * Fires when the splitter is moved (alias for {@link #event-moved})
34442 * @param {Roo.bootstrap.SplitBar} this
34443 * @param {Number} newSize the new width or height
34448 * Fires when the splitter is moved
34449 * @param {Roo.bootstrap.SplitBar} this
34450 * @param {Number} newSize the new width or height
34454 * @event beforeresize
34455 * Fires before the splitter is dragged
34456 * @param {Roo.bootstrap.SplitBar} this
34458 "beforeresize" : true,
34460 "beforeapply" : true
34463 Roo.util.Observable.call(this);
34466 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34467 onStartProxyDrag : function(x, y){
34468 this.fireEvent("beforeresize", this);
34470 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34472 o.enableDisplayMode("block");
34473 // all splitbars share the same overlay
34474 Roo.bootstrap.SplitBar.prototype.overlay = o;
34476 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34477 this.overlay.show();
34478 Roo.get(this.proxy).setDisplayed("block");
34479 var size = this.adapter.getElementSize(this);
34480 this.activeMinSize = this.getMinimumSize();;
34481 this.activeMaxSize = this.getMaximumSize();;
34482 var c1 = size - this.activeMinSize;
34483 var c2 = Math.max(this.activeMaxSize - size, 0);
34484 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34485 this.dd.resetConstraints();
34486 this.dd.setXConstraint(
34487 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34488 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34490 this.dd.setYConstraint(0, 0);
34492 this.dd.resetConstraints();
34493 this.dd.setXConstraint(0, 0);
34494 this.dd.setYConstraint(
34495 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34496 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34499 this.dragSpecs.startSize = size;
34500 this.dragSpecs.startPoint = [x, y];
34501 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34505 * @private Called after the drag operation by the DDProxy
34507 onEndProxyDrag : function(e){
34508 Roo.get(this.proxy).setDisplayed(false);
34509 var endPoint = Roo.lib.Event.getXY(e);
34511 this.overlay.hide();
34514 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34515 newSize = this.dragSpecs.startSize +
34516 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34517 endPoint[0] - this.dragSpecs.startPoint[0] :
34518 this.dragSpecs.startPoint[0] - endPoint[0]
34521 newSize = this.dragSpecs.startSize +
34522 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34523 endPoint[1] - this.dragSpecs.startPoint[1] :
34524 this.dragSpecs.startPoint[1] - endPoint[1]
34527 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34528 if(newSize != this.dragSpecs.startSize){
34529 if(this.fireEvent('beforeapply', this, newSize) !== false){
34530 this.adapter.setElementSize(this, newSize);
34531 this.fireEvent("moved", this, newSize);
34532 this.fireEvent("resize", this, newSize);
34538 * Get the adapter this SplitBar uses
34539 * @return The adapter object
34541 getAdapter : function(){
34542 return this.adapter;
34546 * Set the adapter this SplitBar uses
34547 * @param {Object} adapter A SplitBar adapter object
34549 setAdapter : function(adapter){
34550 this.adapter = adapter;
34551 this.adapter.init(this);
34555 * Gets the minimum size for the resizing element
34556 * @return {Number} The minimum size
34558 getMinimumSize : function(){
34559 return this.minSize;
34563 * Sets the minimum size for the resizing element
34564 * @param {Number} minSize The minimum size
34566 setMinimumSize : function(minSize){
34567 this.minSize = minSize;
34571 * Gets the maximum size for the resizing element
34572 * @return {Number} The maximum size
34574 getMaximumSize : function(){
34575 return this.maxSize;
34579 * Sets the maximum size for the resizing element
34580 * @param {Number} maxSize The maximum size
34582 setMaximumSize : function(maxSize){
34583 this.maxSize = maxSize;
34587 * Sets the initialize size for the resizing element
34588 * @param {Number} size The initial size
34590 setCurrentSize : function(size){
34591 var oldAnimate = this.animate;
34592 this.animate = false;
34593 this.adapter.setElementSize(this, size);
34594 this.animate = oldAnimate;
34598 * Destroy this splitbar.
34599 * @param {Boolean} removeEl True to remove the element
34601 destroy : function(removeEl){
34603 this.shim.remove();
34606 this.proxy.parentNode.removeChild(this.proxy);
34614 * @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.
34616 Roo.bootstrap.SplitBar.createProxy = function(dir){
34617 var proxy = new Roo.Element(document.createElement("div"));
34618 proxy.unselectable();
34619 var cls = 'roo-splitbar-proxy';
34620 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34621 document.body.appendChild(proxy.dom);
34626 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34627 * Default Adapter. It assumes the splitter and resizing element are not positioned
34628 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34630 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34633 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34634 // do nothing for now
34635 init : function(s){
34639 * Called before drag operations to get the current size of the resizing element.
34640 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34642 getElementSize : function(s){
34643 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34644 return s.resizingEl.getWidth();
34646 return s.resizingEl.getHeight();
34651 * Called after drag operations to set the size of the resizing element.
34652 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34653 * @param {Number} newSize The new size to set
34654 * @param {Function} onComplete A function to be invoked when resizing is complete
34656 setElementSize : function(s, newSize, onComplete){
34657 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34659 s.resizingEl.setWidth(newSize);
34661 onComplete(s, newSize);
34664 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34669 s.resizingEl.setHeight(newSize);
34671 onComplete(s, newSize);
34674 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34681 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34682 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34683 * Adapter that moves the splitter element to align with the resized sizing element.
34684 * Used with an absolute positioned SplitBar.
34685 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34686 * document.body, make sure you assign an id to the body element.
34688 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34689 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34690 this.container = Roo.get(container);
34693 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34694 init : function(s){
34695 this.basic.init(s);
34698 getElementSize : function(s){
34699 return this.basic.getElementSize(s);
34702 setElementSize : function(s, newSize, onComplete){
34703 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34706 moveSplitter : function(s){
34707 var yes = Roo.bootstrap.SplitBar;
34708 switch(s.placement){
34710 s.el.setX(s.resizingEl.getRight());
34713 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34716 s.el.setY(s.resizingEl.getBottom());
34719 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34726 * Orientation constant - Create a vertical SplitBar
34730 Roo.bootstrap.SplitBar.VERTICAL = 1;
34733 * Orientation constant - Create a horizontal SplitBar
34737 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34740 * Placement constant - The resizing element is to the left of the splitter element
34744 Roo.bootstrap.SplitBar.LEFT = 1;
34747 * Placement constant - The resizing element is to the right of the splitter element
34751 Roo.bootstrap.SplitBar.RIGHT = 2;
34754 * Placement constant - The resizing element is positioned above the splitter element
34758 Roo.bootstrap.SplitBar.TOP = 3;
34761 * Placement constant - The resizing element is positioned under splitter element
34765 Roo.bootstrap.SplitBar.BOTTOM = 4;
34766 Roo.namespace("Roo.bootstrap.layout");/*
34768 * Ext JS Library 1.1.1
34769 * Copyright(c) 2006-2007, Ext JS, LLC.
34771 * Originally Released Under LGPL - original licence link has changed is not relivant.
34774 * <script type="text/javascript">
34778 * @class Roo.bootstrap.layout.Manager
34779 * @extends Roo.bootstrap.Component
34780 * Base class for layout managers.
34782 Roo.bootstrap.layout.Manager = function(config)
34784 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34790 /** false to disable window resize monitoring @type Boolean */
34791 this.monitorWindowResize = true;
34796 * Fires when a layout is performed.
34797 * @param {Roo.LayoutManager} this
34801 * @event regionresized
34802 * Fires when the user resizes a region.
34803 * @param {Roo.LayoutRegion} region The resized region
34804 * @param {Number} newSize The new size (width for east/west, height for north/south)
34806 "regionresized" : true,
34808 * @event regioncollapsed
34809 * Fires when a region is collapsed.
34810 * @param {Roo.LayoutRegion} region The collapsed region
34812 "regioncollapsed" : true,
34814 * @event regionexpanded
34815 * Fires when a region is expanded.
34816 * @param {Roo.LayoutRegion} region The expanded region
34818 "regionexpanded" : true
34820 this.updating = false;
34823 this.el = Roo.get(config.el);
34829 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34834 monitorWindowResize : true,
34840 onRender : function(ct, position)
34843 this.el = Roo.get(ct);
34846 //this.fireEvent('render',this);
34850 initEvents: function()
34854 // ie scrollbar fix
34855 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34856 document.body.scroll = "no";
34857 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34858 this.el.position('relative');
34860 this.id = this.el.id;
34861 this.el.addClass("roo-layout-container");
34862 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34863 if(this.el.dom != document.body ) {
34864 this.el.on('resize', this.layout,this);
34865 this.el.on('show', this.layout,this);
34871 * Returns true if this layout is currently being updated
34872 * @return {Boolean}
34874 isUpdating : function(){
34875 return this.updating;
34879 * Suspend the LayoutManager from doing auto-layouts while
34880 * making multiple add or remove calls
34882 beginUpdate : function(){
34883 this.updating = true;
34887 * Restore auto-layouts and optionally disable the manager from performing a layout
34888 * @param {Boolean} noLayout true to disable a layout update
34890 endUpdate : function(noLayout){
34891 this.updating = false;
34897 layout: function(){
34901 onRegionResized : function(region, newSize){
34902 this.fireEvent("regionresized", region, newSize);
34906 onRegionCollapsed : function(region){
34907 this.fireEvent("regioncollapsed", region);
34910 onRegionExpanded : function(region){
34911 this.fireEvent("regionexpanded", region);
34915 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34916 * performs box-model adjustments.
34917 * @return {Object} The size as an object {width: (the width), height: (the height)}
34919 getViewSize : function()
34922 if(this.el.dom != document.body){
34923 size = this.el.getSize();
34925 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34927 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34928 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34933 * Returns the Element this layout is bound to.
34934 * @return {Roo.Element}
34936 getEl : function(){
34941 * Returns the specified region.
34942 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34943 * @return {Roo.LayoutRegion}
34945 getRegion : function(target){
34946 return this.regions[target.toLowerCase()];
34949 onWindowResize : function(){
34950 if(this.monitorWindowResize){
34957 * Ext JS Library 1.1.1
34958 * Copyright(c) 2006-2007, Ext JS, LLC.
34960 * Originally Released Under LGPL - original licence link has changed is not relivant.
34963 * <script type="text/javascript">
34966 * @class Roo.bootstrap.layout.Border
34967 * @extends Roo.bootstrap.layout.Manager
34968 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34969 * please see: examples/bootstrap/nested.html<br><br>
34971 <b>The container the layout is rendered into can be either the body element or any other element.
34972 If it is not the body element, the container needs to either be an absolute positioned element,
34973 or you will need to add "position:relative" to the css of the container. You will also need to specify
34974 the container size if it is not the body element.</b>
34977 * Create a new Border
34978 * @param {Object} config Configuration options
34980 Roo.bootstrap.layout.Border = function(config){
34981 config = config || {};
34982 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
34986 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
34987 if(config[region]){
34988 config[region].region = region;
34989 this.addRegion(config[region]);
34995 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
34997 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
34999 * Creates and adds a new region if it doesn't already exist.
35000 * @param {String} target The target region key (north, south, east, west or center).
35001 * @param {Object} config The regions config object
35002 * @return {BorderLayoutRegion} The new region
35004 addRegion : function(config)
35006 if(!this.regions[config.region]){
35007 var r = this.factory(config);
35008 this.bindRegion(r);
35010 return this.regions[config.region];
35014 bindRegion : function(r){
35015 this.regions[r.config.region] = r;
35017 r.on("visibilitychange", this.layout, this);
35018 r.on("paneladded", this.layout, this);
35019 r.on("panelremoved", this.layout, this);
35020 r.on("invalidated", this.layout, this);
35021 r.on("resized", this.onRegionResized, this);
35022 r.on("collapsed", this.onRegionCollapsed, this);
35023 r.on("expanded", this.onRegionExpanded, this);
35027 * Performs a layout update.
35029 layout : function()
35031 if(this.updating) {
35035 // render all the rebions if they have not been done alreayd?
35036 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35037 if(this.regions[region] && !this.regions[region].bodyEl){
35038 this.regions[region].onRender(this.el)
35042 var size = this.getViewSize();
35043 var w = size.width;
35044 var h = size.height;
35049 //var x = 0, y = 0;
35051 var rs = this.regions;
35052 var north = rs["north"];
35053 var south = rs["south"];
35054 var west = rs["west"];
35055 var east = rs["east"];
35056 var center = rs["center"];
35057 //if(this.hideOnLayout){ // not supported anymore
35058 //c.el.setStyle("display", "none");
35060 if(north && north.isVisible()){
35061 var b = north.getBox();
35062 var m = north.getMargins();
35063 b.width = w - (m.left+m.right);
35066 centerY = b.height + b.y + m.bottom;
35067 centerH -= centerY;
35068 north.updateBox(this.safeBox(b));
35070 if(south && south.isVisible()){
35071 var b = south.getBox();
35072 var m = south.getMargins();
35073 b.width = w - (m.left+m.right);
35075 var totalHeight = (b.height + m.top + m.bottom);
35076 b.y = h - totalHeight + m.top;
35077 centerH -= totalHeight;
35078 south.updateBox(this.safeBox(b));
35080 if(west && west.isVisible()){
35081 var b = west.getBox();
35082 var m = west.getMargins();
35083 b.height = centerH - (m.top+m.bottom);
35085 b.y = centerY + m.top;
35086 var totalWidth = (b.width + m.left + m.right);
35087 centerX += totalWidth;
35088 centerW -= totalWidth;
35089 west.updateBox(this.safeBox(b));
35091 if(east && east.isVisible()){
35092 var b = east.getBox();
35093 var m = east.getMargins();
35094 b.height = centerH - (m.top+m.bottom);
35095 var totalWidth = (b.width + m.left + m.right);
35096 b.x = w - totalWidth + m.left;
35097 b.y = centerY + m.top;
35098 centerW -= totalWidth;
35099 east.updateBox(this.safeBox(b));
35102 var m = center.getMargins();
35104 x: centerX + m.left,
35105 y: centerY + m.top,
35106 width: centerW - (m.left+m.right),
35107 height: centerH - (m.top+m.bottom)
35109 //if(this.hideOnLayout){
35110 //center.el.setStyle("display", "block");
35112 center.updateBox(this.safeBox(centerBox));
35115 this.fireEvent("layout", this);
35119 safeBox : function(box){
35120 box.width = Math.max(0, box.width);
35121 box.height = Math.max(0, box.height);
35126 * Adds a ContentPanel (or subclass) to this layout.
35127 * @param {String} target The target region key (north, south, east, west or center).
35128 * @param {Roo.ContentPanel} panel The panel to add
35129 * @return {Roo.ContentPanel} The added panel
35131 add : function(target, panel){
35133 target = target.toLowerCase();
35134 return this.regions[target].add(panel);
35138 * Remove a ContentPanel (or subclass) to this layout.
35139 * @param {String} target The target region key (north, south, east, west or center).
35140 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35141 * @return {Roo.ContentPanel} The removed panel
35143 remove : function(target, panel){
35144 target = target.toLowerCase();
35145 return this.regions[target].remove(panel);
35149 * Searches all regions for a panel with the specified id
35150 * @param {String} panelId
35151 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35153 findPanel : function(panelId){
35154 var rs = this.regions;
35155 for(var target in rs){
35156 if(typeof rs[target] != "function"){
35157 var p = rs[target].getPanel(panelId);
35167 * Searches all regions for a panel with the specified id and activates (shows) it.
35168 * @param {String/ContentPanel} panelId The panels id or the panel itself
35169 * @return {Roo.ContentPanel} The shown panel or null
35171 showPanel : function(panelId) {
35172 var rs = this.regions;
35173 for(var target in rs){
35174 var r = rs[target];
35175 if(typeof r != "function"){
35176 if(r.hasPanel(panelId)){
35177 return r.showPanel(panelId);
35185 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35186 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35189 restoreState : function(provider){
35191 provider = Roo.state.Manager;
35193 var sm = new Roo.LayoutStateManager();
35194 sm.init(this, provider);
35200 * Adds a xtype elements to the layout.
35204 xtype : 'ContentPanel',
35211 xtype : 'NestedLayoutPanel',
35217 items : [ ... list of content panels or nested layout panels.. ]
35221 * @param {Object} cfg Xtype definition of item to add.
35223 addxtype : function(cfg)
35225 // basically accepts a pannel...
35226 // can accept a layout region..!?!?
35227 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35230 // theory? children can only be panels??
35232 //if (!cfg.xtype.match(/Panel$/)) {
35237 if (typeof(cfg.region) == 'undefined') {
35238 Roo.log("Failed to add Panel, region was not set");
35242 var region = cfg.region;
35248 xitems = cfg.items;
35255 case 'Content': // ContentPanel (el, cfg)
35256 case 'Scroll': // ContentPanel (el, cfg)
35258 cfg.autoCreate = true;
35259 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35261 // var el = this.el.createChild();
35262 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35265 this.add(region, ret);
35269 case 'TreePanel': // our new panel!
35270 cfg.el = this.el.createChild();
35271 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35272 this.add(region, ret);
35277 // create a new Layout (which is a Border Layout...
35279 var clayout = cfg.layout;
35280 clayout.el = this.el.createChild();
35281 clayout.items = clayout.items || [];
35285 // replace this exitems with the clayout ones..
35286 xitems = clayout.items;
35288 // force background off if it's in center...
35289 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35290 cfg.background = false;
35292 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35295 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35296 //console.log('adding nested layout panel ' + cfg.toSource());
35297 this.add(region, ret);
35298 nb = {}; /// find first...
35303 // needs grid and region
35305 //var el = this.getRegion(region).el.createChild();
35307 *var el = this.el.createChild();
35308 // create the grid first...
35309 cfg.grid.container = el;
35310 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35313 if (region == 'center' && this.active ) {
35314 cfg.background = false;
35317 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35319 this.add(region, ret);
35321 if (cfg.background) {
35322 // render grid on panel activation (if panel background)
35323 ret.on('activate', function(gp) {
35324 if (!gp.grid.rendered) {
35325 // gp.grid.render(el);
35329 // cfg.grid.render(el);
35335 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35336 // it was the old xcomponent building that caused this before.
35337 // espeically if border is the top element in the tree.
35347 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35349 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35350 this.add(region, ret);
35354 throw "Can not add '" + cfg.xtype + "' to Border";
35360 this.beginUpdate();
35364 Roo.each(xitems, function(i) {
35365 region = nb && i.region ? i.region : false;
35367 var add = ret.addxtype(i);
35370 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35371 if (!i.background) {
35372 abn[region] = nb[region] ;
35379 // make the last non-background panel active..
35380 //if (nb) { Roo.log(abn); }
35383 for(var r in abn) {
35384 region = this.getRegion(r);
35386 // tried using nb[r], but it does not work..
35388 region.showPanel(abn[r]);
35399 factory : function(cfg)
35402 var validRegions = Roo.bootstrap.layout.Border.regions;
35404 var target = cfg.region;
35407 var r = Roo.bootstrap.layout;
35411 return new r.North(cfg);
35413 return new r.South(cfg);
35415 return new r.East(cfg);
35417 return new r.West(cfg);
35419 return new r.Center(cfg);
35421 throw 'Layout region "'+target+'" not supported.';
35428 * Ext JS Library 1.1.1
35429 * Copyright(c) 2006-2007, Ext JS, LLC.
35431 * Originally Released Under LGPL - original licence link has changed is not relivant.
35434 * <script type="text/javascript">
35438 * @class Roo.bootstrap.layout.Basic
35439 * @extends Roo.util.Observable
35440 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35441 * and does not have a titlebar, tabs or any other features. All it does is size and position
35442 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35443 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35444 * @cfg {string} region the region that it inhabits..
35445 * @cfg {bool} skipConfig skip config?
35449 Roo.bootstrap.layout.Basic = function(config){
35451 this.mgr = config.mgr;
35453 this.position = config.region;
35455 var skipConfig = config.skipConfig;
35459 * @scope Roo.BasicLayoutRegion
35463 * @event beforeremove
35464 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35465 * @param {Roo.LayoutRegion} this
35466 * @param {Roo.ContentPanel} panel The panel
35467 * @param {Object} e The cancel event object
35469 "beforeremove" : true,
35471 * @event invalidated
35472 * Fires when the layout for this region is changed.
35473 * @param {Roo.LayoutRegion} this
35475 "invalidated" : true,
35477 * @event visibilitychange
35478 * Fires when this region is shown or hidden
35479 * @param {Roo.LayoutRegion} this
35480 * @param {Boolean} visibility true or false
35482 "visibilitychange" : true,
35484 * @event paneladded
35485 * Fires when a panel is added.
35486 * @param {Roo.LayoutRegion} this
35487 * @param {Roo.ContentPanel} panel The panel
35489 "paneladded" : true,
35491 * @event panelremoved
35492 * Fires when a panel is removed.
35493 * @param {Roo.LayoutRegion} this
35494 * @param {Roo.ContentPanel} panel The panel
35496 "panelremoved" : true,
35498 * @event beforecollapse
35499 * Fires when this region before collapse.
35500 * @param {Roo.LayoutRegion} this
35502 "beforecollapse" : true,
35505 * Fires when this region is collapsed.
35506 * @param {Roo.LayoutRegion} this
35508 "collapsed" : true,
35511 * Fires when this region is expanded.
35512 * @param {Roo.LayoutRegion} this
35517 * Fires when this region is slid into view.
35518 * @param {Roo.LayoutRegion} this
35520 "slideshow" : true,
35523 * Fires when this region slides out of view.
35524 * @param {Roo.LayoutRegion} this
35526 "slidehide" : true,
35528 * @event panelactivated
35529 * Fires when a panel is activated.
35530 * @param {Roo.LayoutRegion} this
35531 * @param {Roo.ContentPanel} panel The activated panel
35533 "panelactivated" : true,
35536 * Fires when the user resizes this region.
35537 * @param {Roo.LayoutRegion} this
35538 * @param {Number} newSize The new size (width for east/west, height for north/south)
35542 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35543 this.panels = new Roo.util.MixedCollection();
35544 this.panels.getKey = this.getPanelId.createDelegate(this);
35546 this.activePanel = null;
35547 // ensure listeners are added...
35549 if (config.listeners || config.events) {
35550 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35551 listeners : config.listeners || {},
35552 events : config.events || {}
35556 if(skipConfig !== true){
35557 this.applyConfig(config);
35561 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35563 getPanelId : function(p){
35567 applyConfig : function(config){
35568 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35569 this.config = config;
35574 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35575 * the width, for horizontal (north, south) the height.
35576 * @param {Number} newSize The new width or height
35578 resizeTo : function(newSize){
35579 var el = this.el ? this.el :
35580 (this.activePanel ? this.activePanel.getEl() : null);
35582 switch(this.position){
35585 el.setWidth(newSize);
35586 this.fireEvent("resized", this, newSize);
35590 el.setHeight(newSize);
35591 this.fireEvent("resized", this, newSize);
35597 getBox : function(){
35598 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35601 getMargins : function(){
35602 return this.margins;
35605 updateBox : function(box){
35607 var el = this.activePanel.getEl();
35608 el.dom.style.left = box.x + "px";
35609 el.dom.style.top = box.y + "px";
35610 this.activePanel.setSize(box.width, box.height);
35614 * Returns the container element for this region.
35615 * @return {Roo.Element}
35617 getEl : function(){
35618 return this.activePanel;
35622 * Returns true if this region is currently visible.
35623 * @return {Boolean}
35625 isVisible : function(){
35626 return this.activePanel ? true : false;
35629 setActivePanel : function(panel){
35630 panel = this.getPanel(panel);
35631 if(this.activePanel && this.activePanel != panel){
35632 this.activePanel.setActiveState(false);
35633 this.activePanel.getEl().setLeftTop(-10000,-10000);
35635 this.activePanel = panel;
35636 panel.setActiveState(true);
35638 panel.setSize(this.box.width, this.box.height);
35640 this.fireEvent("panelactivated", this, panel);
35641 this.fireEvent("invalidated");
35645 * Show the specified panel.
35646 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35647 * @return {Roo.ContentPanel} The shown panel or null
35649 showPanel : function(panel){
35650 panel = this.getPanel(panel);
35652 this.setActivePanel(panel);
35658 * Get the active panel for this region.
35659 * @return {Roo.ContentPanel} The active panel or null
35661 getActivePanel : function(){
35662 return this.activePanel;
35666 * Add the passed ContentPanel(s)
35667 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35668 * @return {Roo.ContentPanel} The panel added (if only one was added)
35670 add : function(panel){
35671 if(arguments.length > 1){
35672 for(var i = 0, len = arguments.length; i < len; i++) {
35673 this.add(arguments[i]);
35677 if(this.hasPanel(panel)){
35678 this.showPanel(panel);
35681 var el = panel.getEl();
35682 if(el.dom.parentNode != this.mgr.el.dom){
35683 this.mgr.el.dom.appendChild(el.dom);
35685 if(panel.setRegion){
35686 panel.setRegion(this);
35688 this.panels.add(panel);
35689 el.setStyle("position", "absolute");
35690 if(!panel.background){
35691 this.setActivePanel(panel);
35692 if(this.config.initialSize && this.panels.getCount()==1){
35693 this.resizeTo(this.config.initialSize);
35696 this.fireEvent("paneladded", this, panel);
35701 * Returns true if the panel is in this region.
35702 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35703 * @return {Boolean}
35705 hasPanel : function(panel){
35706 if(typeof panel == "object"){ // must be panel obj
35707 panel = panel.getId();
35709 return this.getPanel(panel) ? true : false;
35713 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35714 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35715 * @param {Boolean} preservePanel Overrides the config preservePanel option
35716 * @return {Roo.ContentPanel} The panel that was removed
35718 remove : function(panel, preservePanel){
35719 panel = this.getPanel(panel);
35724 this.fireEvent("beforeremove", this, panel, e);
35725 if(e.cancel === true){
35728 var panelId = panel.getId();
35729 this.panels.removeKey(panelId);
35734 * Returns the panel specified or null if it's not in this region.
35735 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35736 * @return {Roo.ContentPanel}
35738 getPanel : function(id){
35739 if(typeof id == "object"){ // must be panel obj
35742 return this.panels.get(id);
35746 * Returns this regions position (north/south/east/west/center).
35749 getPosition: function(){
35750 return this.position;
35754 * Ext JS Library 1.1.1
35755 * Copyright(c) 2006-2007, Ext JS, LLC.
35757 * Originally Released Under LGPL - original licence link has changed is not relivant.
35760 * <script type="text/javascript">
35764 * @class Roo.bootstrap.layout.Region
35765 * @extends Roo.bootstrap.layout.Basic
35766 * This class represents a region in a layout manager.
35768 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35769 * @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})
35770 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35771 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35772 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35773 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35774 * @cfg {String} title The title for the region (overrides panel titles)
35775 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35776 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35777 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35778 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35779 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35780 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35781 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35782 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35783 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35784 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35786 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35787 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35788 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35789 * @cfg {Number} width For East/West panels
35790 * @cfg {Number} height For North/South panels
35791 * @cfg {Boolean} split To show the splitter
35792 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35794 * @cfg {string} cls Extra CSS classes to add to region
35796 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35797 * @cfg {string} region the region that it inhabits..
35800 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35801 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35803 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35804 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35805 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35807 Roo.bootstrap.layout.Region = function(config)
35809 this.applyConfig(config);
35811 var mgr = config.mgr;
35812 var pos = config.region;
35813 config.skipConfig = true;
35814 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35817 this.onRender(mgr.el);
35820 this.visible = true;
35821 this.collapsed = false;
35822 this.unrendered_panels = [];
35825 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35827 position: '', // set by wrapper (eg. north/south etc..)
35828 unrendered_panels : null, // unrendered panels.
35829 createBody : function(){
35830 /** This region's body element
35831 * @type Roo.Element */
35832 this.bodyEl = this.el.createChild({
35834 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35838 onRender: function(ctr, pos)
35840 var dh = Roo.DomHelper;
35841 /** This region's container element
35842 * @type Roo.Element */
35843 this.el = dh.append(ctr.dom, {
35845 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35847 /** This region's title element
35848 * @type Roo.Element */
35850 this.titleEl = dh.append(this.el.dom,
35853 unselectable: "on",
35854 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35856 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35857 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35860 this.titleEl.enableDisplayMode();
35861 /** This region's title text element
35862 * @type HTMLElement */
35863 this.titleTextEl = this.titleEl.dom.firstChild;
35864 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35866 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35867 this.closeBtn.enableDisplayMode();
35868 this.closeBtn.on("click", this.closeClicked, this);
35869 this.closeBtn.hide();
35871 this.createBody(this.config);
35872 if(this.config.hideWhenEmpty){
35874 this.on("paneladded", this.validateVisibility, this);
35875 this.on("panelremoved", this.validateVisibility, this);
35877 if(this.autoScroll){
35878 this.bodyEl.setStyle("overflow", "auto");
35880 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35882 //if(c.titlebar !== false){
35883 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35884 this.titleEl.hide();
35886 this.titleEl.show();
35887 if(this.config.title){
35888 this.titleTextEl.innerHTML = this.config.title;
35892 if(this.config.collapsed){
35893 this.collapse(true);
35895 if(this.config.hidden){
35899 if (this.unrendered_panels && this.unrendered_panels.length) {
35900 for (var i =0;i< this.unrendered_panels.length; i++) {
35901 this.add(this.unrendered_panels[i]);
35903 this.unrendered_panels = null;
35909 applyConfig : function(c)
35912 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35913 var dh = Roo.DomHelper;
35914 if(c.titlebar !== false){
35915 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35916 this.collapseBtn.on("click", this.collapse, this);
35917 this.collapseBtn.enableDisplayMode();
35919 if(c.showPin === true || this.showPin){
35920 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35921 this.stickBtn.enableDisplayMode();
35922 this.stickBtn.on("click", this.expand, this);
35923 this.stickBtn.hide();
35928 /** This region's collapsed element
35929 * @type Roo.Element */
35932 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35933 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35936 if(c.floatable !== false){
35937 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35938 this.collapsedEl.on("click", this.collapseClick, this);
35941 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35942 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35943 id: "message", unselectable: "on", style:{"float":"left"}});
35944 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35946 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35947 this.expandBtn.on("click", this.expand, this);
35951 if(this.collapseBtn){
35952 this.collapseBtn.setVisible(c.collapsible == true);
35955 this.cmargins = c.cmargins || this.cmargins ||
35956 (this.position == "west" || this.position == "east" ?
35957 {top: 0, left: 2, right:2, bottom: 0} :
35958 {top: 2, left: 0, right:0, bottom: 2});
35960 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35963 this.bottomTabs = c.tabPosition != "top";
35965 this.autoScroll = c.autoScroll || false;
35970 this.duration = c.duration || .30;
35971 this.slideDuration = c.slideDuration || .45;
35976 * Returns true if this region is currently visible.
35977 * @return {Boolean}
35979 isVisible : function(){
35980 return this.visible;
35984 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
35985 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
35987 //setCollapsedTitle : function(title){
35988 // title = title || " ";
35989 // if(this.collapsedTitleTextEl){
35990 // this.collapsedTitleTextEl.innerHTML = title;
35994 getBox : function(){
35996 // if(!this.collapsed){
35997 b = this.el.getBox(false, true);
35999 // b = this.collapsedEl.getBox(false, true);
36004 getMargins : function(){
36005 return this.margins;
36006 //return this.collapsed ? this.cmargins : this.margins;
36009 highlight : function(){
36010 this.el.addClass("x-layout-panel-dragover");
36013 unhighlight : function(){
36014 this.el.removeClass("x-layout-panel-dragover");
36017 updateBox : function(box)
36019 if (!this.bodyEl) {
36020 return; // not rendered yet..
36024 if(!this.collapsed){
36025 this.el.dom.style.left = box.x + "px";
36026 this.el.dom.style.top = box.y + "px";
36027 this.updateBody(box.width, box.height);
36029 this.collapsedEl.dom.style.left = box.x + "px";
36030 this.collapsedEl.dom.style.top = box.y + "px";
36031 this.collapsedEl.setSize(box.width, box.height);
36034 this.tabs.autoSizeTabs();
36038 updateBody : function(w, h)
36041 this.el.setWidth(w);
36042 w -= this.el.getBorderWidth("rl");
36043 if(this.config.adjustments){
36044 w += this.config.adjustments[0];
36047 if(h !== null && h > 0){
36048 this.el.setHeight(h);
36049 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36050 h -= this.el.getBorderWidth("tb");
36051 if(this.config.adjustments){
36052 h += this.config.adjustments[1];
36054 this.bodyEl.setHeight(h);
36056 h = this.tabs.syncHeight(h);
36059 if(this.panelSize){
36060 w = w !== null ? w : this.panelSize.width;
36061 h = h !== null ? h : this.panelSize.height;
36063 if(this.activePanel){
36064 var el = this.activePanel.getEl();
36065 w = w !== null ? w : el.getWidth();
36066 h = h !== null ? h : el.getHeight();
36067 this.panelSize = {width: w, height: h};
36068 this.activePanel.setSize(w, h);
36070 if(Roo.isIE && this.tabs){
36071 this.tabs.el.repaint();
36076 * Returns the container element for this region.
36077 * @return {Roo.Element}
36079 getEl : function(){
36084 * Hides this region.
36087 //if(!this.collapsed){
36088 this.el.dom.style.left = "-2000px";
36091 // this.collapsedEl.dom.style.left = "-2000px";
36092 // this.collapsedEl.hide();
36094 this.visible = false;
36095 this.fireEvent("visibilitychange", this, false);
36099 * Shows this region if it was previously hidden.
36102 //if(!this.collapsed){
36105 // this.collapsedEl.show();
36107 this.visible = true;
36108 this.fireEvent("visibilitychange", this, true);
36111 closeClicked : function(){
36112 if(this.activePanel){
36113 this.remove(this.activePanel);
36117 collapseClick : function(e){
36119 e.stopPropagation();
36122 e.stopPropagation();
36128 * Collapses this region.
36129 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36132 collapse : function(skipAnim, skipCheck = false){
36133 if(this.collapsed) {
36137 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36139 this.collapsed = true;
36141 this.split.el.hide();
36143 if(this.config.animate && skipAnim !== true){
36144 this.fireEvent("invalidated", this);
36145 this.animateCollapse();
36147 this.el.setLocation(-20000,-20000);
36149 this.collapsedEl.show();
36150 this.fireEvent("collapsed", this);
36151 this.fireEvent("invalidated", this);
36157 animateCollapse : function(){
36162 * Expands this region if it was previously collapsed.
36163 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36164 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36167 expand : function(e, skipAnim){
36169 e.stopPropagation();
36171 if(!this.collapsed || this.el.hasActiveFx()) {
36175 this.afterSlideIn();
36178 this.collapsed = false;
36179 if(this.config.animate && skipAnim !== true){
36180 this.animateExpand();
36184 this.split.el.show();
36186 this.collapsedEl.setLocation(-2000,-2000);
36187 this.collapsedEl.hide();
36188 this.fireEvent("invalidated", this);
36189 this.fireEvent("expanded", this);
36193 animateExpand : function(){
36197 initTabs : function()
36199 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36201 var ts = new Roo.bootstrap.panel.Tabs({
36202 el: this.bodyEl.dom,
36203 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36204 disableTooltips: this.config.disableTabTips,
36205 toolbar : this.config.toolbar
36208 if(this.config.hideTabs){
36209 ts.stripWrap.setDisplayed(false);
36212 ts.resizeTabs = this.config.resizeTabs === true;
36213 ts.minTabWidth = this.config.minTabWidth || 40;
36214 ts.maxTabWidth = this.config.maxTabWidth || 250;
36215 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36216 ts.monitorResize = false;
36217 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36218 ts.bodyEl.addClass('roo-layout-tabs-body');
36219 this.panels.each(this.initPanelAsTab, this);
36222 initPanelAsTab : function(panel){
36223 var ti = this.tabs.addTab(
36227 this.config.closeOnTab && panel.isClosable(),
36230 if(panel.tabTip !== undefined){
36231 ti.setTooltip(panel.tabTip);
36233 ti.on("activate", function(){
36234 this.setActivePanel(panel);
36237 if(this.config.closeOnTab){
36238 ti.on("beforeclose", function(t, e){
36240 this.remove(panel);
36244 panel.tabItem = ti;
36249 updatePanelTitle : function(panel, title)
36251 if(this.activePanel == panel){
36252 this.updateTitle(title);
36255 var ti = this.tabs.getTab(panel.getEl().id);
36257 if(panel.tabTip !== undefined){
36258 ti.setTooltip(panel.tabTip);
36263 updateTitle : function(title){
36264 if(this.titleTextEl && !this.config.title){
36265 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36269 setActivePanel : function(panel)
36271 panel = this.getPanel(panel);
36272 if(this.activePanel && this.activePanel != panel){
36273 if(this.activePanel.setActiveState(false) === false){
36277 this.activePanel = panel;
36278 panel.setActiveState(true);
36279 if(this.panelSize){
36280 panel.setSize(this.panelSize.width, this.panelSize.height);
36283 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36285 this.updateTitle(panel.getTitle());
36287 this.fireEvent("invalidated", this);
36289 this.fireEvent("panelactivated", this, panel);
36293 * Shows the specified panel.
36294 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36295 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36297 showPanel : function(panel)
36299 panel = this.getPanel(panel);
36302 var tab = this.tabs.getTab(panel.getEl().id);
36303 if(tab.isHidden()){
36304 this.tabs.unhideTab(tab.id);
36308 this.setActivePanel(panel);
36315 * Get the active panel for this region.
36316 * @return {Roo.ContentPanel} The active panel or null
36318 getActivePanel : function(){
36319 return this.activePanel;
36322 validateVisibility : function(){
36323 if(this.panels.getCount() < 1){
36324 this.updateTitle(" ");
36325 this.closeBtn.hide();
36328 if(!this.isVisible()){
36335 * Adds the passed ContentPanel(s) to this region.
36336 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36337 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36339 add : function(panel)
36341 if(arguments.length > 1){
36342 for(var i = 0, len = arguments.length; i < len; i++) {
36343 this.add(arguments[i]);
36348 // if we have not been rendered yet, then we can not really do much of this..
36349 if (!this.bodyEl) {
36350 this.unrendered_panels.push(panel);
36357 if(this.hasPanel(panel)){
36358 this.showPanel(panel);
36361 panel.setRegion(this);
36362 this.panels.add(panel);
36363 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36364 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36365 // and hide them... ???
36366 this.bodyEl.dom.appendChild(panel.getEl().dom);
36367 if(panel.background !== true){
36368 this.setActivePanel(panel);
36370 this.fireEvent("paneladded", this, panel);
36377 this.initPanelAsTab(panel);
36381 if(panel.background !== true){
36382 this.tabs.activate(panel.getEl().id);
36384 this.fireEvent("paneladded", this, panel);
36389 * Hides the tab for the specified panel.
36390 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36392 hidePanel : function(panel){
36393 if(this.tabs && (panel = this.getPanel(panel))){
36394 this.tabs.hideTab(panel.getEl().id);
36399 * Unhides the tab for a previously hidden panel.
36400 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36402 unhidePanel : function(panel){
36403 if(this.tabs && (panel = this.getPanel(panel))){
36404 this.tabs.unhideTab(panel.getEl().id);
36408 clearPanels : function(){
36409 while(this.panels.getCount() > 0){
36410 this.remove(this.panels.first());
36415 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36416 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36417 * @param {Boolean} preservePanel Overrides the config preservePanel option
36418 * @return {Roo.ContentPanel} The panel that was removed
36420 remove : function(panel, preservePanel)
36422 panel = this.getPanel(panel);
36427 this.fireEvent("beforeremove", this, panel, e);
36428 if(e.cancel === true){
36431 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36432 var panelId = panel.getId();
36433 this.panels.removeKey(panelId);
36435 document.body.appendChild(panel.getEl().dom);
36438 this.tabs.removeTab(panel.getEl().id);
36439 }else if (!preservePanel){
36440 this.bodyEl.dom.removeChild(panel.getEl().dom);
36442 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36443 var p = this.panels.first();
36444 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36445 tempEl.appendChild(p.getEl().dom);
36446 this.bodyEl.update("");
36447 this.bodyEl.dom.appendChild(p.getEl().dom);
36449 this.updateTitle(p.getTitle());
36451 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36452 this.setActivePanel(p);
36454 panel.setRegion(null);
36455 if(this.activePanel == panel){
36456 this.activePanel = null;
36458 if(this.config.autoDestroy !== false && preservePanel !== true){
36459 try{panel.destroy();}catch(e){}
36461 this.fireEvent("panelremoved", this, panel);
36466 * Returns the TabPanel component used by this region
36467 * @return {Roo.TabPanel}
36469 getTabs : function(){
36473 createTool : function(parentEl, className){
36474 var btn = Roo.DomHelper.append(parentEl, {
36476 cls: "x-layout-tools-button",
36479 cls: "roo-layout-tools-button-inner " + className,
36483 btn.addClassOnOver("roo-layout-tools-button-over");
36488 * Ext JS Library 1.1.1
36489 * Copyright(c) 2006-2007, Ext JS, LLC.
36491 * Originally Released Under LGPL - original licence link has changed is not relivant.
36494 * <script type="text/javascript">
36500 * @class Roo.SplitLayoutRegion
36501 * @extends Roo.LayoutRegion
36502 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36504 Roo.bootstrap.layout.Split = function(config){
36505 this.cursor = config.cursor;
36506 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36509 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36511 splitTip : "Drag to resize.",
36512 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36513 useSplitTips : false,
36515 applyConfig : function(config){
36516 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36519 onRender : function(ctr,pos) {
36521 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36522 if(!this.config.split){
36527 var splitEl = Roo.DomHelper.append(ctr.dom, {
36529 id: this.el.id + "-split",
36530 cls: "roo-layout-split roo-layout-split-"+this.position,
36533 /** The SplitBar for this region
36534 * @type Roo.SplitBar */
36535 // does not exist yet...
36536 Roo.log([this.position, this.orientation]);
36538 this.split = new Roo.bootstrap.SplitBar({
36539 dragElement : splitEl,
36540 resizingElement: this.el,
36541 orientation : this.orientation
36544 this.split.on("moved", this.onSplitMove, this);
36545 this.split.useShim = this.config.useShim === true;
36546 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36547 if(this.useSplitTips){
36548 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36550 //if(config.collapsible){
36551 // this.split.el.on("dblclick", this.collapse, this);
36554 if(typeof this.config.minSize != "undefined"){
36555 this.split.minSize = this.config.minSize;
36557 if(typeof this.config.maxSize != "undefined"){
36558 this.split.maxSize = this.config.maxSize;
36560 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36561 this.hideSplitter();
36566 getHMaxSize : function(){
36567 var cmax = this.config.maxSize || 10000;
36568 var center = this.mgr.getRegion("center");
36569 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36572 getVMaxSize : function(){
36573 var cmax = this.config.maxSize || 10000;
36574 var center = this.mgr.getRegion("center");
36575 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36578 onSplitMove : function(split, newSize){
36579 this.fireEvent("resized", this, newSize);
36583 * Returns the {@link Roo.SplitBar} for this region.
36584 * @return {Roo.SplitBar}
36586 getSplitBar : function(){
36591 this.hideSplitter();
36592 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36595 hideSplitter : function(){
36597 this.split.el.setLocation(-2000,-2000);
36598 this.split.el.hide();
36604 this.split.el.show();
36606 Roo.bootstrap.layout.Split.superclass.show.call(this);
36609 beforeSlide: function(){
36610 if(Roo.isGecko){// firefox overflow auto bug workaround
36611 this.bodyEl.clip();
36613 this.tabs.bodyEl.clip();
36615 if(this.activePanel){
36616 this.activePanel.getEl().clip();
36618 if(this.activePanel.beforeSlide){
36619 this.activePanel.beforeSlide();
36625 afterSlide : function(){
36626 if(Roo.isGecko){// firefox overflow auto bug workaround
36627 this.bodyEl.unclip();
36629 this.tabs.bodyEl.unclip();
36631 if(this.activePanel){
36632 this.activePanel.getEl().unclip();
36633 if(this.activePanel.afterSlide){
36634 this.activePanel.afterSlide();
36640 initAutoHide : function(){
36641 if(this.autoHide !== false){
36642 if(!this.autoHideHd){
36643 var st = new Roo.util.DelayedTask(this.slideIn, this);
36644 this.autoHideHd = {
36645 "mouseout": function(e){
36646 if(!e.within(this.el, true)){
36650 "mouseover" : function(e){
36656 this.el.on(this.autoHideHd);
36660 clearAutoHide : function(){
36661 if(this.autoHide !== false){
36662 this.el.un("mouseout", this.autoHideHd.mouseout);
36663 this.el.un("mouseover", this.autoHideHd.mouseover);
36667 clearMonitor : function(){
36668 Roo.get(document).un("click", this.slideInIf, this);
36671 // these names are backwards but not changed for compat
36672 slideOut : function(){
36673 if(this.isSlid || this.el.hasActiveFx()){
36676 this.isSlid = true;
36677 if(this.collapseBtn){
36678 this.collapseBtn.hide();
36680 this.closeBtnState = this.closeBtn.getStyle('display');
36681 this.closeBtn.hide();
36683 this.stickBtn.show();
36686 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36687 this.beforeSlide();
36688 this.el.setStyle("z-index", 10001);
36689 this.el.slideIn(this.getSlideAnchor(), {
36690 callback: function(){
36692 this.initAutoHide();
36693 Roo.get(document).on("click", this.slideInIf, this);
36694 this.fireEvent("slideshow", this);
36701 afterSlideIn : function(){
36702 this.clearAutoHide();
36703 this.isSlid = false;
36704 this.clearMonitor();
36705 this.el.setStyle("z-index", "");
36706 if(this.collapseBtn){
36707 this.collapseBtn.show();
36709 this.closeBtn.setStyle('display', this.closeBtnState);
36711 this.stickBtn.hide();
36713 this.fireEvent("slidehide", this);
36716 slideIn : function(cb){
36717 if(!this.isSlid || this.el.hasActiveFx()){
36721 this.isSlid = false;
36722 this.beforeSlide();
36723 this.el.slideOut(this.getSlideAnchor(), {
36724 callback: function(){
36725 this.el.setLeftTop(-10000, -10000);
36727 this.afterSlideIn();
36735 slideInIf : function(e){
36736 if(!e.within(this.el)){
36741 animateCollapse : function(){
36742 this.beforeSlide();
36743 this.el.setStyle("z-index", 20000);
36744 var anchor = this.getSlideAnchor();
36745 this.el.slideOut(anchor, {
36746 callback : function(){
36747 this.el.setStyle("z-index", "");
36748 this.collapsedEl.slideIn(anchor, {duration:.3});
36750 this.el.setLocation(-10000,-10000);
36752 this.fireEvent("collapsed", this);
36759 animateExpand : function(){
36760 this.beforeSlide();
36761 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36762 this.el.setStyle("z-index", 20000);
36763 this.collapsedEl.hide({
36766 this.el.slideIn(this.getSlideAnchor(), {
36767 callback : function(){
36768 this.el.setStyle("z-index", "");
36771 this.split.el.show();
36773 this.fireEvent("invalidated", this);
36774 this.fireEvent("expanded", this);
36802 getAnchor : function(){
36803 return this.anchors[this.position];
36806 getCollapseAnchor : function(){
36807 return this.canchors[this.position];
36810 getSlideAnchor : function(){
36811 return this.sanchors[this.position];
36814 getAlignAdj : function(){
36815 var cm = this.cmargins;
36816 switch(this.position){
36832 getExpandAdj : function(){
36833 var c = this.collapsedEl, cm = this.cmargins;
36834 switch(this.position){
36836 return [-(cm.right+c.getWidth()+cm.left), 0];
36839 return [cm.right+c.getWidth()+cm.left, 0];
36842 return [0, -(cm.top+cm.bottom+c.getHeight())];
36845 return [0, cm.top+cm.bottom+c.getHeight()];
36851 * Ext JS Library 1.1.1
36852 * Copyright(c) 2006-2007, Ext JS, LLC.
36854 * Originally Released Under LGPL - original licence link has changed is not relivant.
36857 * <script type="text/javascript">
36860 * These classes are private internal classes
36862 Roo.bootstrap.layout.Center = function(config){
36863 config.region = "center";
36864 Roo.bootstrap.layout.Region.call(this, config);
36865 this.visible = true;
36866 this.minWidth = config.minWidth || 20;
36867 this.minHeight = config.minHeight || 20;
36870 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36872 // center panel can't be hidden
36876 // center panel can't be hidden
36879 getMinWidth: function(){
36880 return this.minWidth;
36883 getMinHeight: function(){
36884 return this.minHeight;
36897 Roo.bootstrap.layout.North = function(config)
36899 config.region = 'north';
36900 config.cursor = 'n-resize';
36902 Roo.bootstrap.layout.Split.call(this, config);
36906 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36907 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36908 this.split.el.addClass("roo-layout-split-v");
36910 var size = config.initialSize || config.height;
36911 if(typeof size != "undefined"){
36912 this.el.setHeight(size);
36915 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36917 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36921 getBox : function(){
36922 if(this.collapsed){
36923 return this.collapsedEl.getBox();
36925 var box = this.el.getBox();
36927 box.height += this.split.el.getHeight();
36932 updateBox : function(box){
36933 if(this.split && !this.collapsed){
36934 box.height -= this.split.el.getHeight();
36935 this.split.el.setLeft(box.x);
36936 this.split.el.setTop(box.y+box.height);
36937 this.split.el.setWidth(box.width);
36939 if(this.collapsed){
36940 this.updateBody(box.width, null);
36942 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36950 Roo.bootstrap.layout.South = function(config){
36951 config.region = 'south';
36952 config.cursor = 's-resize';
36953 Roo.bootstrap.layout.Split.call(this, config);
36955 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36956 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36957 this.split.el.addClass("roo-layout-split-v");
36959 var size = config.initialSize || config.height;
36960 if(typeof size != "undefined"){
36961 this.el.setHeight(size);
36965 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36966 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36967 getBox : function(){
36968 if(this.collapsed){
36969 return this.collapsedEl.getBox();
36971 var box = this.el.getBox();
36973 var sh = this.split.el.getHeight();
36980 updateBox : function(box){
36981 if(this.split && !this.collapsed){
36982 var sh = this.split.el.getHeight();
36985 this.split.el.setLeft(box.x);
36986 this.split.el.setTop(box.y-sh);
36987 this.split.el.setWidth(box.width);
36989 if(this.collapsed){
36990 this.updateBody(box.width, null);
36992 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36996 Roo.bootstrap.layout.East = function(config){
36997 config.region = "east";
36998 config.cursor = "e-resize";
36999 Roo.bootstrap.layout.Split.call(this, config);
37001 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37002 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37003 this.split.el.addClass("roo-layout-split-h");
37005 var size = config.initialSize || config.width;
37006 if(typeof size != "undefined"){
37007 this.el.setWidth(size);
37010 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37011 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37012 getBox : function(){
37013 if(this.collapsed){
37014 return this.collapsedEl.getBox();
37016 var box = this.el.getBox();
37018 var sw = this.split.el.getWidth();
37025 updateBox : function(box){
37026 if(this.split && !this.collapsed){
37027 var sw = this.split.el.getWidth();
37029 this.split.el.setLeft(box.x);
37030 this.split.el.setTop(box.y);
37031 this.split.el.setHeight(box.height);
37034 if(this.collapsed){
37035 this.updateBody(null, box.height);
37037 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37041 Roo.bootstrap.layout.West = function(config){
37042 config.region = "west";
37043 config.cursor = "w-resize";
37045 Roo.bootstrap.layout.Split.call(this, config);
37047 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37048 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37049 this.split.el.addClass("roo-layout-split-h");
37053 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37054 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37056 onRender: function(ctr, pos)
37058 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37059 var size = this.config.initialSize || this.config.width;
37060 if(typeof size != "undefined"){
37061 this.el.setWidth(size);
37065 getBox : function(){
37066 if(this.collapsed){
37067 return this.collapsedEl.getBox();
37069 var box = this.el.getBox();
37071 box.width += this.split.el.getWidth();
37076 updateBox : function(box){
37077 if(this.split && !this.collapsed){
37078 var sw = this.split.el.getWidth();
37080 this.split.el.setLeft(box.x+box.width);
37081 this.split.el.setTop(box.y);
37082 this.split.el.setHeight(box.height);
37084 if(this.collapsed){
37085 this.updateBody(null, box.height);
37087 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37090 Roo.namespace("Roo.bootstrap.panel");/*
37092 * Ext JS Library 1.1.1
37093 * Copyright(c) 2006-2007, Ext JS, LLC.
37095 * Originally Released Under LGPL - original licence link has changed is not relivant.
37098 * <script type="text/javascript">
37101 * @class Roo.ContentPanel
37102 * @extends Roo.util.Observable
37103 * A basic ContentPanel element.
37104 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37105 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37106 * @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
37107 * @cfg {Boolean} closable True if the panel can be closed/removed
37108 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37109 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37110 * @cfg {Toolbar} toolbar A toolbar for this panel
37111 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37112 * @cfg {String} title The title for this panel
37113 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37114 * @cfg {String} url Calls {@link #setUrl} with this value
37115 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37116 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37117 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37118 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37119 * @cfg {Boolean} badges render the badges
37122 * Create a new ContentPanel.
37123 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37124 * @param {String/Object} config A string to set only the title or a config object
37125 * @param {String} content (optional) Set the HTML content for this panel
37126 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37128 Roo.bootstrap.panel.Content = function( config){
37130 this.tpl = config.tpl || false;
37132 var el = config.el;
37133 var content = config.content;
37135 if(config.autoCreate){ // xtype is available if this is called from factory
37138 this.el = Roo.get(el);
37139 if(!this.el && config && config.autoCreate){
37140 if(typeof config.autoCreate == "object"){
37141 if(!config.autoCreate.id){
37142 config.autoCreate.id = config.id||el;
37144 this.el = Roo.DomHelper.append(document.body,
37145 config.autoCreate, true);
37147 var elcfg = { tag: "div",
37148 cls: "roo-layout-inactive-content",
37152 elcfg.html = config.html;
37156 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37159 this.closable = false;
37160 this.loaded = false;
37161 this.active = false;
37164 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37166 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37168 this.wrapEl = this.el; //this.el.wrap();
37170 if (config.toolbar.items) {
37171 ti = config.toolbar.items ;
37172 delete config.toolbar.items ;
37176 this.toolbar.render(this.wrapEl, 'before');
37177 for(var i =0;i < ti.length;i++) {
37178 // Roo.log(['add child', items[i]]);
37179 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37181 this.toolbar.items = nitems;
37182 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37183 delete config.toolbar;
37187 // xtype created footer. - not sure if will work as we normally have to render first..
37188 if (this.footer && !this.footer.el && this.footer.xtype) {
37189 if (!this.wrapEl) {
37190 this.wrapEl = this.el.wrap();
37193 this.footer.container = this.wrapEl.createChild();
37195 this.footer = Roo.factory(this.footer, Roo);
37200 if(typeof config == "string"){
37201 this.title = config;
37203 Roo.apply(this, config);
37207 this.resizeEl = Roo.get(this.resizeEl, true);
37209 this.resizeEl = this.el;
37211 // handle view.xtype
37219 * Fires when this panel is activated.
37220 * @param {Roo.ContentPanel} this
37224 * @event deactivate
37225 * Fires when this panel is activated.
37226 * @param {Roo.ContentPanel} this
37228 "deactivate" : true,
37232 * Fires when this panel is resized if fitToFrame is true.
37233 * @param {Roo.ContentPanel} this
37234 * @param {Number} width The width after any component adjustments
37235 * @param {Number} height The height after any component adjustments
37241 * Fires when this tab is created
37242 * @param {Roo.ContentPanel} this
37253 if(this.autoScroll){
37254 this.resizeEl.setStyle("overflow", "auto");
37256 // fix randome scrolling
37257 //this.el.on('scroll', function() {
37258 // Roo.log('fix random scolling');
37259 // this.scrollTo('top',0);
37262 content = content || this.content;
37264 this.setContent(content);
37266 if(config && config.url){
37267 this.setUrl(this.url, this.params, this.loadOnce);
37272 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37274 if (this.view && typeof(this.view.xtype) != 'undefined') {
37275 this.view.el = this.el.appendChild(document.createElement("div"));
37276 this.view = Roo.factory(this.view);
37277 this.view.render && this.view.render(false, '');
37281 this.fireEvent('render', this);
37284 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37288 setRegion : function(region){
37289 this.region = region;
37290 this.setActiveClass(region && !this.background);
37294 setActiveClass: function(state)
37297 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37298 this.el.setStyle('position','relative');
37300 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37301 this.el.setStyle('position', 'absolute');
37306 * Returns the toolbar for this Panel if one was configured.
37307 * @return {Roo.Toolbar}
37309 getToolbar : function(){
37310 return this.toolbar;
37313 setActiveState : function(active)
37315 this.active = active;
37316 this.setActiveClass(active);
37318 if(this.fireEvent("deactivate", this) === false){
37323 this.fireEvent("activate", this);
37327 * Updates this panel's element
37328 * @param {String} content The new content
37329 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37331 setContent : function(content, loadScripts){
37332 this.el.update(content, loadScripts);
37335 ignoreResize : function(w, h){
37336 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37339 this.lastSize = {width: w, height: h};
37344 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37345 * @return {Roo.UpdateManager} The UpdateManager
37347 getUpdateManager : function(){
37348 return this.el.getUpdateManager();
37351 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37352 * @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:
37355 url: "your-url.php",
37356 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37357 callback: yourFunction,
37358 scope: yourObject, //(optional scope)
37361 text: "Loading...",
37366 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37367 * 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.
37368 * @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}
37369 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37370 * @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.
37371 * @return {Roo.ContentPanel} this
37374 var um = this.el.getUpdateManager();
37375 um.update.apply(um, arguments);
37381 * 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.
37382 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37383 * @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)
37384 * @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)
37385 * @return {Roo.UpdateManager} The UpdateManager
37387 setUrl : function(url, params, loadOnce){
37388 if(this.refreshDelegate){
37389 this.removeListener("activate", this.refreshDelegate);
37391 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37392 this.on("activate", this.refreshDelegate);
37393 return this.el.getUpdateManager();
37396 _handleRefresh : function(url, params, loadOnce){
37397 if(!loadOnce || !this.loaded){
37398 var updater = this.el.getUpdateManager();
37399 updater.update(url, params, this._setLoaded.createDelegate(this));
37403 _setLoaded : function(){
37404 this.loaded = true;
37408 * Returns this panel's id
37411 getId : function(){
37416 * Returns this panel's element - used by regiosn to add.
37417 * @return {Roo.Element}
37419 getEl : function(){
37420 return this.wrapEl || this.el;
37425 adjustForComponents : function(width, height)
37427 //Roo.log('adjustForComponents ');
37428 if(this.resizeEl != this.el){
37429 width -= this.el.getFrameWidth('lr');
37430 height -= this.el.getFrameWidth('tb');
37433 var te = this.toolbar.getEl();
37434 te.setWidth(width);
37435 height -= te.getHeight();
37438 var te = this.footer.getEl();
37439 te.setWidth(width);
37440 height -= te.getHeight();
37444 if(this.adjustments){
37445 width += this.adjustments[0];
37446 height += this.adjustments[1];
37448 return {"width": width, "height": height};
37451 setSize : function(width, height){
37452 if(this.fitToFrame && !this.ignoreResize(width, height)){
37453 if(this.fitContainer && this.resizeEl != this.el){
37454 this.el.setSize(width, height);
37456 var size = this.adjustForComponents(width, height);
37457 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37458 this.fireEvent('resize', this, size.width, size.height);
37463 * Returns this panel's title
37466 getTitle : function(){
37468 if (typeof(this.title) != 'object') {
37473 for (var k in this.title) {
37474 if (!this.title.hasOwnProperty(k)) {
37478 if (k.indexOf('-') >= 0) {
37479 var s = k.split('-');
37480 for (var i = 0; i<s.length; i++) {
37481 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37484 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37491 * Set this panel's title
37492 * @param {String} title
37494 setTitle : function(title){
37495 this.title = title;
37497 this.region.updatePanelTitle(this, title);
37502 * Returns true is this panel was configured to be closable
37503 * @return {Boolean}
37505 isClosable : function(){
37506 return this.closable;
37509 beforeSlide : function(){
37511 this.resizeEl.clip();
37514 afterSlide : function(){
37516 this.resizeEl.unclip();
37520 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37521 * Will fail silently if the {@link #setUrl} method has not been called.
37522 * This does not activate the panel, just updates its content.
37524 refresh : function(){
37525 if(this.refreshDelegate){
37526 this.loaded = false;
37527 this.refreshDelegate();
37532 * Destroys this panel
37534 destroy : function(){
37535 this.el.removeAllListeners();
37536 var tempEl = document.createElement("span");
37537 tempEl.appendChild(this.el.dom);
37538 tempEl.innerHTML = "";
37544 * form - if the content panel contains a form - this is a reference to it.
37545 * @type {Roo.form.Form}
37549 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37550 * This contains a reference to it.
37556 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37566 * @param {Object} cfg Xtype definition of item to add.
37570 getChildContainer: function () {
37571 return this.getEl();
37576 var ret = new Roo.factory(cfg);
37581 if (cfg.xtype.match(/^Form$/)) {
37584 //if (this.footer) {
37585 // el = this.footer.container.insertSibling(false, 'before');
37587 el = this.el.createChild();
37590 this.form = new Roo.form.Form(cfg);
37593 if ( this.form.allItems.length) {
37594 this.form.render(el.dom);
37598 // should only have one of theses..
37599 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37600 // views.. should not be just added - used named prop 'view''
37602 cfg.el = this.el.appendChild(document.createElement("div"));
37605 var ret = new Roo.factory(cfg);
37607 ret.render && ret.render(false, ''); // render blank..
37617 * @class Roo.bootstrap.panel.Grid
37618 * @extends Roo.bootstrap.panel.Content
37620 * Create a new GridPanel.
37621 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37622 * @param {Object} config A the config object
37628 Roo.bootstrap.panel.Grid = function(config)
37632 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37633 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37635 config.el = this.wrapper;
37636 //this.el = this.wrapper;
37638 if (config.container) {
37639 // ctor'ed from a Border/panel.grid
37642 this.wrapper.setStyle("overflow", "hidden");
37643 this.wrapper.addClass('roo-grid-container');
37648 if(config.toolbar){
37649 var tool_el = this.wrapper.createChild();
37650 this.toolbar = Roo.factory(config.toolbar);
37652 if (config.toolbar.items) {
37653 ti = config.toolbar.items ;
37654 delete config.toolbar.items ;
37658 this.toolbar.render(tool_el);
37659 for(var i =0;i < ti.length;i++) {
37660 // Roo.log(['add child', items[i]]);
37661 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37663 this.toolbar.items = nitems;
37665 delete config.toolbar;
37668 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37669 config.grid.scrollBody = true;;
37670 config.grid.monitorWindowResize = false; // turn off autosizing
37671 config.grid.autoHeight = false;
37672 config.grid.autoWidth = false;
37674 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37676 if (config.background) {
37677 // render grid on panel activation (if panel background)
37678 this.on('activate', function(gp) {
37679 if (!gp.grid.rendered) {
37680 gp.grid.render(this.wrapper);
37681 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37686 this.grid.render(this.wrapper);
37687 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37690 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37691 // ??? needed ??? config.el = this.wrapper;
37696 // xtype created footer. - not sure if will work as we normally have to render first..
37697 if (this.footer && !this.footer.el && this.footer.xtype) {
37699 var ctr = this.grid.getView().getFooterPanel(true);
37700 this.footer.dataSource = this.grid.dataSource;
37701 this.footer = Roo.factory(this.footer, Roo);
37702 this.footer.render(ctr);
37712 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37713 getId : function(){
37714 return this.grid.id;
37718 * Returns the grid for this panel
37719 * @return {Roo.bootstrap.Table}
37721 getGrid : function(){
37725 setSize : function(width, height){
37726 if(!this.ignoreResize(width, height)){
37727 var grid = this.grid;
37728 var size = this.adjustForComponents(width, height);
37729 var gridel = grid.getGridEl();
37730 gridel.setSize(size.width, size.height);
37732 var thd = grid.getGridEl().select('thead',true).first();
37733 var tbd = grid.getGridEl().select('tbody', true).first();
37735 tbd.setSize(width, height - thd.getHeight());
37744 beforeSlide : function(){
37745 this.grid.getView().scroller.clip();
37748 afterSlide : function(){
37749 this.grid.getView().scroller.unclip();
37752 destroy : function(){
37753 this.grid.destroy();
37755 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37760 * @class Roo.bootstrap.panel.Nest
37761 * @extends Roo.bootstrap.panel.Content
37763 * Create a new Panel, that can contain a layout.Border.
37766 * @param {Roo.BorderLayout} layout The layout for this panel
37767 * @param {String/Object} config A string to set only the title or a config object
37769 Roo.bootstrap.panel.Nest = function(config)
37771 // construct with only one argument..
37772 /* FIXME - implement nicer consturctors
37773 if (layout.layout) {
37775 layout = config.layout;
37776 delete config.layout;
37778 if (layout.xtype && !layout.getEl) {
37779 // then layout needs constructing..
37780 layout = Roo.factory(layout, Roo);
37784 config.el = config.layout.getEl();
37786 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37788 config.layout.monitorWindowResize = false; // turn off autosizing
37789 this.layout = config.layout;
37790 this.layout.getEl().addClass("roo-layout-nested-layout");
37797 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37799 setSize : function(width, height){
37800 if(!this.ignoreResize(width, height)){
37801 var size = this.adjustForComponents(width, height);
37802 var el = this.layout.getEl();
37803 if (size.height < 1) {
37804 el.setWidth(size.width);
37806 el.setSize(size.width, size.height);
37808 var touch = el.dom.offsetWidth;
37809 this.layout.layout();
37810 // ie requires a double layout on the first pass
37811 if(Roo.isIE && !this.initialized){
37812 this.initialized = true;
37813 this.layout.layout();
37818 // activate all subpanels if not currently active..
37820 setActiveState : function(active){
37821 this.active = active;
37822 this.setActiveClass(active);
37825 this.fireEvent("deactivate", this);
37829 this.fireEvent("activate", this);
37830 // not sure if this should happen before or after..
37831 if (!this.layout) {
37832 return; // should not happen..
37835 for (var r in this.layout.regions) {
37836 reg = this.layout.getRegion(r);
37837 if (reg.getActivePanel()) {
37838 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37839 reg.setActivePanel(reg.getActivePanel());
37842 if (!reg.panels.length) {
37845 reg.showPanel(reg.getPanel(0));
37854 * Returns the nested BorderLayout for this panel
37855 * @return {Roo.BorderLayout}
37857 getLayout : function(){
37858 return this.layout;
37862 * Adds a xtype elements to the layout of the nested panel
37866 xtype : 'ContentPanel',
37873 xtype : 'NestedLayoutPanel',
37879 items : [ ... list of content panels or nested layout panels.. ]
37883 * @param {Object} cfg Xtype definition of item to add.
37885 addxtype : function(cfg) {
37886 return this.layout.addxtype(cfg);
37891 * Ext JS Library 1.1.1
37892 * Copyright(c) 2006-2007, Ext JS, LLC.
37894 * Originally Released Under LGPL - original licence link has changed is not relivant.
37897 * <script type="text/javascript">
37900 * @class Roo.TabPanel
37901 * @extends Roo.util.Observable
37902 * A lightweight tab container.
37906 // basic tabs 1, built from existing content
37907 var tabs = new Roo.TabPanel("tabs1");
37908 tabs.addTab("script", "View Script");
37909 tabs.addTab("markup", "View Markup");
37910 tabs.activate("script");
37912 // more advanced tabs, built from javascript
37913 var jtabs = new Roo.TabPanel("jtabs");
37914 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37916 // set up the UpdateManager
37917 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37918 var updater = tab2.getUpdateManager();
37919 updater.setDefaultUrl("ajax1.htm");
37920 tab2.on('activate', updater.refresh, updater, true);
37922 // Use setUrl for Ajax loading
37923 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37924 tab3.setUrl("ajax2.htm", null, true);
37927 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37930 jtabs.activate("jtabs-1");
37933 * Create a new TabPanel.
37934 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37935 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37937 Roo.bootstrap.panel.Tabs = function(config){
37939 * The container element for this TabPanel.
37940 * @type Roo.Element
37942 this.el = Roo.get(config.el);
37945 if(typeof config == "boolean"){
37946 this.tabPosition = config ? "bottom" : "top";
37948 Roo.apply(this, config);
37952 if(this.tabPosition == "bottom"){
37953 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37954 this.el.addClass("roo-tabs-bottom");
37956 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37957 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37958 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
37959 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37961 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37963 if(this.tabPosition != "bottom"){
37964 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37965 * @type Roo.Element
37967 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37968 this.el.addClass("roo-tabs-top");
37972 this.bodyEl.setStyle("position", "relative");
37974 this.active = null;
37975 this.activateDelegate = this.activate.createDelegate(this);
37980 * Fires when the active tab changes
37981 * @param {Roo.TabPanel} this
37982 * @param {Roo.TabPanelItem} activePanel The new active tab
37986 * @event beforetabchange
37987 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
37988 * @param {Roo.TabPanel} this
37989 * @param {Object} e Set cancel to true on this object to cancel the tab change
37990 * @param {Roo.TabPanelItem} tab The tab being changed to
37992 "beforetabchange" : true
37995 Roo.EventManager.onWindowResize(this.onResize, this);
37996 this.cpad = this.el.getPadding("lr");
37997 this.hiddenCount = 0;
38000 // toolbar on the tabbar support...
38001 if (this.toolbar) {
38002 alert("no toolbar support yet");
38003 this.toolbar = false;
38005 var tcfg = this.toolbar;
38006 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38007 this.toolbar = new Roo.Toolbar(tcfg);
38008 if (Roo.isSafari) {
38009 var tbl = tcfg.container.child('table', true);
38010 tbl.setAttribute('width', '100%');
38018 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38021 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38023 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38025 tabPosition : "top",
38027 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38029 currentTabWidth : 0,
38031 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38035 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38039 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38041 preferredTabWidth : 175,
38043 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38045 resizeTabs : false,
38047 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38049 monitorResize : true,
38051 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38056 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38057 * @param {String} id The id of the div to use <b>or create</b>
38058 * @param {String} text The text for the tab
38059 * @param {String} content (optional) Content to put in the TabPanelItem body
38060 * @param {Boolean} closable (optional) True to create a close icon on the tab
38061 * @return {Roo.TabPanelItem} The created TabPanelItem
38063 addTab : function(id, text, content, closable, tpl)
38065 var item = new Roo.bootstrap.panel.TabItem({
38069 closable : closable,
38072 this.addTabItem(item);
38074 item.setContent(content);
38080 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38081 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38082 * @return {Roo.TabPanelItem}
38084 getTab : function(id){
38085 return this.items[id];
38089 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38090 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38092 hideTab : function(id){
38093 var t = this.items[id];
38096 this.hiddenCount++;
38097 this.autoSizeTabs();
38102 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38103 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38105 unhideTab : function(id){
38106 var t = this.items[id];
38108 t.setHidden(false);
38109 this.hiddenCount--;
38110 this.autoSizeTabs();
38115 * Adds an existing {@link Roo.TabPanelItem}.
38116 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38118 addTabItem : function(item)
38120 this.items[item.id] = item;
38121 this.items.push(item);
38122 this.autoSizeTabs();
38123 // if(this.resizeTabs){
38124 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38125 // this.autoSizeTabs();
38127 // item.autoSize();
38132 * Removes a {@link Roo.TabPanelItem}.
38133 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38135 removeTab : function(id){
38136 var items = this.items;
38137 var tab = items[id];
38138 if(!tab) { return; }
38139 var index = items.indexOf(tab);
38140 if(this.active == tab && items.length > 1){
38141 var newTab = this.getNextAvailable(index);
38146 this.stripEl.dom.removeChild(tab.pnode.dom);
38147 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38148 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38150 items.splice(index, 1);
38151 delete this.items[tab.id];
38152 tab.fireEvent("close", tab);
38153 tab.purgeListeners();
38154 this.autoSizeTabs();
38157 getNextAvailable : function(start){
38158 var items = this.items;
38160 // look for a next tab that will slide over to
38161 // replace the one being removed
38162 while(index < items.length){
38163 var item = items[++index];
38164 if(item && !item.isHidden()){
38168 // if one isn't found select the previous tab (on the left)
38171 var item = items[--index];
38172 if(item && !item.isHidden()){
38180 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38181 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38183 disableTab : function(id){
38184 var tab = this.items[id];
38185 if(tab && this.active != tab){
38191 * Enables a {@link Roo.TabPanelItem} that is disabled.
38192 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38194 enableTab : function(id){
38195 var tab = this.items[id];
38200 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38201 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38202 * @return {Roo.TabPanelItem} The TabPanelItem.
38204 activate : function(id)
38206 var tab = this.items[id];
38210 if(tab == this.active || tab.disabled){
38214 this.fireEvent("beforetabchange", this, e, tab);
38215 if(e.cancel !== true && !tab.disabled){
38217 this.active.hide();
38219 this.active = this.items[id];
38220 this.active.show();
38221 this.fireEvent("tabchange", this, this.active);
38227 * Gets the active {@link Roo.TabPanelItem}.
38228 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38230 getActiveTab : function(){
38231 return this.active;
38235 * Updates the tab body element to fit the height of the container element
38236 * for overflow scrolling
38237 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38239 syncHeight : function(targetHeight){
38240 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38241 var bm = this.bodyEl.getMargins();
38242 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38243 this.bodyEl.setHeight(newHeight);
38247 onResize : function(){
38248 if(this.monitorResize){
38249 this.autoSizeTabs();
38254 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38256 beginUpdate : function(){
38257 this.updating = true;
38261 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38263 endUpdate : function(){
38264 this.updating = false;
38265 this.autoSizeTabs();
38269 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38271 autoSizeTabs : function()
38273 var count = this.items.length;
38274 var vcount = count - this.hiddenCount;
38277 this.stripEl.hide();
38279 this.stripEl.show();
38282 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38287 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38288 var availWidth = Math.floor(w / vcount);
38289 var b = this.stripBody;
38290 if(b.getWidth() > w){
38291 var tabs = this.items;
38292 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38293 if(availWidth < this.minTabWidth){
38294 /*if(!this.sleft){ // incomplete scrolling code
38295 this.createScrollButtons();
38298 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38301 if(this.currentTabWidth < this.preferredTabWidth){
38302 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38308 * Returns the number of tabs in this TabPanel.
38311 getCount : function(){
38312 return this.items.length;
38316 * Resizes all the tabs to the passed width
38317 * @param {Number} The new width
38319 setTabWidth : function(width){
38320 this.currentTabWidth = width;
38321 for(var i = 0, len = this.items.length; i < len; i++) {
38322 if(!this.items[i].isHidden()) {
38323 this.items[i].setWidth(width);
38329 * Destroys this TabPanel
38330 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38332 destroy : function(removeEl){
38333 Roo.EventManager.removeResizeListener(this.onResize, this);
38334 for(var i = 0, len = this.items.length; i < len; i++){
38335 this.items[i].purgeListeners();
38337 if(removeEl === true){
38338 this.el.update("");
38343 createStrip : function(container)
38345 var strip = document.createElement("nav");
38346 strip.className = Roo.bootstrap.version == 4 ?
38347 "navbar-light bg-light" :
38348 "navbar navbar-default"; //"x-tabs-wrap";
38349 container.appendChild(strip);
38353 createStripList : function(strip)
38355 // div wrapper for retard IE
38356 // returns the "tr" element.
38357 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38358 //'<div class="x-tabs-strip-wrap">'+
38359 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38360 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38361 return strip.firstChild; //.firstChild.firstChild.firstChild;
38363 createBody : function(container)
38365 var body = document.createElement("div");
38366 Roo.id(body, "tab-body");
38367 //Roo.fly(body).addClass("x-tabs-body");
38368 Roo.fly(body).addClass("tab-content");
38369 container.appendChild(body);
38372 createItemBody :function(bodyEl, id){
38373 var body = Roo.getDom(id);
38375 body = document.createElement("div");
38378 //Roo.fly(body).addClass("x-tabs-item-body");
38379 Roo.fly(body).addClass("tab-pane");
38380 bodyEl.insertBefore(body, bodyEl.firstChild);
38384 createStripElements : function(stripEl, text, closable, tpl)
38386 var td = document.createElement("li"); // was td..
38387 td.className = 'nav-item';
38389 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38392 stripEl.appendChild(td);
38394 td.className = "x-tabs-closable";
38395 if(!this.closeTpl){
38396 this.closeTpl = new Roo.Template(
38397 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38398 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38399 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38402 var el = this.closeTpl.overwrite(td, {"text": text});
38403 var close = el.getElementsByTagName("div")[0];
38404 var inner = el.getElementsByTagName("em")[0];
38405 return {"el": el, "close": close, "inner": inner};
38408 // not sure what this is..
38409 // if(!this.tabTpl){
38410 //this.tabTpl = new Roo.Template(
38411 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38412 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38414 // this.tabTpl = new Roo.Template(
38415 // '<a href="#">' +
38416 // '<span unselectable="on"' +
38417 // (this.disableTooltips ? '' : ' title="{text}"') +
38418 // ' >{text}</span></a>'
38424 var template = tpl || this.tabTpl || false;
38427 template = new Roo.Template(
38428 Roo.bootstrap.version == 4 ?
38430 '<a class="nav-link" href="#" unselectable="on"' +
38431 (this.disableTooltips ? '' : ' title="{text}"') +
38434 '<a class="nav-link" href="#">' +
38435 '<span unselectable="on"' +
38436 (this.disableTooltips ? '' : ' title="{text}"') +
38437 ' >{text}</span></a>'
38442 switch (typeof(template)) {
38446 template = new Roo.Template(template);
38452 var el = template.overwrite(td, {"text": text});
38454 var inner = el.getElementsByTagName("span")[0];
38456 return {"el": el, "inner": inner};
38464 * @class Roo.TabPanelItem
38465 * @extends Roo.util.Observable
38466 * Represents an individual item (tab plus body) in a TabPanel.
38467 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38468 * @param {String} id The id of this TabPanelItem
38469 * @param {String} text The text for the tab of this TabPanelItem
38470 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38472 Roo.bootstrap.panel.TabItem = function(config){
38474 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38475 * @type Roo.TabPanel
38477 this.tabPanel = config.panel;
38479 * The id for this TabPanelItem
38482 this.id = config.id;
38484 this.disabled = false;
38486 this.text = config.text;
38488 this.loaded = false;
38489 this.closable = config.closable;
38492 * The body element for this TabPanelItem.
38493 * @type Roo.Element
38495 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38496 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38497 this.bodyEl.setStyle("display", "block");
38498 this.bodyEl.setStyle("zoom", "1");
38499 //this.hideAction();
38501 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38503 this.el = Roo.get(els.el);
38504 this.inner = Roo.get(els.inner, true);
38505 this.textEl = Roo.bootstrap.version == 4 ?
38506 this.el : Roo.get(this.el.dom.firstChild, true);
38508 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38509 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38512 // this.el.on("mousedown", this.onTabMouseDown, this);
38513 this.el.on("click", this.onTabClick, this);
38515 if(config.closable){
38516 var c = Roo.get(els.close, true);
38517 c.dom.title = this.closeText;
38518 c.addClassOnOver("close-over");
38519 c.on("click", this.closeClick, this);
38525 * Fires when this tab becomes the active tab.
38526 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38527 * @param {Roo.TabPanelItem} this
38531 * @event beforeclose
38532 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38533 * @param {Roo.TabPanelItem} this
38534 * @param {Object} e Set cancel to true on this object to cancel the close.
38536 "beforeclose": true,
38539 * Fires when this tab is closed.
38540 * @param {Roo.TabPanelItem} this
38544 * @event deactivate
38545 * Fires when this tab is no longer the active tab.
38546 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38547 * @param {Roo.TabPanelItem} this
38549 "deactivate" : true
38551 this.hidden = false;
38553 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38556 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38558 purgeListeners : function(){
38559 Roo.util.Observable.prototype.purgeListeners.call(this);
38560 this.el.removeAllListeners();
38563 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38566 this.status_node.addClass("active");
38569 this.tabPanel.stripWrap.repaint();
38571 this.fireEvent("activate", this.tabPanel, this);
38575 * Returns true if this tab is the active tab.
38576 * @return {Boolean}
38578 isActive : function(){
38579 return this.tabPanel.getActiveTab() == this;
38583 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38586 this.status_node.removeClass("active");
38588 this.fireEvent("deactivate", this.tabPanel, this);
38591 hideAction : function(){
38592 this.bodyEl.hide();
38593 this.bodyEl.setStyle("position", "absolute");
38594 this.bodyEl.setLeft("-20000px");
38595 this.bodyEl.setTop("-20000px");
38598 showAction : function(){
38599 this.bodyEl.setStyle("position", "relative");
38600 this.bodyEl.setTop("");
38601 this.bodyEl.setLeft("");
38602 this.bodyEl.show();
38606 * Set the tooltip for the tab.
38607 * @param {String} tooltip The tab's tooltip
38609 setTooltip : function(text){
38610 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38611 this.textEl.dom.qtip = text;
38612 this.textEl.dom.removeAttribute('title');
38614 this.textEl.dom.title = text;
38618 onTabClick : function(e){
38619 e.preventDefault();
38620 this.tabPanel.activate(this.id);
38623 onTabMouseDown : function(e){
38624 e.preventDefault();
38625 this.tabPanel.activate(this.id);
38628 getWidth : function(){
38629 return this.inner.getWidth();
38632 setWidth : function(width){
38633 var iwidth = width - this.linode.getPadding("lr");
38634 this.inner.setWidth(iwidth);
38635 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38636 this.linode.setWidth(width);
38640 * Show or hide the tab
38641 * @param {Boolean} hidden True to hide or false to show.
38643 setHidden : function(hidden){
38644 this.hidden = hidden;
38645 this.linode.setStyle("display", hidden ? "none" : "");
38649 * Returns true if this tab is "hidden"
38650 * @return {Boolean}
38652 isHidden : function(){
38653 return this.hidden;
38657 * Returns the text for this tab
38660 getText : function(){
38664 autoSize : function(){
38665 //this.el.beginMeasure();
38666 this.textEl.setWidth(1);
38668 * #2804 [new] Tabs in Roojs
38669 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38671 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38672 //this.el.endMeasure();
38676 * Sets the text for the tab (Note: this also sets the tooltip text)
38677 * @param {String} text The tab's text and tooltip
38679 setText : function(text){
38681 this.textEl.update(text);
38682 this.setTooltip(text);
38683 //if(!this.tabPanel.resizeTabs){
38684 // this.autoSize();
38688 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38690 activate : function(){
38691 this.tabPanel.activate(this.id);
38695 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38697 disable : function(){
38698 if(this.tabPanel.active != this){
38699 this.disabled = true;
38700 this.status_node.addClass("disabled");
38705 * Enables this TabPanelItem if it was previously disabled.
38707 enable : function(){
38708 this.disabled = false;
38709 this.status_node.removeClass("disabled");
38713 * Sets the content for this TabPanelItem.
38714 * @param {String} content The content
38715 * @param {Boolean} loadScripts true to look for and load scripts
38717 setContent : function(content, loadScripts){
38718 this.bodyEl.update(content, loadScripts);
38722 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38723 * @return {Roo.UpdateManager} The UpdateManager
38725 getUpdateManager : function(){
38726 return this.bodyEl.getUpdateManager();
38730 * Set a URL to be used to load the content for this TabPanelItem.
38731 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38732 * @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)
38733 * @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)
38734 * @return {Roo.UpdateManager} The UpdateManager
38736 setUrl : function(url, params, loadOnce){
38737 if(this.refreshDelegate){
38738 this.un('activate', this.refreshDelegate);
38740 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38741 this.on("activate", this.refreshDelegate);
38742 return this.bodyEl.getUpdateManager();
38746 _handleRefresh : function(url, params, loadOnce){
38747 if(!loadOnce || !this.loaded){
38748 var updater = this.bodyEl.getUpdateManager();
38749 updater.update(url, params, this._setLoaded.createDelegate(this));
38754 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38755 * Will fail silently if the setUrl method has not been called.
38756 * This does not activate the panel, just updates its content.
38758 refresh : function(){
38759 if(this.refreshDelegate){
38760 this.loaded = false;
38761 this.refreshDelegate();
38766 _setLoaded : function(){
38767 this.loaded = true;
38771 closeClick : function(e){
38774 this.fireEvent("beforeclose", this, o);
38775 if(o.cancel !== true){
38776 this.tabPanel.removeTab(this.id);
38780 * The text displayed in the tooltip for the close icon.
38783 closeText : "Close this tab"
38786 * This script refer to:
38787 * Title: International Telephone Input
38788 * Author: Jack O'Connor
38789 * Code version: v12.1.12
38790 * Availability: https://github.com/jackocnr/intl-tel-input.git
38793 Roo.bootstrap.PhoneInputData = function() {
38796 "Afghanistan (افغانستان)",
38801 "Albania (Shqipëri)",
38806 "Algeria (الجزائر)",
38831 "Antigua and Barbuda",
38841 "Armenia (Հայաստան)",
38857 "Austria (Österreich)",
38862 "Azerbaijan (Azərbaycan)",
38872 "Bahrain (البحرين)",
38877 "Bangladesh (বাংলাদেশ)",
38887 "Belarus (Беларусь)",
38892 "Belgium (België)",
38922 "Bosnia and Herzegovina (Босна и Херцеговина)",
38937 "British Indian Ocean Territory",
38942 "British Virgin Islands",
38952 "Bulgaria (България)",
38962 "Burundi (Uburundi)",
38967 "Cambodia (កម្ពុជា)",
38972 "Cameroon (Cameroun)",
38981 ["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"]
38984 "Cape Verde (Kabu Verdi)",
38989 "Caribbean Netherlands",
39000 "Central African Republic (République centrafricaine)",
39020 "Christmas Island",
39026 "Cocos (Keeling) Islands",
39037 "Comoros (جزر القمر)",
39042 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39047 "Congo (Republic) (Congo-Brazzaville)",
39067 "Croatia (Hrvatska)",
39088 "Czech Republic (Česká republika)",
39093 "Denmark (Danmark)",
39108 "Dominican Republic (República Dominicana)",
39112 ["809", "829", "849"]
39130 "Equatorial Guinea (Guinea Ecuatorial)",
39150 "Falkland Islands (Islas Malvinas)",
39155 "Faroe Islands (Føroyar)",
39176 "French Guiana (Guyane française)",
39181 "French Polynesia (Polynésie française)",
39196 "Georgia (საქართველო)",
39201 "Germany (Deutschland)",
39221 "Greenland (Kalaallit Nunaat)",
39258 "Guinea-Bissau (Guiné Bissau)",
39283 "Hungary (Magyarország)",
39288 "Iceland (Ísland)",
39308 "Iraq (العراق)",
39324 "Israel (ישראל)",
39351 "Jordan (الأردن)",
39356 "Kazakhstan (Казахстан)",
39377 "Kuwait (الكويت)",
39382 "Kyrgyzstan (Кыргызстан)",
39392 "Latvia (Latvija)",
39397 "Lebanon (لبنان)",
39412 "Libya (ليبيا)",
39422 "Lithuania (Lietuva)",
39437 "Macedonia (FYROM) (Македонија)",
39442 "Madagascar (Madagasikara)",
39472 "Marshall Islands",
39482 "Mauritania (موريتانيا)",
39487 "Mauritius (Moris)",
39508 "Moldova (Republica Moldova)",
39518 "Mongolia (Монгол)",
39523 "Montenegro (Crna Gora)",
39533 "Morocco (المغرب)",
39539 "Mozambique (Moçambique)",
39544 "Myanmar (Burma) (မြန်မာ)",
39549 "Namibia (Namibië)",
39564 "Netherlands (Nederland)",
39569 "New Caledonia (Nouvelle-Calédonie)",
39604 "North Korea (조선 민주주의 인민 공화국)",
39609 "Northern Mariana Islands",
39625 "Pakistan (پاکستان)",
39635 "Palestine (فلسطين)",
39645 "Papua New Guinea",
39687 "Réunion (La Réunion)",
39693 "Romania (România)",
39709 "Saint Barthélemy",
39720 "Saint Kitts and Nevis",
39730 "Saint Martin (Saint-Martin (partie française))",
39736 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39741 "Saint Vincent and the Grenadines",
39756 "São Tomé and Príncipe (São Tomé e Príncipe)",
39761 "Saudi Arabia (المملكة العربية السعودية)",
39766 "Senegal (Sénégal)",
39796 "Slovakia (Slovensko)",
39801 "Slovenia (Slovenija)",
39811 "Somalia (Soomaaliya)",
39821 "South Korea (대한민국)",
39826 "South Sudan (جنوب السودان)",
39836 "Sri Lanka (ශ්රී ලංකාව)",
39841 "Sudan (السودان)",
39851 "Svalbard and Jan Mayen",
39862 "Sweden (Sverige)",
39867 "Switzerland (Schweiz)",
39872 "Syria (سوريا)",
39917 "Trinidad and Tobago",
39922 "Tunisia (تونس)",
39927 "Turkey (Türkiye)",
39937 "Turks and Caicos Islands",
39947 "U.S. Virgin Islands",
39957 "Ukraine (Україна)",
39962 "United Arab Emirates (الإمارات العربية المتحدة)",
39984 "Uzbekistan (Oʻzbekiston)",
39994 "Vatican City (Città del Vaticano)",
40005 "Vietnam (Việt Nam)",
40010 "Wallis and Futuna (Wallis-et-Futuna)",
40015 "Western Sahara (الصحراء الغربية)",
40021 "Yemen (اليمن)",
40045 * This script refer to:
40046 * Title: International Telephone Input
40047 * Author: Jack O'Connor
40048 * Code version: v12.1.12
40049 * Availability: https://github.com/jackocnr/intl-tel-input.git
40053 * @class Roo.bootstrap.PhoneInput
40054 * @extends Roo.bootstrap.TriggerField
40055 * An input with International dial-code selection
40057 * @cfg {String} defaultDialCode default '+852'
40058 * @cfg {Array} preferedCountries default []
40061 * Create a new PhoneInput.
40062 * @param {Object} config Configuration options
40065 Roo.bootstrap.PhoneInput = function(config) {
40066 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40069 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40071 listWidth: undefined,
40073 selectedClass: 'active',
40075 invalidClass : "has-warning",
40077 validClass: 'has-success',
40079 allowed: '0123456789',
40084 * @cfg {String} defaultDialCode The default dial code when initializing the input
40086 defaultDialCode: '+852',
40089 * @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
40091 preferedCountries: false,
40093 getAutoCreate : function()
40095 var data = Roo.bootstrap.PhoneInputData();
40096 var align = this.labelAlign || this.parentLabelAlign();
40099 this.allCountries = [];
40100 this.dialCodeMapping = [];
40102 for (var i = 0; i < data.length; i++) {
40104 this.allCountries[i] = {
40108 priority: c[3] || 0,
40109 areaCodes: c[4] || null
40111 this.dialCodeMapping[c[2]] = {
40114 priority: c[3] || 0,
40115 areaCodes: c[4] || null
40127 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40128 maxlength: this.max_length,
40129 cls : 'form-control tel-input',
40130 autocomplete: 'new-password'
40133 var hiddenInput = {
40136 cls: 'hidden-tel-input'
40140 hiddenInput.name = this.name;
40143 if (this.disabled) {
40144 input.disabled = true;
40147 var flag_container = {
40164 cls: this.hasFeedback ? 'has-feedback' : '',
40170 cls: 'dial-code-holder',
40177 cls: 'roo-select2-container input-group',
40184 if (this.fieldLabel.length) {
40187 tooltip: 'This field is required'
40193 cls: 'control-label',
40199 html: this.fieldLabel
40202 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40208 if(this.indicatorpos == 'right') {
40209 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40216 if(align == 'left') {
40224 if(this.labelWidth > 12){
40225 label.style = "width: " + this.labelWidth + 'px';
40227 if(this.labelWidth < 13 && this.labelmd == 0){
40228 this.labelmd = this.labelWidth;
40230 if(this.labellg > 0){
40231 label.cls += ' col-lg-' + this.labellg;
40232 input.cls += ' col-lg-' + (12 - this.labellg);
40234 if(this.labelmd > 0){
40235 label.cls += ' col-md-' + this.labelmd;
40236 container.cls += ' col-md-' + (12 - this.labelmd);
40238 if(this.labelsm > 0){
40239 label.cls += ' col-sm-' + this.labelsm;
40240 container.cls += ' col-sm-' + (12 - this.labelsm);
40242 if(this.labelxs > 0){
40243 label.cls += ' col-xs-' + this.labelxs;
40244 container.cls += ' col-xs-' + (12 - this.labelxs);
40254 var settings = this;
40256 ['xs','sm','md','lg'].map(function(size){
40257 if (settings[size]) {
40258 cfg.cls += ' col-' + size + '-' + settings[size];
40262 this.store = new Roo.data.Store({
40263 proxy : new Roo.data.MemoryProxy({}),
40264 reader : new Roo.data.JsonReader({
40275 'name' : 'dialCode',
40279 'name' : 'priority',
40283 'name' : 'areaCodes',
40290 if(!this.preferedCountries) {
40291 this.preferedCountries = [
40298 var p = this.preferedCountries.reverse();
40301 for (var i = 0; i < p.length; i++) {
40302 for (var j = 0; j < this.allCountries.length; j++) {
40303 if(this.allCountries[j].iso2 == p[i]) {
40304 var t = this.allCountries[j];
40305 this.allCountries.splice(j,1);
40306 this.allCountries.unshift(t);
40312 this.store.proxy.data = {
40314 data: this.allCountries
40320 initEvents : function()
40323 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40325 this.indicator = this.indicatorEl();
40326 this.flag = this.flagEl();
40327 this.dialCodeHolder = this.dialCodeHolderEl();
40329 this.trigger = this.el.select('div.flag-box',true).first();
40330 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40335 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40336 _this.list.setWidth(lw);
40339 this.list.on('mouseover', this.onViewOver, this);
40340 this.list.on('mousemove', this.onViewMove, this);
40341 this.inputEl().on("keyup", this.onKeyUp, this);
40342 this.inputEl().on("keypress", this.onKeyPress, this);
40344 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40346 this.view = new Roo.View(this.list, this.tpl, {
40347 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40350 this.view.on('click', this.onViewClick, this);
40351 this.setValue(this.defaultDialCode);
40354 onTriggerClick : function(e)
40356 Roo.log('trigger click');
40361 if(this.isExpanded()){
40363 this.hasFocus = false;
40365 this.store.load({});
40366 this.hasFocus = true;
40371 isExpanded : function()
40373 return this.list.isVisible();
40376 collapse : function()
40378 if(!this.isExpanded()){
40382 Roo.get(document).un('mousedown', this.collapseIf, this);
40383 Roo.get(document).un('mousewheel', this.collapseIf, this);
40384 this.fireEvent('collapse', this);
40388 expand : function()
40392 if(this.isExpanded() || !this.hasFocus){
40396 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40397 this.list.setWidth(lw);
40400 this.restrictHeight();
40402 Roo.get(document).on('mousedown', this.collapseIf, this);
40403 Roo.get(document).on('mousewheel', this.collapseIf, this);
40405 this.fireEvent('expand', this);
40408 restrictHeight : function()
40410 this.list.alignTo(this.inputEl(), this.listAlign);
40411 this.list.alignTo(this.inputEl(), this.listAlign);
40414 onViewOver : function(e, t)
40416 if(this.inKeyMode){
40419 var item = this.view.findItemFromChild(t);
40422 var index = this.view.indexOf(item);
40423 this.select(index, false);
40428 onViewClick : function(view, doFocus, el, e)
40430 var index = this.view.getSelectedIndexes()[0];
40432 var r = this.store.getAt(index);
40435 this.onSelect(r, index);
40437 if(doFocus !== false && !this.blockFocus){
40438 this.inputEl().focus();
40442 onViewMove : function(e, t)
40444 this.inKeyMode = false;
40447 select : function(index, scrollIntoView)
40449 this.selectedIndex = index;
40450 this.view.select(index);
40451 if(scrollIntoView !== false){
40452 var el = this.view.getNode(index);
40454 this.list.scrollChildIntoView(el, false);
40459 createList : function()
40461 this.list = Roo.get(document.body).createChild({
40463 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40464 style: 'display:none'
40467 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40470 collapseIf : function(e)
40472 var in_combo = e.within(this.el);
40473 var in_list = e.within(this.list);
40474 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40476 if (in_combo || in_list || is_list) {
40482 onSelect : function(record, index)
40484 if(this.fireEvent('beforeselect', this, record, index) !== false){
40486 this.setFlagClass(record.data.iso2);
40487 this.setDialCode(record.data.dialCode);
40488 this.hasFocus = false;
40490 this.fireEvent('select', this, record, index);
40494 flagEl : function()
40496 var flag = this.el.select('div.flag',true).first();
40503 dialCodeHolderEl : function()
40505 var d = this.el.select('input.dial-code-holder',true).first();
40512 setDialCode : function(v)
40514 this.dialCodeHolder.dom.value = '+'+v;
40517 setFlagClass : function(n)
40519 this.flag.dom.className = 'flag '+n;
40522 getValue : function()
40524 var v = this.inputEl().getValue();
40525 if(this.dialCodeHolder) {
40526 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40531 setValue : function(v)
40533 var d = this.getDialCode(v);
40535 //invalid dial code
40536 if(v.length == 0 || !d || d.length == 0) {
40538 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40539 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40545 this.setFlagClass(this.dialCodeMapping[d].iso2);
40546 this.setDialCode(d);
40547 this.inputEl().dom.value = v.replace('+'+d,'');
40548 this.hiddenEl().dom.value = this.getValue();
40553 getDialCode : function(v)
40557 if (v.length == 0) {
40558 return this.dialCodeHolder.dom.value;
40562 if (v.charAt(0) != "+") {
40565 var numericChars = "";
40566 for (var i = 1; i < v.length; i++) {
40567 var c = v.charAt(i);
40570 if (this.dialCodeMapping[numericChars]) {
40571 dialCode = v.substr(1, i);
40573 if (numericChars.length == 4) {
40583 this.setValue(this.defaultDialCode);
40587 hiddenEl : function()
40589 return this.el.select('input.hidden-tel-input',true).first();
40592 // after setting val
40593 onKeyUp : function(e){
40594 this.setValue(this.getValue());
40597 onKeyPress : function(e){
40598 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40605 * @class Roo.bootstrap.MoneyField
40606 * @extends Roo.bootstrap.ComboBox
40607 * Bootstrap MoneyField class
40610 * Create a new MoneyField.
40611 * @param {Object} config Configuration options
40614 Roo.bootstrap.MoneyField = function(config) {
40616 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40620 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40623 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40625 allowDecimals : true,
40627 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40629 decimalSeparator : ".",
40631 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40633 decimalPrecision : 0,
40635 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40637 allowNegative : true,
40639 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40643 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40645 minValue : Number.NEGATIVE_INFINITY,
40647 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40649 maxValue : Number.MAX_VALUE,
40651 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40653 minText : "The minimum value for this field is {0}",
40655 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40657 maxText : "The maximum value for this field is {0}",
40659 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40660 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40662 nanText : "{0} is not a valid number",
40664 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40668 * @cfg {String} defaults currency of the MoneyField
40669 * value should be in lkey
40671 defaultCurrency : false,
40673 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40675 thousandsDelimiter : false,
40677 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40688 getAutoCreate : function()
40690 var align = this.labelAlign || this.parentLabelAlign();
40702 cls : 'form-control roo-money-amount-input',
40703 autocomplete: 'new-password'
40706 var hiddenInput = {
40710 cls: 'hidden-number-input'
40713 if(this.max_length) {
40714 input.maxlength = this.max_length;
40718 hiddenInput.name = this.name;
40721 if (this.disabled) {
40722 input.disabled = true;
40725 var clg = 12 - this.inputlg;
40726 var cmd = 12 - this.inputmd;
40727 var csm = 12 - this.inputsm;
40728 var cxs = 12 - this.inputxs;
40732 cls : 'row roo-money-field',
40736 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40740 cls: 'roo-select2-container input-group',
40744 cls : 'form-control roo-money-currency-input',
40745 autocomplete: 'new-password',
40747 name : this.currencyName
40751 cls : 'input-group-addon',
40765 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40769 cls: this.hasFeedback ? 'has-feedback' : '',
40780 if (this.fieldLabel.length) {
40783 tooltip: 'This field is required'
40789 cls: 'control-label',
40795 html: this.fieldLabel
40798 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40804 if(this.indicatorpos == 'right') {
40805 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40812 if(align == 'left') {
40820 if(this.labelWidth > 12){
40821 label.style = "width: " + this.labelWidth + 'px';
40823 if(this.labelWidth < 13 && this.labelmd == 0){
40824 this.labelmd = this.labelWidth;
40826 if(this.labellg > 0){
40827 label.cls += ' col-lg-' + this.labellg;
40828 input.cls += ' col-lg-' + (12 - this.labellg);
40830 if(this.labelmd > 0){
40831 label.cls += ' col-md-' + this.labelmd;
40832 container.cls += ' col-md-' + (12 - this.labelmd);
40834 if(this.labelsm > 0){
40835 label.cls += ' col-sm-' + this.labelsm;
40836 container.cls += ' col-sm-' + (12 - this.labelsm);
40838 if(this.labelxs > 0){
40839 label.cls += ' col-xs-' + this.labelxs;
40840 container.cls += ' col-xs-' + (12 - this.labelxs);
40851 var settings = this;
40853 ['xs','sm','md','lg'].map(function(size){
40854 if (settings[size]) {
40855 cfg.cls += ' col-' + size + '-' + settings[size];
40862 initEvents : function()
40864 this.indicator = this.indicatorEl();
40866 this.initCurrencyEvent();
40868 this.initNumberEvent();
40871 initCurrencyEvent : function()
40874 throw "can not find store for combo";
40877 this.store = Roo.factory(this.store, Roo.data);
40878 this.store.parent = this;
40882 this.triggerEl = this.el.select('.input-group-addon', true).first();
40884 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40889 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40890 _this.list.setWidth(lw);
40893 this.list.on('mouseover', this.onViewOver, this);
40894 this.list.on('mousemove', this.onViewMove, this);
40895 this.list.on('scroll', this.onViewScroll, this);
40898 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40901 this.view = new Roo.View(this.list, this.tpl, {
40902 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40905 this.view.on('click', this.onViewClick, this);
40907 this.store.on('beforeload', this.onBeforeLoad, this);
40908 this.store.on('load', this.onLoad, this);
40909 this.store.on('loadexception', this.onLoadException, this);
40911 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40912 "up" : function(e){
40913 this.inKeyMode = true;
40917 "down" : function(e){
40918 if(!this.isExpanded()){
40919 this.onTriggerClick();
40921 this.inKeyMode = true;
40926 "enter" : function(e){
40929 if(this.fireEvent("specialkey", this, e)){
40930 this.onViewClick(false);
40936 "esc" : function(e){
40940 "tab" : function(e){
40943 if(this.fireEvent("specialkey", this, e)){
40944 this.onViewClick(false);
40952 doRelay : function(foo, bar, hname){
40953 if(hname == 'down' || this.scope.isExpanded()){
40954 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40962 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40966 initNumberEvent : function(e)
40968 this.inputEl().on("keydown" , this.fireKey, this);
40969 this.inputEl().on("focus", this.onFocus, this);
40970 this.inputEl().on("blur", this.onBlur, this);
40972 this.inputEl().relayEvent('keyup', this);
40974 if(this.indicator){
40975 this.indicator.addClass('invisible');
40978 this.originalValue = this.getValue();
40980 if(this.validationEvent == 'keyup'){
40981 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40982 this.inputEl().on('keyup', this.filterValidation, this);
40984 else if(this.validationEvent !== false){
40985 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
40988 if(this.selectOnFocus){
40989 this.on("focus", this.preFocus, this);
40992 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
40993 this.inputEl().on("keypress", this.filterKeys, this);
40995 this.inputEl().relayEvent('keypress', this);
40998 var allowed = "0123456789";
41000 if(this.allowDecimals){
41001 allowed += this.decimalSeparator;
41004 if(this.allowNegative){
41008 if(this.thousandsDelimiter) {
41012 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41014 var keyPress = function(e){
41016 var k = e.getKey();
41018 var c = e.getCharCode();
41021 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41022 allowed.indexOf(String.fromCharCode(c)) === -1
41028 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41032 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41037 this.inputEl().on("keypress", keyPress, this);
41041 onTriggerClick : function(e)
41048 this.loadNext = false;
41050 if(this.isExpanded()){
41055 this.hasFocus = true;
41057 if(this.triggerAction == 'all') {
41058 this.doQuery(this.allQuery, true);
41062 this.doQuery(this.getRawValue());
41065 getCurrency : function()
41067 var v = this.currencyEl().getValue();
41072 restrictHeight : function()
41074 this.list.alignTo(this.currencyEl(), this.listAlign);
41075 this.list.alignTo(this.currencyEl(), this.listAlign);
41078 onViewClick : function(view, doFocus, el, e)
41080 var index = this.view.getSelectedIndexes()[0];
41082 var r = this.store.getAt(index);
41085 this.onSelect(r, index);
41089 onSelect : function(record, index){
41091 if(this.fireEvent('beforeselect', this, record, index) !== false){
41093 this.setFromCurrencyData(index > -1 ? record.data : false);
41097 this.fireEvent('select', this, record, index);
41101 setFromCurrencyData : function(o)
41105 this.lastCurrency = o;
41107 if (this.currencyField) {
41108 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41110 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41113 this.lastSelectionText = currency;
41115 //setting default currency
41116 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41117 this.setCurrency(this.defaultCurrency);
41121 this.setCurrency(currency);
41124 setFromData : function(o)
41128 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41130 this.setFromCurrencyData(c);
41135 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41137 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41140 this.setValue(value);
41144 setCurrency : function(v)
41146 this.currencyValue = v;
41149 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41154 setValue : function(v)
41156 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41162 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41164 this.inputEl().dom.value = (v == '') ? '' :
41165 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41167 if(!this.allowZero && v === '0') {
41168 this.hiddenEl().dom.value = '';
41169 this.inputEl().dom.value = '';
41176 getRawValue : function()
41178 var v = this.inputEl().getValue();
41183 getValue : function()
41185 return this.fixPrecision(this.parseValue(this.getRawValue()));
41188 parseValue : function(value)
41190 if(this.thousandsDelimiter) {
41192 r = new RegExp(",", "g");
41193 value = value.replace(r, "");
41196 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41197 return isNaN(value) ? '' : value;
41201 fixPrecision : function(value)
41203 if(this.thousandsDelimiter) {
41205 r = new RegExp(",", "g");
41206 value = value.replace(r, "");
41209 var nan = isNaN(value);
41211 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41212 return nan ? '' : value;
41214 return parseFloat(value).toFixed(this.decimalPrecision);
41217 decimalPrecisionFcn : function(v)
41219 return Math.floor(v);
41222 validateValue : function(value)
41224 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41228 var num = this.parseValue(value);
41231 this.markInvalid(String.format(this.nanText, value));
41235 if(num < this.minValue){
41236 this.markInvalid(String.format(this.minText, this.minValue));
41240 if(num > this.maxValue){
41241 this.markInvalid(String.format(this.maxText, this.maxValue));
41248 validate : function()
41250 if(this.disabled || this.allowBlank){
41255 var currency = this.getCurrency();
41257 if(this.validateValue(this.getRawValue()) && currency.length){
41262 this.markInvalid();
41266 getName: function()
41271 beforeBlur : function()
41277 var v = this.parseValue(this.getRawValue());
41284 onBlur : function()
41288 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41289 //this.el.removeClass(this.focusClass);
41292 this.hasFocus = false;
41294 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41298 var v = this.getValue();
41300 if(String(v) !== String(this.startValue)){
41301 this.fireEvent('change', this, v, this.startValue);
41304 this.fireEvent("blur", this);
41307 inputEl : function()
41309 return this.el.select('.roo-money-amount-input', true).first();
41312 currencyEl : function()
41314 return this.el.select('.roo-money-currency-input', true).first();
41317 hiddenEl : function()
41319 return this.el.select('input.hidden-number-input',true).first();