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]);
9782 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9784 var feedback = this.el.select('.form-control-feedback', true).first();
9787 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9791 this.indicator.removeClass('visible');
9792 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9799 if(this.allowBlank && !this.getRawValue().length){
9802 if (Roo.bootstrap.version == 3) {
9803 this.el.addClass(this.validClass);
9806 this.inputEl().addClass('is-valid');
9808 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9810 var feedback = this.el.select('.form-control-feedback', true).first();
9813 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9814 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9819 this.fireEvent('valid', this);
9823 * Mark this field as invalid
9824 * @param {String} msg The validation message
9826 markInvalid : function(msg)
9828 if(!this.el || this.preventMark){ // not rendered
9832 this.el.removeClass([this.invalidClass, this.validClass]);
9833 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9835 var feedback = this.el.select('.form-control-feedback', true).first();
9838 this.el.select('.form-control-feedback', true).first().removeClass(
9839 [this.invalidFeedbackClass, this.validFeedbackClass]);
9846 if(this.allowBlank && !this.getRawValue().length){
9851 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9852 this.indicator.addClass('visible');
9854 if (Roo.bootstrap.version == 3) {
9855 this.el.addClass(this.invalidClass);
9858 this.inputEl().addClass('is-invalid');
9860 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9862 var feedback = this.el.select('.form-control-feedback', true).first();
9865 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9867 if(this.getValue().length || this.forceFeedback){
9868 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9875 this.fireEvent('invalid', this, msg);
9878 SafariOnKeyDown : function(event)
9880 // this is a workaround for a password hang bug on chrome/ webkit.
9881 if (this.inputEl().dom.type != 'password') {
9885 var isSelectAll = false;
9887 if(this.inputEl().dom.selectionEnd > 0){
9888 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9890 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9891 event.preventDefault();
9896 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9898 event.preventDefault();
9899 // this is very hacky as keydown always get's upper case.
9901 var cc = String.fromCharCode(event.getCharCode());
9902 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9906 adjustWidth : function(tag, w){
9907 tag = tag.toLowerCase();
9908 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9909 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9913 if(tag == 'textarea'){
9916 }else if(Roo.isOpera){
9920 if(tag == 'textarea'){
9928 setFieldLabel : function(v)
9934 if(this.indicatorEl()){
9935 var ar = this.el.select('label > span',true);
9937 if (ar.elements.length) {
9938 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9939 this.fieldLabel = v;
9943 var br = this.el.select('label',true);
9945 if(br.elements.length) {
9946 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9947 this.fieldLabel = v;
9951 Roo.log('Cannot Found any of label > span || label in input');
9955 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9956 this.fieldLabel = v;
9971 * @class Roo.bootstrap.TextArea
9972 * @extends Roo.bootstrap.Input
9973 * Bootstrap TextArea class
9974 * @cfg {Number} cols Specifies the visible width of a text area
9975 * @cfg {Number} rows Specifies the visible number of lines in a text area
9976 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
9977 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
9978 * @cfg {string} html text
9981 * Create a new TextArea
9982 * @param {Object} config The config object
9985 Roo.bootstrap.TextArea = function(config){
9986 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
9990 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10000 getAutoCreate : function(){
10002 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10008 if(this.inputType != 'hidden'){
10009 cfg.cls = 'form-group' //input-group
10017 value : this.value || '',
10018 html: this.html || '',
10019 cls : 'form-control',
10020 placeholder : this.placeholder || ''
10024 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10025 input.maxLength = this.maxLength;
10029 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10033 input.cols = this.cols;
10036 if (this.readOnly) {
10037 input.readonly = true;
10041 input.name = this.name;
10045 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10049 ['xs','sm','md','lg'].map(function(size){
10050 if (settings[size]) {
10051 cfg.cls += ' col-' + size + '-' + settings[size];
10055 var inputblock = input;
10057 if(this.hasFeedback && !this.allowBlank){
10061 cls: 'glyphicon form-control-feedback'
10065 cls : 'has-feedback',
10074 if (this.before || this.after) {
10077 cls : 'input-group',
10081 inputblock.cn.push({
10083 cls : 'input-group-addon',
10088 inputblock.cn.push(input);
10090 if(this.hasFeedback && !this.allowBlank){
10091 inputblock.cls += ' has-feedback';
10092 inputblock.cn.push(feedback);
10096 inputblock.cn.push({
10098 cls : 'input-group-addon',
10105 if (align ==='left' && this.fieldLabel.length) {
10110 cls : 'control-label',
10111 html : this.fieldLabel
10122 if(this.labelWidth > 12){
10123 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10126 if(this.labelWidth < 13 && this.labelmd == 0){
10127 this.labelmd = this.labelWidth;
10130 if(this.labellg > 0){
10131 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10132 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10135 if(this.labelmd > 0){
10136 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10137 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10140 if(this.labelsm > 0){
10141 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10142 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10145 if(this.labelxs > 0){
10146 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10147 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10150 } else if ( this.fieldLabel.length) {
10155 //cls : 'input-group-addon',
10156 html : this.fieldLabel
10174 if (this.disabled) {
10175 input.disabled=true;
10182 * return the real textarea element.
10184 inputEl: function ()
10186 return this.el.select('textarea.form-control',true).first();
10190 * Clear any invalid styles/messages for this field
10192 clearInvalid : function()
10195 if(!this.el || this.preventMark){ // not rendered
10199 var label = this.el.select('label', true).first();
10200 var icon = this.el.select('i.fa-star', true).first();
10206 this.el.removeClass(this.invalidClass);
10208 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10210 var feedback = this.el.select('.form-control-feedback', true).first();
10213 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10218 this.fireEvent('valid', this);
10222 * Mark this field as valid
10224 markValid : function()
10226 if(!this.el || this.preventMark){ // not rendered
10230 this.el.removeClass([this.invalidClass, this.validClass]);
10232 var feedback = this.el.select('.form-control-feedback', true).first();
10235 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10238 if(this.disabled || this.allowBlank){
10242 var label = this.el.select('label', true).first();
10243 var icon = this.el.select('i.fa-star', true).first();
10249 this.el.addClass(this.validClass);
10251 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10253 var feedback = this.el.select('.form-control-feedback', true).first();
10256 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10257 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10262 this.fireEvent('valid', this);
10266 * Mark this field as invalid
10267 * @param {String} msg The validation message
10269 markInvalid : function(msg)
10271 if(!this.el || this.preventMark){ // not rendered
10275 this.el.removeClass([this.invalidClass, this.validClass]);
10277 var feedback = this.el.select('.form-control-feedback', true).first();
10280 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10283 if(this.disabled || this.allowBlank){
10287 var label = this.el.select('label', true).first();
10288 var icon = this.el.select('i.fa-star', true).first();
10290 if(!this.getValue().length && label && !icon){
10291 this.el.createChild({
10293 cls : 'text-danger fa fa-lg fa-star',
10294 tooltip : 'This field is required',
10295 style : 'margin-right:5px;'
10299 this.el.addClass(this.invalidClass);
10301 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10303 var feedback = this.el.select('.form-control-feedback', true).first();
10306 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10308 if(this.getValue().length || this.forceFeedback){
10309 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10316 this.fireEvent('invalid', this, msg);
10324 * trigger field - base class for combo..
10329 * @class Roo.bootstrap.TriggerField
10330 * @extends Roo.bootstrap.Input
10331 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10332 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10333 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10334 * for which you can provide a custom implementation. For example:
10336 var trigger = new Roo.bootstrap.TriggerField();
10337 trigger.onTriggerClick = myTriggerFn;
10338 trigger.applyTo('my-field');
10341 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10342 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10343 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10344 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10345 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10348 * Create a new TriggerField.
10349 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10350 * to the base TextField)
10352 Roo.bootstrap.TriggerField = function(config){
10353 this.mimicing = false;
10354 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10357 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10359 * @cfg {String} triggerClass A CSS class to apply to the trigger
10362 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10367 * @cfg {Boolean} removable (true|false) special filter default false
10371 /** @cfg {Boolean} grow @hide */
10372 /** @cfg {Number} growMin @hide */
10373 /** @cfg {Number} growMax @hide */
10379 autoSize: Roo.emptyFn,
10383 deferHeight : true,
10386 actionMode : 'wrap',
10391 getAutoCreate : function(){
10393 var align = this.labelAlign || this.parentLabelAlign();
10398 cls: 'form-group' //input-group
10405 type : this.inputType,
10406 cls : 'form-control',
10407 autocomplete: 'new-password',
10408 placeholder : this.placeholder || ''
10412 input.name = this.name;
10415 input.cls += ' input-' + this.size;
10418 if (this.disabled) {
10419 input.disabled=true;
10422 var inputblock = input;
10424 if(this.hasFeedback && !this.allowBlank){
10428 cls: 'glyphicon form-control-feedback'
10431 if(this.removable && !this.editable && !this.tickable){
10433 cls : 'has-feedback',
10439 cls : 'roo-combo-removable-btn close'
10446 cls : 'has-feedback',
10455 if(this.removable && !this.editable && !this.tickable){
10457 cls : 'roo-removable',
10463 cls : 'roo-combo-removable-btn close'
10470 if (this.before || this.after) {
10473 cls : 'input-group',
10477 inputblock.cn.push({
10479 cls : 'input-group-addon input-group-prepend input-group-text',
10484 inputblock.cn.push(input);
10486 if(this.hasFeedback && !this.allowBlank){
10487 inputblock.cls += ' has-feedback';
10488 inputblock.cn.push(feedback);
10492 inputblock.cn.push({
10494 cls : 'input-group-addon input-group-append input-group-text',
10503 var ibwrap = inputblock;
10508 cls: 'roo-select2-choices',
10512 cls: 'roo-select2-search-field',
10524 cls: 'roo-select2-container input-group',
10529 cls: 'form-hidden-field'
10535 if(!this.multiple && this.showToggleBtn){
10541 if (this.caret != false) {
10544 cls: 'fa fa-' + this.caret
10551 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10556 cls: 'combobox-clear',
10570 combobox.cls += ' roo-select2-container-multi';
10574 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10575 tooltip : 'This field is required'
10577 if (Roo.bootstrap.version == 4) {
10580 style : 'display:none'
10585 if (align ==='left' && this.fieldLabel.length) {
10587 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10594 cls : 'control-label',
10595 html : this.fieldLabel
10607 var labelCfg = cfg.cn[1];
10608 var contentCfg = cfg.cn[2];
10610 if(this.indicatorpos == 'right'){
10615 cls : 'control-label',
10619 html : this.fieldLabel
10633 labelCfg = cfg.cn[0];
10634 contentCfg = cfg.cn[1];
10637 if(this.labelWidth > 12){
10638 labelCfg.style = "width: " + this.labelWidth + 'px';
10641 if(this.labelWidth < 13 && this.labelmd == 0){
10642 this.labelmd = this.labelWidth;
10645 if(this.labellg > 0){
10646 labelCfg.cls += ' col-lg-' + this.labellg;
10647 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10650 if(this.labelmd > 0){
10651 labelCfg.cls += ' col-md-' + this.labelmd;
10652 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10655 if(this.labelsm > 0){
10656 labelCfg.cls += ' col-sm-' + this.labelsm;
10657 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10660 if(this.labelxs > 0){
10661 labelCfg.cls += ' col-xs-' + this.labelxs;
10662 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10665 } else if ( this.fieldLabel.length) {
10666 // Roo.log(" label");
10671 //cls : 'input-group-addon',
10672 html : this.fieldLabel
10680 if(this.indicatorpos == 'right'){
10688 html : this.fieldLabel
10702 // Roo.log(" no label && no align");
10709 ['xs','sm','md','lg'].map(function(size){
10710 if (settings[size]) {
10711 cfg.cls += ' col-' + size + '-' + settings[size];
10722 onResize : function(w, h){
10723 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10724 // if(typeof w == 'number'){
10725 // var x = w - this.trigger.getWidth();
10726 // this.inputEl().setWidth(this.adjustWidth('input', x));
10727 // this.trigger.setStyle('left', x+'px');
10732 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10735 getResizeEl : function(){
10736 return this.inputEl();
10740 getPositionEl : function(){
10741 return this.inputEl();
10745 alignErrorIcon : function(){
10746 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10750 initEvents : function(){
10754 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10755 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10756 if(!this.multiple && this.showToggleBtn){
10757 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10758 if(this.hideTrigger){
10759 this.trigger.setDisplayed(false);
10761 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10765 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10768 if(this.removable && !this.editable && !this.tickable){
10769 var close = this.closeTriggerEl();
10772 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10773 close.on('click', this.removeBtnClick, this, close);
10777 //this.trigger.addClassOnOver('x-form-trigger-over');
10778 //this.trigger.addClassOnClick('x-form-trigger-click');
10781 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10785 closeTriggerEl : function()
10787 var close = this.el.select('.roo-combo-removable-btn', true).first();
10788 return close ? close : false;
10791 removeBtnClick : function(e, h, el)
10793 e.preventDefault();
10795 if(this.fireEvent("remove", this) !== false){
10797 this.fireEvent("afterremove", this)
10801 createList : function()
10803 this.list = Roo.get(document.body).createChild({
10804 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10805 cls: 'typeahead typeahead-long dropdown-menu',
10806 style: 'display:none'
10809 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10814 initTrigger : function(){
10819 onDestroy : function(){
10821 this.trigger.removeAllListeners();
10822 // this.trigger.remove();
10825 // this.wrap.remove();
10827 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10831 onFocus : function(){
10832 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10834 if(!this.mimicing){
10835 this.wrap.addClass('x-trigger-wrap-focus');
10836 this.mimicing = true;
10837 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10838 if(this.monitorTab){
10839 this.el.on("keydown", this.checkTab, this);
10846 checkTab : function(e){
10847 if(e.getKey() == e.TAB){
10848 this.triggerBlur();
10853 onBlur : function(){
10858 mimicBlur : function(e, t){
10860 if(!this.wrap.contains(t) && this.validateBlur()){
10861 this.triggerBlur();
10867 triggerBlur : function(){
10868 this.mimicing = false;
10869 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10870 if(this.monitorTab){
10871 this.el.un("keydown", this.checkTab, this);
10873 //this.wrap.removeClass('x-trigger-wrap-focus');
10874 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10878 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10879 validateBlur : function(e, t){
10884 onDisable : function(){
10885 this.inputEl().dom.disabled = true;
10886 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10888 // this.wrap.addClass('x-item-disabled');
10893 onEnable : function(){
10894 this.inputEl().dom.disabled = false;
10895 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10897 // this.el.removeClass('x-item-disabled');
10902 onShow : function(){
10903 var ae = this.getActionEl();
10906 ae.dom.style.display = '';
10907 ae.dom.style.visibility = 'visible';
10913 onHide : function(){
10914 var ae = this.getActionEl();
10915 ae.dom.style.display = 'none';
10919 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10920 * by an implementing function.
10922 * @param {EventObject} e
10924 onTriggerClick : Roo.emptyFn
10928 * Ext JS Library 1.1.1
10929 * Copyright(c) 2006-2007, Ext JS, LLC.
10931 * Originally Released Under LGPL - original licence link has changed is not relivant.
10934 * <script type="text/javascript">
10939 * @class Roo.data.SortTypes
10941 * Defines the default sorting (casting?) comparison functions used when sorting data.
10943 Roo.data.SortTypes = {
10945 * Default sort that does nothing
10946 * @param {Mixed} s The value being converted
10947 * @return {Mixed} The comparison value
10949 none : function(s){
10954 * The regular expression used to strip tags
10958 stripTagsRE : /<\/?[^>]+>/gi,
10961 * Strips all HTML tags to sort on text only
10962 * @param {Mixed} s The value being converted
10963 * @return {String} The comparison value
10965 asText : function(s){
10966 return String(s).replace(this.stripTagsRE, "");
10970 * Strips all HTML tags to sort on text only - Case insensitive
10971 * @param {Mixed} s The value being converted
10972 * @return {String} The comparison value
10974 asUCText : function(s){
10975 return String(s).toUpperCase().replace(this.stripTagsRE, "");
10979 * Case insensitive string
10980 * @param {Mixed} s The value being converted
10981 * @return {String} The comparison value
10983 asUCString : function(s) {
10984 return String(s).toUpperCase();
10989 * @param {Mixed} s The value being converted
10990 * @return {Number} The comparison value
10992 asDate : function(s) {
10996 if(s instanceof Date){
10997 return s.getTime();
10999 return Date.parse(String(s));
11004 * @param {Mixed} s The value being converted
11005 * @return {Float} The comparison value
11007 asFloat : function(s) {
11008 var val = parseFloat(String(s).replace(/,/g, ""));
11017 * @param {Mixed} s The value being converted
11018 * @return {Number} The comparison value
11020 asInt : function(s) {
11021 var val = parseInt(String(s).replace(/,/g, ""));
11029 * Ext JS Library 1.1.1
11030 * Copyright(c) 2006-2007, Ext JS, LLC.
11032 * Originally Released Under LGPL - original licence link has changed is not relivant.
11035 * <script type="text/javascript">
11039 * @class Roo.data.Record
11040 * Instances of this class encapsulate both record <em>definition</em> information, and record
11041 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11042 * to access Records cached in an {@link Roo.data.Store} object.<br>
11044 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11045 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11048 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11050 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11051 * {@link #create}. The parameters are the same.
11052 * @param {Array} data An associative Array of data values keyed by the field name.
11053 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11054 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11055 * not specified an integer id is generated.
11057 Roo.data.Record = function(data, id){
11058 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11063 * Generate a constructor for a specific record layout.
11064 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11065 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11066 * Each field definition object may contain the following properties: <ul>
11067 * <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,
11068 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11069 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11070 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11071 * is being used, then this is a string containing the javascript expression to reference the data relative to
11072 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11073 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11074 * this may be omitted.</p></li>
11075 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11076 * <ul><li>auto (Default, implies no conversion)</li>
11081 * <li>date</li></ul></p></li>
11082 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11083 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11084 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11085 * by the Reader into an object that will be stored in the Record. It is passed the
11086 * following parameters:<ul>
11087 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11089 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11091 * <br>usage:<br><pre><code>
11092 var TopicRecord = Roo.data.Record.create(
11093 {name: 'title', mapping: 'topic_title'},
11094 {name: 'author', mapping: 'username'},
11095 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11096 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11097 {name: 'lastPoster', mapping: 'user2'},
11098 {name: 'excerpt', mapping: 'post_text'}
11101 var myNewRecord = new TopicRecord({
11102 title: 'Do my job please',
11105 lastPost: new Date(),
11106 lastPoster: 'Animal',
11107 excerpt: 'No way dude!'
11109 myStore.add(myNewRecord);
11114 Roo.data.Record.create = function(o){
11115 var f = function(){
11116 f.superclass.constructor.apply(this, arguments);
11118 Roo.extend(f, Roo.data.Record);
11119 var p = f.prototype;
11120 p.fields = new Roo.util.MixedCollection(false, function(field){
11123 for(var i = 0, len = o.length; i < len; i++){
11124 p.fields.add(new Roo.data.Field(o[i]));
11126 f.getField = function(name){
11127 return p.fields.get(name);
11132 Roo.data.Record.AUTO_ID = 1000;
11133 Roo.data.Record.EDIT = 'edit';
11134 Roo.data.Record.REJECT = 'reject';
11135 Roo.data.Record.COMMIT = 'commit';
11137 Roo.data.Record.prototype = {
11139 * Readonly flag - true if this record has been modified.
11148 join : function(store){
11149 this.store = store;
11153 * Set the named field to the specified value.
11154 * @param {String} name The name of the field to set.
11155 * @param {Object} value The value to set the field to.
11157 set : function(name, value){
11158 if(this.data[name] == value){
11162 if(!this.modified){
11163 this.modified = {};
11165 if(typeof this.modified[name] == 'undefined'){
11166 this.modified[name] = this.data[name];
11168 this.data[name] = value;
11169 if(!this.editing && this.store){
11170 this.store.afterEdit(this);
11175 * Get the value of the named field.
11176 * @param {String} name The name of the field to get the value of.
11177 * @return {Object} The value of the field.
11179 get : function(name){
11180 return this.data[name];
11184 beginEdit : function(){
11185 this.editing = true;
11186 this.modified = {};
11190 cancelEdit : function(){
11191 this.editing = false;
11192 delete this.modified;
11196 endEdit : function(){
11197 this.editing = false;
11198 if(this.dirty && this.store){
11199 this.store.afterEdit(this);
11204 * Usually called by the {@link Roo.data.Store} which owns the Record.
11205 * Rejects all changes made to the Record since either creation, or the last commit operation.
11206 * Modified fields are reverted to their original values.
11208 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11209 * of reject operations.
11211 reject : function(){
11212 var m = this.modified;
11214 if(typeof m[n] != "function"){
11215 this.data[n] = m[n];
11218 this.dirty = false;
11219 delete this.modified;
11220 this.editing = false;
11222 this.store.afterReject(this);
11227 * Usually called by the {@link Roo.data.Store} which owns the Record.
11228 * Commits all changes made to the Record since either creation, or the last commit operation.
11230 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11231 * of commit operations.
11233 commit : function(){
11234 this.dirty = false;
11235 delete this.modified;
11236 this.editing = false;
11238 this.store.afterCommit(this);
11243 hasError : function(){
11244 return this.error != null;
11248 clearError : function(){
11253 * Creates a copy of this record.
11254 * @param {String} id (optional) A new record id if you don't want to use this record's id
11257 copy : function(newId) {
11258 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11262 * Ext JS Library 1.1.1
11263 * Copyright(c) 2006-2007, Ext JS, LLC.
11265 * Originally Released Under LGPL - original licence link has changed is not relivant.
11268 * <script type="text/javascript">
11274 * @class Roo.data.Store
11275 * @extends Roo.util.Observable
11276 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11277 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11279 * 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
11280 * has no knowledge of the format of the data returned by the Proxy.<br>
11282 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11283 * instances from the data object. These records are cached and made available through accessor functions.
11285 * Creates a new Store.
11286 * @param {Object} config A config object containing the objects needed for the Store to access data,
11287 * and read the data into Records.
11289 Roo.data.Store = function(config){
11290 this.data = new Roo.util.MixedCollection(false);
11291 this.data.getKey = function(o){
11294 this.baseParams = {};
11296 this.paramNames = {
11301 "multisort" : "_multisort"
11304 if(config && config.data){
11305 this.inlineData = config.data;
11306 delete config.data;
11309 Roo.apply(this, config);
11311 if(this.reader){ // reader passed
11312 this.reader = Roo.factory(this.reader, Roo.data);
11313 this.reader.xmodule = this.xmodule || false;
11314 if(!this.recordType){
11315 this.recordType = this.reader.recordType;
11317 if(this.reader.onMetaChange){
11318 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11322 if(this.recordType){
11323 this.fields = this.recordType.prototype.fields;
11325 this.modified = [];
11329 * @event datachanged
11330 * Fires when the data cache has changed, and a widget which is using this Store
11331 * as a Record cache should refresh its view.
11332 * @param {Store} this
11334 datachanged : true,
11336 * @event metachange
11337 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11338 * @param {Store} this
11339 * @param {Object} meta The JSON metadata
11344 * Fires when Records have been added to the Store
11345 * @param {Store} this
11346 * @param {Roo.data.Record[]} records The array of Records added
11347 * @param {Number} index The index at which the record(s) were added
11352 * Fires when a Record has been removed from the Store
11353 * @param {Store} this
11354 * @param {Roo.data.Record} record The Record that was removed
11355 * @param {Number} index The index at which the record was removed
11360 * Fires when a Record has been updated
11361 * @param {Store} this
11362 * @param {Roo.data.Record} record The Record that was updated
11363 * @param {String} operation The update operation being performed. Value may be one of:
11365 Roo.data.Record.EDIT
11366 Roo.data.Record.REJECT
11367 Roo.data.Record.COMMIT
11373 * Fires when the data cache has been cleared.
11374 * @param {Store} this
11378 * @event beforeload
11379 * Fires before a request is made for a new data object. If the beforeload handler returns false
11380 * the load action will be canceled.
11381 * @param {Store} this
11382 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11386 * @event beforeloadadd
11387 * Fires after a new set of Records has been loaded.
11388 * @param {Store} this
11389 * @param {Roo.data.Record[]} records The Records that were loaded
11390 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11392 beforeloadadd : true,
11395 * Fires after a new set of Records has been loaded, before they are added to the store.
11396 * @param {Store} this
11397 * @param {Roo.data.Record[]} records The Records that were loaded
11398 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11399 * @params {Object} return from reader
11403 * @event loadexception
11404 * Fires if an exception occurs in the Proxy during loading.
11405 * Called with the signature of the Proxy's "loadexception" event.
11406 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11409 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11410 * @param {Object} load options
11411 * @param {Object} jsonData from your request (normally this contains the Exception)
11413 loadexception : true
11417 this.proxy = Roo.factory(this.proxy, Roo.data);
11418 this.proxy.xmodule = this.xmodule || false;
11419 this.relayEvents(this.proxy, ["loadexception"]);
11421 this.sortToggle = {};
11422 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11424 Roo.data.Store.superclass.constructor.call(this);
11426 if(this.inlineData){
11427 this.loadData(this.inlineData);
11428 delete this.inlineData;
11432 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11434 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11435 * without a remote query - used by combo/forms at present.
11439 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11442 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11445 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11446 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11449 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11450 * on any HTTP request
11453 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11456 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11460 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11461 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11463 remoteSort : false,
11466 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11467 * loaded or when a record is removed. (defaults to false).
11469 pruneModifiedRecords : false,
11472 lastOptions : null,
11475 * Add Records to the Store and fires the add event.
11476 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11478 add : function(records){
11479 records = [].concat(records);
11480 for(var i = 0, len = records.length; i < len; i++){
11481 records[i].join(this);
11483 var index = this.data.length;
11484 this.data.addAll(records);
11485 this.fireEvent("add", this, records, index);
11489 * Remove a Record from the Store and fires the remove event.
11490 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11492 remove : function(record){
11493 var index = this.data.indexOf(record);
11494 this.data.removeAt(index);
11496 if(this.pruneModifiedRecords){
11497 this.modified.remove(record);
11499 this.fireEvent("remove", this, record, index);
11503 * Remove all Records from the Store and fires the clear event.
11505 removeAll : function(){
11507 if(this.pruneModifiedRecords){
11508 this.modified = [];
11510 this.fireEvent("clear", this);
11514 * Inserts Records to the Store at the given index and fires the add event.
11515 * @param {Number} index The start index at which to insert the passed Records.
11516 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11518 insert : function(index, records){
11519 records = [].concat(records);
11520 for(var i = 0, len = records.length; i < len; i++){
11521 this.data.insert(index, records[i]);
11522 records[i].join(this);
11524 this.fireEvent("add", this, records, index);
11528 * Get the index within the cache of the passed Record.
11529 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11530 * @return {Number} The index of the passed Record. Returns -1 if not found.
11532 indexOf : function(record){
11533 return this.data.indexOf(record);
11537 * Get the index within the cache of the Record with the passed id.
11538 * @param {String} id The id of the Record to find.
11539 * @return {Number} The index of the Record. Returns -1 if not found.
11541 indexOfId : function(id){
11542 return this.data.indexOfKey(id);
11546 * Get the Record with the specified id.
11547 * @param {String} id The id of the Record to find.
11548 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11550 getById : function(id){
11551 return this.data.key(id);
11555 * Get the Record at the specified index.
11556 * @param {Number} index The index of the Record to find.
11557 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11559 getAt : function(index){
11560 return this.data.itemAt(index);
11564 * Returns a range of Records between specified indices.
11565 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11566 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11567 * @return {Roo.data.Record[]} An array of Records
11569 getRange : function(start, end){
11570 return this.data.getRange(start, end);
11574 storeOptions : function(o){
11575 o = Roo.apply({}, o);
11578 this.lastOptions = o;
11582 * Loads the Record cache from the configured Proxy using the configured Reader.
11584 * If using remote paging, then the first load call must specify the <em>start</em>
11585 * and <em>limit</em> properties in the options.params property to establish the initial
11586 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11588 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11589 * and this call will return before the new data has been loaded. Perform any post-processing
11590 * in a callback function, or in a "load" event handler.</strong>
11592 * @param {Object} options An object containing properties which control loading options:<ul>
11593 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11594 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11595 * passed the following arguments:<ul>
11596 * <li>r : Roo.data.Record[]</li>
11597 * <li>options: Options object from the load call</li>
11598 * <li>success: Boolean success indicator</li></ul></li>
11599 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11600 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11603 load : function(options){
11604 options = options || {};
11605 if(this.fireEvent("beforeload", this, options) !== false){
11606 this.storeOptions(options);
11607 var p = Roo.apply(options.params || {}, this.baseParams);
11608 // if meta was not loaded from remote source.. try requesting it.
11609 if (!this.reader.metaFromRemote) {
11610 p._requestMeta = 1;
11612 if(this.sortInfo && this.remoteSort){
11613 var pn = this.paramNames;
11614 p[pn["sort"]] = this.sortInfo.field;
11615 p[pn["dir"]] = this.sortInfo.direction;
11617 if (this.multiSort) {
11618 var pn = this.paramNames;
11619 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11622 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11627 * Reloads the Record cache from the configured Proxy using the configured Reader and
11628 * the options from the last load operation performed.
11629 * @param {Object} options (optional) An object containing properties which may override the options
11630 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11631 * the most recently used options are reused).
11633 reload : function(options){
11634 this.load(Roo.applyIf(options||{}, this.lastOptions));
11638 // Called as a callback by the Reader during a load operation.
11639 loadRecords : function(o, options, success){
11640 if(!o || success === false){
11641 if(success !== false){
11642 this.fireEvent("load", this, [], options, o);
11644 if(options.callback){
11645 options.callback.call(options.scope || this, [], options, false);
11649 // if data returned failure - throw an exception.
11650 if (o.success === false) {
11651 // show a message if no listener is registered.
11652 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11653 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11655 // loadmask wil be hooked into this..
11656 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11659 var r = o.records, t = o.totalRecords || r.length;
11661 this.fireEvent("beforeloadadd", this, r, options, o);
11663 if(!options || options.add !== true){
11664 if(this.pruneModifiedRecords){
11665 this.modified = [];
11667 for(var i = 0, len = r.length; i < len; i++){
11671 this.data = this.snapshot;
11672 delete this.snapshot;
11675 this.data.addAll(r);
11676 this.totalLength = t;
11678 this.fireEvent("datachanged", this);
11680 this.totalLength = Math.max(t, this.data.length+r.length);
11684 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11686 var e = new Roo.data.Record({});
11688 e.set(this.parent.displayField, this.parent.emptyTitle);
11689 e.set(this.parent.valueField, '');
11694 this.fireEvent("load", this, r, options, o);
11695 if(options.callback){
11696 options.callback.call(options.scope || this, r, options, true);
11702 * Loads data from a passed data block. A Reader which understands the format of the data
11703 * must have been configured in the constructor.
11704 * @param {Object} data The data block from which to read the Records. The format of the data expected
11705 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11706 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11708 loadData : function(o, append){
11709 var r = this.reader.readRecords(o);
11710 this.loadRecords(r, {add: append}, true);
11714 * Gets the number of cached records.
11716 * <em>If using paging, this may not be the total size of the dataset. If the data object
11717 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11718 * the data set size</em>
11720 getCount : function(){
11721 return this.data.length || 0;
11725 * Gets the total number of records in the dataset as returned by the server.
11727 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11728 * the dataset size</em>
11730 getTotalCount : function(){
11731 return this.totalLength || 0;
11735 * Returns the sort state of the Store as an object with two properties:
11737 field {String} The name of the field by which the Records are sorted
11738 direction {String} The sort order, "ASC" or "DESC"
11741 getSortState : function(){
11742 return this.sortInfo;
11746 applySort : function(){
11747 if(this.sortInfo && !this.remoteSort){
11748 var s = this.sortInfo, f = s.field;
11749 var st = this.fields.get(f).sortType;
11750 var fn = function(r1, r2){
11751 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11752 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11754 this.data.sort(s.direction, fn);
11755 if(this.snapshot && this.snapshot != this.data){
11756 this.snapshot.sort(s.direction, fn);
11762 * Sets the default sort column and order to be used by the next load operation.
11763 * @param {String} fieldName The name of the field to sort by.
11764 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11766 setDefaultSort : function(field, dir){
11767 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11771 * Sort the Records.
11772 * If remote sorting is used, the sort is performed on the server, and the cache is
11773 * reloaded. If local sorting is used, the cache is sorted internally.
11774 * @param {String} fieldName The name of the field to sort by.
11775 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11777 sort : function(fieldName, dir){
11778 var f = this.fields.get(fieldName);
11780 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11782 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11783 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11788 this.sortToggle[f.name] = dir;
11789 this.sortInfo = {field: f.name, direction: dir};
11790 if(!this.remoteSort){
11792 this.fireEvent("datachanged", this);
11794 this.load(this.lastOptions);
11799 * Calls the specified function for each of the Records in the cache.
11800 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11801 * Returning <em>false</em> aborts and exits the iteration.
11802 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11804 each : function(fn, scope){
11805 this.data.each(fn, scope);
11809 * Gets all records modified since the last commit. Modified records are persisted across load operations
11810 * (e.g., during paging).
11811 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11813 getModifiedRecords : function(){
11814 return this.modified;
11818 createFilterFn : function(property, value, anyMatch){
11819 if(!value.exec){ // not a regex
11820 value = String(value);
11821 if(value.length == 0){
11824 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11826 return function(r){
11827 return value.test(r.data[property]);
11832 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11833 * @param {String} property A field on your records
11834 * @param {Number} start The record index to start at (defaults to 0)
11835 * @param {Number} end The last record index to include (defaults to length - 1)
11836 * @return {Number} The sum
11838 sum : function(property, start, end){
11839 var rs = this.data.items, v = 0;
11840 start = start || 0;
11841 end = (end || end === 0) ? end : rs.length-1;
11843 for(var i = start; i <= end; i++){
11844 v += (rs[i].data[property] || 0);
11850 * Filter the records by a specified property.
11851 * @param {String} field A field on your records
11852 * @param {String/RegExp} value Either a string that the field
11853 * should start with or a RegExp to test against the field
11854 * @param {Boolean} anyMatch True to match any part not just the beginning
11856 filter : function(property, value, anyMatch){
11857 var fn = this.createFilterFn(property, value, anyMatch);
11858 return fn ? this.filterBy(fn) : this.clearFilter();
11862 * Filter by a function. The specified function will be called with each
11863 * record in this data source. If the function returns true the record is included,
11864 * otherwise it is filtered.
11865 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11866 * @param {Object} scope (optional) The scope of the function (defaults to this)
11868 filterBy : function(fn, scope){
11869 this.snapshot = this.snapshot || this.data;
11870 this.data = this.queryBy(fn, scope||this);
11871 this.fireEvent("datachanged", this);
11875 * Query the records by a specified property.
11876 * @param {String} field A field on your records
11877 * @param {String/RegExp} value Either a string that the field
11878 * should start with or a RegExp to test against the field
11879 * @param {Boolean} anyMatch True to match any part not just the beginning
11880 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11882 query : function(property, value, anyMatch){
11883 var fn = this.createFilterFn(property, value, anyMatch);
11884 return fn ? this.queryBy(fn) : this.data.clone();
11888 * Query by a function. The specified function will be called with each
11889 * record in this data source. If the function returns true the record is included
11891 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11892 * @param {Object} scope (optional) The scope of the function (defaults to this)
11893 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11895 queryBy : function(fn, scope){
11896 var data = this.snapshot || this.data;
11897 return data.filterBy(fn, scope||this);
11901 * Collects unique values for a particular dataIndex from this store.
11902 * @param {String} dataIndex The property to collect
11903 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11904 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11905 * @return {Array} An array of the unique values
11907 collect : function(dataIndex, allowNull, bypassFilter){
11908 var d = (bypassFilter === true && this.snapshot) ?
11909 this.snapshot.items : this.data.items;
11910 var v, sv, r = [], l = {};
11911 for(var i = 0, len = d.length; i < len; i++){
11912 v = d[i].data[dataIndex];
11914 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11923 * Revert to a view of the Record cache with no filtering applied.
11924 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11926 clearFilter : function(suppressEvent){
11927 if(this.snapshot && this.snapshot != this.data){
11928 this.data = this.snapshot;
11929 delete this.snapshot;
11930 if(suppressEvent !== true){
11931 this.fireEvent("datachanged", this);
11937 afterEdit : function(record){
11938 if(this.modified.indexOf(record) == -1){
11939 this.modified.push(record);
11941 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11945 afterReject : function(record){
11946 this.modified.remove(record);
11947 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
11951 afterCommit : function(record){
11952 this.modified.remove(record);
11953 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
11957 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
11958 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
11960 commitChanges : function(){
11961 var m = this.modified.slice(0);
11962 this.modified = [];
11963 for(var i = 0, len = m.length; i < len; i++){
11969 * Cancel outstanding changes on all changed records.
11971 rejectChanges : function(){
11972 var m = this.modified.slice(0);
11973 this.modified = [];
11974 for(var i = 0, len = m.length; i < len; i++){
11979 onMetaChange : function(meta, rtype, o){
11980 this.recordType = rtype;
11981 this.fields = rtype.prototype.fields;
11982 delete this.snapshot;
11983 this.sortInfo = meta.sortInfo || this.sortInfo;
11984 this.modified = [];
11985 this.fireEvent('metachange', this, this.reader.meta);
11988 moveIndex : function(data, type)
11990 var index = this.indexOf(data);
11992 var newIndex = index + type;
11996 this.insert(newIndex, data);
12001 * Ext JS Library 1.1.1
12002 * Copyright(c) 2006-2007, Ext JS, LLC.
12004 * Originally Released Under LGPL - original licence link has changed is not relivant.
12007 * <script type="text/javascript">
12011 * @class Roo.data.SimpleStore
12012 * @extends Roo.data.Store
12013 * Small helper class to make creating Stores from Array data easier.
12014 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12015 * @cfg {Array} fields An array of field definition objects, or field name strings.
12016 * @cfg {Array} data The multi-dimensional array of data
12018 * @param {Object} config
12020 Roo.data.SimpleStore = function(config){
12021 Roo.data.SimpleStore.superclass.constructor.call(this, {
12023 reader: new Roo.data.ArrayReader({
12026 Roo.data.Record.create(config.fields)
12028 proxy : new Roo.data.MemoryProxy(config.data)
12032 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12034 * Ext JS Library 1.1.1
12035 * Copyright(c) 2006-2007, Ext JS, LLC.
12037 * Originally Released Under LGPL - original licence link has changed is not relivant.
12040 * <script type="text/javascript">
12045 * @extends Roo.data.Store
12046 * @class Roo.data.JsonStore
12047 * Small helper class to make creating Stores for JSON data easier. <br/>
12049 var store = new Roo.data.JsonStore({
12050 url: 'get-images.php',
12052 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12055 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12056 * JsonReader and HttpProxy (unless inline data is provided).</b>
12057 * @cfg {Array} fields An array of field definition objects, or field name strings.
12059 * @param {Object} config
12061 Roo.data.JsonStore = function(c){
12062 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12063 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12064 reader: new Roo.data.JsonReader(c, c.fields)
12067 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12069 * Ext JS Library 1.1.1
12070 * Copyright(c) 2006-2007, Ext JS, LLC.
12072 * Originally Released Under LGPL - original licence link has changed is not relivant.
12075 * <script type="text/javascript">
12079 Roo.data.Field = function(config){
12080 if(typeof config == "string"){
12081 config = {name: config};
12083 Roo.apply(this, config);
12086 this.type = "auto";
12089 var st = Roo.data.SortTypes;
12090 // named sortTypes are supported, here we look them up
12091 if(typeof this.sortType == "string"){
12092 this.sortType = st[this.sortType];
12095 // set default sortType for strings and dates
12096 if(!this.sortType){
12099 this.sortType = st.asUCString;
12102 this.sortType = st.asDate;
12105 this.sortType = st.none;
12110 var stripRe = /[\$,%]/g;
12112 // prebuilt conversion function for this field, instead of
12113 // switching every time we're reading a value
12115 var cv, dateFormat = this.dateFormat;
12120 cv = function(v){ return v; };
12123 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12127 return v !== undefined && v !== null && v !== '' ?
12128 parseInt(String(v).replace(stripRe, ""), 10) : '';
12133 return v !== undefined && v !== null && v !== '' ?
12134 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12139 cv = function(v){ return v === true || v === "true" || v == 1; };
12146 if(v instanceof Date){
12150 if(dateFormat == "timestamp"){
12151 return new Date(v*1000);
12153 return Date.parseDate(v, dateFormat);
12155 var parsed = Date.parse(v);
12156 return parsed ? new Date(parsed) : null;
12165 Roo.data.Field.prototype = {
12173 * Ext JS Library 1.1.1
12174 * Copyright(c) 2006-2007, Ext JS, LLC.
12176 * Originally Released Under LGPL - original licence link has changed is not relivant.
12179 * <script type="text/javascript">
12182 // Base class for reading structured data from a data source. This class is intended to be
12183 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12186 * @class Roo.data.DataReader
12187 * Base class for reading structured data from a data source. This class is intended to be
12188 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12191 Roo.data.DataReader = function(meta, recordType){
12195 this.recordType = recordType instanceof Array ?
12196 Roo.data.Record.create(recordType) : recordType;
12199 Roo.data.DataReader.prototype = {
12201 * Create an empty record
12202 * @param {Object} data (optional) - overlay some values
12203 * @return {Roo.data.Record} record created.
12205 newRow : function(d) {
12207 this.recordType.prototype.fields.each(function(c) {
12209 case 'int' : da[c.name] = 0; break;
12210 case 'date' : da[c.name] = new Date(); break;
12211 case 'float' : da[c.name] = 0.0; break;
12212 case 'boolean' : da[c.name] = false; break;
12213 default : da[c.name] = ""; break;
12217 return new this.recordType(Roo.apply(da, d));
12222 * Ext JS Library 1.1.1
12223 * Copyright(c) 2006-2007, Ext JS, LLC.
12225 * Originally Released Under LGPL - original licence link has changed is not relivant.
12228 * <script type="text/javascript">
12232 * @class Roo.data.DataProxy
12233 * @extends Roo.data.Observable
12234 * This class is an abstract base class for implementations which provide retrieval of
12235 * unformatted data objects.<br>
12237 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12238 * (of the appropriate type which knows how to parse the data object) to provide a block of
12239 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12241 * Custom implementations must implement the load method as described in
12242 * {@link Roo.data.HttpProxy#load}.
12244 Roo.data.DataProxy = function(){
12247 * @event beforeload
12248 * Fires before a network request is made to retrieve a data object.
12249 * @param {Object} This DataProxy object.
12250 * @param {Object} params The params parameter to the load function.
12255 * Fires before the load method's callback is called.
12256 * @param {Object} This DataProxy object.
12257 * @param {Object} o The data object.
12258 * @param {Object} arg The callback argument object passed to the load function.
12262 * @event loadexception
12263 * Fires if an Exception occurs during data retrieval.
12264 * @param {Object} This DataProxy object.
12265 * @param {Object} o The data object.
12266 * @param {Object} arg The callback argument object passed to the load function.
12267 * @param {Object} e The Exception.
12269 loadexception : true
12271 Roo.data.DataProxy.superclass.constructor.call(this);
12274 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12277 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12281 * Ext JS Library 1.1.1
12282 * Copyright(c) 2006-2007, Ext JS, LLC.
12284 * Originally Released Under LGPL - original licence link has changed is not relivant.
12287 * <script type="text/javascript">
12290 * @class Roo.data.MemoryProxy
12291 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12292 * to the Reader when its load method is called.
12294 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12296 Roo.data.MemoryProxy = function(data){
12300 Roo.data.MemoryProxy.superclass.constructor.call(this);
12304 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12307 * Load data from the requested source (in this case an in-memory
12308 * data object passed to the constructor), read the data object into
12309 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12310 * process that block using the passed callback.
12311 * @param {Object} params This parameter is not used by the MemoryProxy class.
12312 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12313 * object into a block of Roo.data.Records.
12314 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12315 * The function must be passed <ul>
12316 * <li>The Record block object</li>
12317 * <li>The "arg" argument from the load function</li>
12318 * <li>A boolean success indicator</li>
12320 * @param {Object} scope The scope in which to call the callback
12321 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12323 load : function(params, reader, callback, scope, arg){
12324 params = params || {};
12327 result = reader.readRecords(this.data);
12329 this.fireEvent("loadexception", this, arg, null, e);
12330 callback.call(scope, null, arg, false);
12333 callback.call(scope, result, arg, true);
12337 update : function(params, records){
12342 * Ext JS Library 1.1.1
12343 * Copyright(c) 2006-2007, Ext JS, LLC.
12345 * Originally Released Under LGPL - original licence link has changed is not relivant.
12348 * <script type="text/javascript">
12351 * @class Roo.data.HttpProxy
12352 * @extends Roo.data.DataProxy
12353 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12354 * configured to reference a certain URL.<br><br>
12356 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12357 * from which the running page was served.<br><br>
12359 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12361 * Be aware that to enable the browser to parse an XML document, the server must set
12362 * the Content-Type header in the HTTP response to "text/xml".
12364 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12365 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12366 * will be used to make the request.
12368 Roo.data.HttpProxy = function(conn){
12369 Roo.data.HttpProxy.superclass.constructor.call(this);
12370 // is conn a conn config or a real conn?
12372 this.useAjax = !conn || !conn.events;
12376 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12377 // thse are take from connection...
12380 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12383 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12384 * extra parameters to each request made by this object. (defaults to undefined)
12387 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12388 * to each request made by this object. (defaults to undefined)
12391 * @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)
12394 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12397 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12403 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12407 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12408 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12409 * a finer-grained basis than the DataProxy events.
12411 getConnection : function(){
12412 return this.useAjax ? Roo.Ajax : this.conn;
12416 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12417 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12418 * process that block using the passed callback.
12419 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12420 * for the request to the remote server.
12421 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12422 * object into a block of Roo.data.Records.
12423 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12424 * The function must be passed <ul>
12425 * <li>The Record block object</li>
12426 * <li>The "arg" argument from the load function</li>
12427 * <li>A boolean success indicator</li>
12429 * @param {Object} scope The scope in which to call the callback
12430 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12432 load : function(params, reader, callback, scope, arg){
12433 if(this.fireEvent("beforeload", this, params) !== false){
12435 params : params || {},
12437 callback : callback,
12442 callback : this.loadResponse,
12446 Roo.applyIf(o, this.conn);
12447 if(this.activeRequest){
12448 Roo.Ajax.abort(this.activeRequest);
12450 this.activeRequest = Roo.Ajax.request(o);
12452 this.conn.request(o);
12455 callback.call(scope||this, null, arg, false);
12460 loadResponse : function(o, success, response){
12461 delete this.activeRequest;
12463 this.fireEvent("loadexception", this, o, response);
12464 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12469 result = o.reader.read(response);
12471 this.fireEvent("loadexception", this, o, response, e);
12472 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12476 this.fireEvent("load", this, o, o.request.arg);
12477 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12481 update : function(dataSet){
12486 updateResponse : function(dataSet){
12491 * Ext JS Library 1.1.1
12492 * Copyright(c) 2006-2007, Ext JS, LLC.
12494 * Originally Released Under LGPL - original licence link has changed is not relivant.
12497 * <script type="text/javascript">
12501 * @class Roo.data.ScriptTagProxy
12502 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12503 * other than the originating domain of the running page.<br><br>
12505 * <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
12506 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12508 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12509 * source code that is used as the source inside a <script> tag.<br><br>
12511 * In order for the browser to process the returned data, the server must wrap the data object
12512 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12513 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12514 * depending on whether the callback name was passed:
12517 boolean scriptTag = false;
12518 String cb = request.getParameter("callback");
12521 response.setContentType("text/javascript");
12523 response.setContentType("application/x-json");
12525 Writer out = response.getWriter();
12527 out.write(cb + "(");
12529 out.print(dataBlock.toJsonString());
12536 * @param {Object} config A configuration object.
12538 Roo.data.ScriptTagProxy = function(config){
12539 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12540 Roo.apply(this, config);
12541 this.head = document.getElementsByTagName("head")[0];
12544 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12546 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12548 * @cfg {String} url The URL from which to request the data object.
12551 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12555 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12556 * the server the name of the callback function set up by the load call to process the returned data object.
12557 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12558 * javascript output which calls this named function passing the data object as its only parameter.
12560 callbackParam : "callback",
12562 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12563 * name to the request.
12568 * Load data from the configured URL, read the data object into
12569 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12570 * process that block using the passed callback.
12571 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12572 * for the request to the remote server.
12573 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12574 * object into a block of Roo.data.Records.
12575 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12576 * The function must be passed <ul>
12577 * <li>The Record block object</li>
12578 * <li>The "arg" argument from the load function</li>
12579 * <li>A boolean success indicator</li>
12581 * @param {Object} scope The scope in which to call the callback
12582 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12584 load : function(params, reader, callback, scope, arg){
12585 if(this.fireEvent("beforeload", this, params) !== false){
12587 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12589 var url = this.url;
12590 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12592 url += "&_dc=" + (new Date().getTime());
12594 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12597 cb : "stcCallback"+transId,
12598 scriptId : "stcScript"+transId,
12602 callback : callback,
12608 window[trans.cb] = function(o){
12609 conn.handleResponse(o, trans);
12612 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12614 if(this.autoAbort !== false){
12618 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12620 var script = document.createElement("script");
12621 script.setAttribute("src", url);
12622 script.setAttribute("type", "text/javascript");
12623 script.setAttribute("id", trans.scriptId);
12624 this.head.appendChild(script);
12626 this.trans = trans;
12628 callback.call(scope||this, null, arg, false);
12633 isLoading : function(){
12634 return this.trans ? true : false;
12638 * Abort the current server request.
12640 abort : function(){
12641 if(this.isLoading()){
12642 this.destroyTrans(this.trans);
12647 destroyTrans : function(trans, isLoaded){
12648 this.head.removeChild(document.getElementById(trans.scriptId));
12649 clearTimeout(trans.timeoutId);
12651 window[trans.cb] = undefined;
12653 delete window[trans.cb];
12656 // if hasn't been loaded, wait for load to remove it to prevent script error
12657 window[trans.cb] = function(){
12658 window[trans.cb] = undefined;
12660 delete window[trans.cb];
12667 handleResponse : function(o, trans){
12668 this.trans = false;
12669 this.destroyTrans(trans, true);
12672 result = trans.reader.readRecords(o);
12674 this.fireEvent("loadexception", this, o, trans.arg, e);
12675 trans.callback.call(trans.scope||window, null, trans.arg, false);
12678 this.fireEvent("load", this, o, trans.arg);
12679 trans.callback.call(trans.scope||window, result, trans.arg, true);
12683 handleFailure : function(trans){
12684 this.trans = false;
12685 this.destroyTrans(trans, false);
12686 this.fireEvent("loadexception", this, null, trans.arg);
12687 trans.callback.call(trans.scope||window, null, trans.arg, false);
12691 * Ext JS Library 1.1.1
12692 * Copyright(c) 2006-2007, Ext JS, LLC.
12694 * Originally Released Under LGPL - original licence link has changed is not relivant.
12697 * <script type="text/javascript">
12701 * @class Roo.data.JsonReader
12702 * @extends Roo.data.DataReader
12703 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12704 * based on mappings in a provided Roo.data.Record constructor.
12706 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12707 * in the reply previously.
12712 var RecordDef = Roo.data.Record.create([
12713 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12714 {name: 'occupation'} // This field will use "occupation" as the mapping.
12716 var myReader = new Roo.data.JsonReader({
12717 totalProperty: "results", // The property which contains the total dataset size (optional)
12718 root: "rows", // The property which contains an Array of row objects
12719 id: "id" // The property within each row object that provides an ID for the record (optional)
12723 * This would consume a JSON file like this:
12725 { 'results': 2, 'rows': [
12726 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12727 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12730 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12731 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12732 * paged from the remote server.
12733 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12734 * @cfg {String} root name of the property which contains the Array of row objects.
12735 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12736 * @cfg {Array} fields Array of field definition objects
12738 * Create a new JsonReader
12739 * @param {Object} meta Metadata configuration options
12740 * @param {Object} recordType Either an Array of field definition objects,
12741 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12743 Roo.data.JsonReader = function(meta, recordType){
12746 // set some defaults:
12747 Roo.applyIf(meta, {
12748 totalProperty: 'total',
12749 successProperty : 'success',
12754 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12756 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12759 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12760 * Used by Store query builder to append _requestMeta to params.
12763 metaFromRemote : false,
12765 * This method is only used by a DataProxy which has retrieved data from a remote server.
12766 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12767 * @return {Object} data A data block which is used by an Roo.data.Store object as
12768 * a cache of Roo.data.Records.
12770 read : function(response){
12771 var json = response.responseText;
12773 var o = /* eval:var:o */ eval("("+json+")");
12775 throw {message: "JsonReader.read: Json object not found"};
12781 this.metaFromRemote = true;
12782 this.meta = o.metaData;
12783 this.recordType = Roo.data.Record.create(o.metaData.fields);
12784 this.onMetaChange(this.meta, this.recordType, o);
12786 return this.readRecords(o);
12789 // private function a store will implement
12790 onMetaChange : function(meta, recordType, o){
12797 simpleAccess: function(obj, subsc) {
12804 getJsonAccessor: function(){
12806 return function(expr) {
12808 return(re.test(expr))
12809 ? new Function("obj", "return obj." + expr)
12814 return Roo.emptyFn;
12819 * Create a data block containing Roo.data.Records from an XML document.
12820 * @param {Object} o An object which contains an Array of row objects in the property specified
12821 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12822 * which contains the total size of the dataset.
12823 * @return {Object} data A data block which is used by an Roo.data.Store object as
12824 * a cache of Roo.data.Records.
12826 readRecords : function(o){
12828 * After any data loads, the raw JSON data is available for further custom processing.
12832 var s = this.meta, Record = this.recordType,
12833 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12835 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12837 if(s.totalProperty) {
12838 this.getTotal = this.getJsonAccessor(s.totalProperty);
12840 if(s.successProperty) {
12841 this.getSuccess = this.getJsonAccessor(s.successProperty);
12843 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12845 var g = this.getJsonAccessor(s.id);
12846 this.getId = function(rec) {
12848 return (r === undefined || r === "") ? null : r;
12851 this.getId = function(){return null;};
12854 for(var jj = 0; jj < fl; jj++){
12856 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12857 this.ef[jj] = this.getJsonAccessor(map);
12861 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12862 if(s.totalProperty){
12863 var vt = parseInt(this.getTotal(o), 10);
12868 if(s.successProperty){
12869 var vs = this.getSuccess(o);
12870 if(vs === false || vs === 'false'){
12875 for(var i = 0; i < c; i++){
12878 var id = this.getId(n);
12879 for(var j = 0; j < fl; j++){
12881 var v = this.ef[j](n);
12883 Roo.log('missing convert for ' + f.name);
12887 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12889 var record = new Record(values, id);
12891 records[i] = record;
12897 totalRecords : totalRecords
12902 * Ext JS Library 1.1.1
12903 * Copyright(c) 2006-2007, Ext JS, LLC.
12905 * Originally Released Under LGPL - original licence link has changed is not relivant.
12908 * <script type="text/javascript">
12912 * @class Roo.data.ArrayReader
12913 * @extends Roo.data.DataReader
12914 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12915 * Each element of that Array represents a row of data fields. The
12916 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12917 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12921 var RecordDef = Roo.data.Record.create([
12922 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12923 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12925 var myReader = new Roo.data.ArrayReader({
12926 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12930 * This would consume an Array like this:
12932 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12934 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12936 * Create a new JsonReader
12937 * @param {Object} meta Metadata configuration options.
12938 * @param {Object} recordType Either an Array of field definition objects
12939 * as specified to {@link Roo.data.Record#create},
12940 * or an {@link Roo.data.Record} object
12941 * created using {@link Roo.data.Record#create}.
12943 Roo.data.ArrayReader = function(meta, recordType){
12944 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
12947 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
12949 * Create a data block containing Roo.data.Records from an XML document.
12950 * @param {Object} o An Array of row objects which represents the dataset.
12951 * @return {Object} data A data block which is used by an Roo.data.Store object as
12952 * a cache of Roo.data.Records.
12954 readRecords : function(o){
12955 var sid = this.meta ? this.meta.id : null;
12956 var recordType = this.recordType, fields = recordType.prototype.fields;
12959 for(var i = 0; i < root.length; i++){
12962 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
12963 for(var j = 0, jlen = fields.length; j < jlen; j++){
12964 var f = fields.items[j];
12965 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
12966 var v = n[k] !== undefined ? n[k] : f.defaultValue;
12968 values[f.name] = v;
12970 var record = new recordType(values, id);
12972 records[records.length] = record;
12976 totalRecords : records.length
12985 * @class Roo.bootstrap.ComboBox
12986 * @extends Roo.bootstrap.TriggerField
12987 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
12988 * @cfg {Boolean} append (true|false) default false
12989 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
12990 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
12991 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
12992 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
12993 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
12994 * @cfg {Boolean} animate default true
12995 * @cfg {Boolean} emptyResultText only for touch device
12996 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
12997 * @cfg {String} emptyTitle default ''
12999 * Create a new ComboBox.
13000 * @param {Object} config Configuration options
13002 Roo.bootstrap.ComboBox = function(config){
13003 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13007 * Fires when the dropdown list is expanded
13008 * @param {Roo.bootstrap.ComboBox} combo This combo box
13013 * Fires when the dropdown list is collapsed
13014 * @param {Roo.bootstrap.ComboBox} combo This combo box
13018 * @event beforeselect
13019 * Fires before a list item is selected. Return false to cancel the selection.
13020 * @param {Roo.bootstrap.ComboBox} combo This combo box
13021 * @param {Roo.data.Record} record The data record returned from the underlying store
13022 * @param {Number} index The index of the selected item in the dropdown list
13024 'beforeselect' : true,
13027 * Fires when a list item is selected
13028 * @param {Roo.bootstrap.ComboBox} combo This combo box
13029 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13030 * @param {Number} index The index of the selected item in the dropdown list
13034 * @event beforequery
13035 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13036 * The event object passed has these properties:
13037 * @param {Roo.bootstrap.ComboBox} combo This combo box
13038 * @param {String} query The query
13039 * @param {Boolean} forceAll true to force "all" query
13040 * @param {Boolean} cancel true to cancel the query
13041 * @param {Object} e The query event object
13043 'beforequery': true,
13046 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13047 * @param {Roo.bootstrap.ComboBox} combo This combo box
13052 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13053 * @param {Roo.bootstrap.ComboBox} combo This combo box
13054 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13059 * Fires when the remove value from the combobox array
13060 * @param {Roo.bootstrap.ComboBox} combo This combo box
13064 * @event afterremove
13065 * Fires when the remove value from the combobox array
13066 * @param {Roo.bootstrap.ComboBox} combo This combo box
13068 'afterremove' : true,
13070 * @event specialfilter
13071 * Fires when specialfilter
13072 * @param {Roo.bootstrap.ComboBox} combo This combo box
13074 'specialfilter' : true,
13077 * Fires when tick the element
13078 * @param {Roo.bootstrap.ComboBox} combo This combo box
13082 * @event touchviewdisplay
13083 * Fires when touch view require special display (default is using displayField)
13084 * @param {Roo.bootstrap.ComboBox} combo This combo box
13085 * @param {Object} cfg set html .
13087 'touchviewdisplay' : true
13092 this.tickItems = [];
13094 this.selectedIndex = -1;
13095 if(this.mode == 'local'){
13096 if(config.queryDelay === undefined){
13097 this.queryDelay = 10;
13099 if(config.minChars === undefined){
13105 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13108 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13109 * rendering into an Roo.Editor, defaults to false)
13112 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13113 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13116 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13119 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13120 * the dropdown list (defaults to undefined, with no header element)
13124 * @cfg {String/Roo.Template} tpl The template to use to render the output
13128 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13130 listWidth: undefined,
13132 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13133 * mode = 'remote' or 'text' if mode = 'local')
13135 displayField: undefined,
13138 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13139 * mode = 'remote' or 'value' if mode = 'local').
13140 * Note: use of a valueField requires the user make a selection
13141 * in order for a value to be mapped.
13143 valueField: undefined,
13145 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13150 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13151 * field's data value (defaults to the underlying DOM element's name)
13153 hiddenName: undefined,
13155 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13159 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13161 selectedClass: 'active',
13164 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13168 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13169 * anchor positions (defaults to 'tl-bl')
13171 listAlign: 'tl-bl?',
13173 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13177 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13178 * query specified by the allQuery config option (defaults to 'query')
13180 triggerAction: 'query',
13182 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13183 * (defaults to 4, does not apply if editable = false)
13187 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13188 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13192 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13193 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13197 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13198 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13202 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13203 * when editable = true (defaults to false)
13205 selectOnFocus:false,
13207 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13209 queryParam: 'query',
13211 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13212 * when mode = 'remote' (defaults to 'Loading...')
13214 loadingText: 'Loading...',
13216 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13220 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13224 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13225 * traditional select (defaults to true)
13229 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13233 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13237 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13238 * listWidth has a higher value)
13242 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13243 * allow the user to set arbitrary text into the field (defaults to false)
13245 forceSelection:false,
13247 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13248 * if typeAhead = true (defaults to 250)
13250 typeAheadDelay : 250,
13252 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13253 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13255 valueNotFoundText : undefined,
13257 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13259 blockFocus : false,
13262 * @cfg {Boolean} disableClear Disable showing of clear button.
13264 disableClear : false,
13266 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13268 alwaysQuery : false,
13271 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13276 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
13278 invalidClass : "has-warning",
13281 * @cfg {String} validClass The CSS class to use when marking a field valid (defaults to "x-form-invalid")
13283 validClass : "has-success",
13286 * @cfg {Boolean} specialFilter (true|false) special filter default false
13288 specialFilter : false,
13291 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13293 mobileTouchView : true,
13296 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13298 useNativeIOS : false,
13301 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13303 mobile_restrict_height : false,
13305 ios_options : false,
13317 btnPosition : 'right',
13318 triggerList : true,
13319 showToggleBtn : true,
13321 emptyResultText: 'Empty',
13322 triggerText : 'Select',
13325 // element that contains real text value.. (when hidden is used..)
13327 getAutoCreate : function()
13332 * Render classic select for iso
13335 if(Roo.isIOS && this.useNativeIOS){
13336 cfg = this.getAutoCreateNativeIOS();
13344 if(Roo.isTouch && this.mobileTouchView){
13345 cfg = this.getAutoCreateTouchView();
13352 if(!this.tickable){
13353 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13358 * ComboBox with tickable selections
13361 var align = this.labelAlign || this.parentLabelAlign();
13364 cls : 'form-group roo-combobox-tickable' //input-group
13367 var btn_text_select = '';
13368 var btn_text_done = '';
13369 var btn_text_cancel = '';
13371 if (this.btn_text_show) {
13372 btn_text_select = 'Select';
13373 btn_text_done = 'Done';
13374 btn_text_cancel = 'Cancel';
13379 cls : 'tickable-buttons',
13384 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13385 //html : this.triggerText
13386 html: btn_text_select
13392 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13394 html: btn_text_done
13400 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13402 html: btn_text_cancel
13408 buttons.cn.unshift({
13410 cls: 'roo-select2-search-field-input'
13416 Roo.each(buttons.cn, function(c){
13418 c.cls += ' btn-' + _this.size;
13421 if (_this.disabled) {
13428 style : 'display: contents',
13433 cls: 'form-hidden-field'
13437 cls: 'roo-select2-choices',
13441 cls: 'roo-select2-search-field',
13452 cls: 'roo-select2-container input-group roo-select2-container-multi',
13458 // cls: 'typeahead typeahead-long dropdown-menu',
13459 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13464 if(this.hasFeedback && !this.allowBlank){
13468 cls: 'glyphicon form-control-feedback'
13471 combobox.cn.push(feedback);
13476 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13477 tooltip : 'This field is required'
13479 if (Roo.bootstrap.version == 4) {
13482 style : 'display:none'
13485 if (align ==='left' && this.fieldLabel.length) {
13487 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13494 cls : 'control-label col-form-label',
13495 html : this.fieldLabel
13507 var labelCfg = cfg.cn[1];
13508 var contentCfg = cfg.cn[2];
13511 if(this.indicatorpos == 'right'){
13517 cls : 'control-label col-form-label',
13521 html : this.fieldLabel
13537 labelCfg = cfg.cn[0];
13538 contentCfg = cfg.cn[1];
13542 if(this.labelWidth > 12){
13543 labelCfg.style = "width: " + this.labelWidth + 'px';
13546 if(this.labelWidth < 13 && this.labelmd == 0){
13547 this.labelmd = this.labelWidth;
13550 if(this.labellg > 0){
13551 labelCfg.cls += ' col-lg-' + this.labellg;
13552 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13555 if(this.labelmd > 0){
13556 labelCfg.cls += ' col-md-' + this.labelmd;
13557 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13560 if(this.labelsm > 0){
13561 labelCfg.cls += ' col-sm-' + this.labelsm;
13562 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13565 if(this.labelxs > 0){
13566 labelCfg.cls += ' col-xs-' + this.labelxs;
13567 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13571 } else if ( this.fieldLabel.length) {
13572 // Roo.log(" label");
13577 //cls : 'input-group-addon',
13578 html : this.fieldLabel
13583 if(this.indicatorpos == 'right'){
13587 //cls : 'input-group-addon',
13588 html : this.fieldLabel
13598 // Roo.log(" no label && no align");
13605 ['xs','sm','md','lg'].map(function(size){
13606 if (settings[size]) {
13607 cfg.cls += ' col-' + size + '-' + settings[size];
13615 _initEventsCalled : false,
13618 initEvents: function()
13620 if (this._initEventsCalled) { // as we call render... prevent looping...
13623 this._initEventsCalled = true;
13626 throw "can not find store for combo";
13629 this.indicator = this.indicatorEl();
13631 this.store = Roo.factory(this.store, Roo.data);
13632 this.store.parent = this;
13634 // if we are building from html. then this element is so complex, that we can not really
13635 // use the rendered HTML.
13636 // so we have to trash and replace the previous code.
13637 if (Roo.XComponent.build_from_html) {
13638 // remove this element....
13639 var e = this.el.dom, k=0;
13640 while (e ) { e = e.previousSibling; ++k;}
13645 this.rendered = false;
13647 this.render(this.parent().getChildContainer(true), k);
13650 if(Roo.isIOS && this.useNativeIOS){
13651 this.initIOSView();
13659 if(Roo.isTouch && this.mobileTouchView){
13660 this.initTouchView();
13665 this.initTickableEvents();
13669 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13671 if(this.hiddenName){
13673 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13675 this.hiddenField.dom.value =
13676 this.hiddenValue !== undefined ? this.hiddenValue :
13677 this.value !== undefined ? this.value : '';
13679 // prevent input submission
13680 this.el.dom.removeAttribute('name');
13681 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13686 // this.el.dom.setAttribute('autocomplete', 'off');
13689 var cls = 'x-combo-list';
13691 //this.list = new Roo.Layer({
13692 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13698 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13699 _this.list.setWidth(lw);
13702 this.list.on('mouseover', this.onViewOver, this);
13703 this.list.on('mousemove', this.onViewMove, this);
13704 this.list.on('scroll', this.onViewScroll, this);
13707 this.list.swallowEvent('mousewheel');
13708 this.assetHeight = 0;
13711 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13712 this.assetHeight += this.header.getHeight();
13715 this.innerList = this.list.createChild({cls:cls+'-inner'});
13716 this.innerList.on('mouseover', this.onViewOver, this);
13717 this.innerList.on('mousemove', this.onViewMove, this);
13718 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13720 if(this.allowBlank && !this.pageSize && !this.disableClear){
13721 this.footer = this.list.createChild({cls:cls+'-ft'});
13722 this.pageTb = new Roo.Toolbar(this.footer);
13726 this.footer = this.list.createChild({cls:cls+'-ft'});
13727 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13728 {pageSize: this.pageSize});
13732 if (this.pageTb && this.allowBlank && !this.disableClear) {
13734 this.pageTb.add(new Roo.Toolbar.Fill(), {
13735 cls: 'x-btn-icon x-btn-clear',
13737 handler: function()
13740 _this.clearValue();
13741 _this.onSelect(false, -1);
13746 this.assetHeight += this.footer.getHeight();
13751 this.tpl = Roo.bootstrap.version == 4 ?
13752 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13753 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13756 this.view = new Roo.View(this.list, this.tpl, {
13757 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13759 //this.view.wrapEl.setDisplayed(false);
13760 this.view.on('click', this.onViewClick, this);
13763 this.store.on('beforeload', this.onBeforeLoad, this);
13764 this.store.on('load', this.onLoad, this);
13765 this.store.on('loadexception', this.onLoadException, this);
13767 if(this.resizable){
13768 this.resizer = new Roo.Resizable(this.list, {
13769 pinned:true, handles:'se'
13771 this.resizer.on('resize', function(r, w, h){
13772 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13773 this.listWidth = w;
13774 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13775 this.restrictHeight();
13777 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13780 if(!this.editable){
13781 this.editable = true;
13782 this.setEditable(false);
13787 if (typeof(this.events.add.listeners) != 'undefined') {
13789 this.addicon = this.wrap.createChild(
13790 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13792 this.addicon.on('click', function(e) {
13793 this.fireEvent('add', this);
13796 if (typeof(this.events.edit.listeners) != 'undefined') {
13798 this.editicon = this.wrap.createChild(
13799 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13800 if (this.addicon) {
13801 this.editicon.setStyle('margin-left', '40px');
13803 this.editicon.on('click', function(e) {
13805 // we fire even if inothing is selected..
13806 this.fireEvent('edit', this, this.lastData );
13812 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13813 "up" : function(e){
13814 this.inKeyMode = true;
13818 "down" : function(e){
13819 if(!this.isExpanded()){
13820 this.onTriggerClick();
13822 this.inKeyMode = true;
13827 "enter" : function(e){
13828 // this.onViewClick();
13832 if(this.fireEvent("specialkey", this, e)){
13833 this.onViewClick(false);
13839 "esc" : function(e){
13843 "tab" : function(e){
13846 if(this.fireEvent("specialkey", this, e)){
13847 this.onViewClick(false);
13855 doRelay : function(foo, bar, hname){
13856 if(hname == 'down' || this.scope.isExpanded()){
13857 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13866 this.queryDelay = Math.max(this.queryDelay || 10,
13867 this.mode == 'local' ? 10 : 250);
13870 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13872 if(this.typeAhead){
13873 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13875 if(this.editable !== false){
13876 this.inputEl().on("keyup", this.onKeyUp, this);
13878 if(this.forceSelection){
13879 this.inputEl().on('blur', this.doForce, this);
13883 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13884 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13888 initTickableEvents: function()
13892 if(this.hiddenName){
13894 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13896 this.hiddenField.dom.value =
13897 this.hiddenValue !== undefined ? this.hiddenValue :
13898 this.value !== undefined ? this.value : '';
13900 // prevent input submission
13901 this.el.dom.removeAttribute('name');
13902 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13907 // this.list = this.el.select('ul.dropdown-menu',true).first();
13909 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13910 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13911 if(this.triggerList){
13912 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13915 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13916 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13918 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13919 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13921 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13922 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13924 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13925 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13926 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13929 this.cancelBtn.hide();
13934 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13935 _this.list.setWidth(lw);
13938 this.list.on('mouseover', this.onViewOver, this);
13939 this.list.on('mousemove', this.onViewMove, this);
13941 this.list.on('scroll', this.onViewScroll, this);
13944 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13945 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
13948 this.view = new Roo.View(this.list, this.tpl, {
13953 selectedClass: this.selectedClass
13956 //this.view.wrapEl.setDisplayed(false);
13957 this.view.on('click', this.onViewClick, this);
13961 this.store.on('beforeload', this.onBeforeLoad, this);
13962 this.store.on('load', this.onLoad, this);
13963 this.store.on('loadexception', this.onLoadException, this);
13966 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
13967 "up" : function(e){
13968 this.inKeyMode = true;
13972 "down" : function(e){
13973 this.inKeyMode = true;
13977 "enter" : function(e){
13978 if(this.fireEvent("specialkey", this, e)){
13979 this.onViewClick(false);
13985 "esc" : function(e){
13986 this.onTickableFooterButtonClick(e, false, false);
13989 "tab" : function(e){
13990 this.fireEvent("specialkey", this, e);
13992 this.onTickableFooterButtonClick(e, false, false);
13999 doRelay : function(e, fn, key){
14000 if(this.scope.isExpanded()){
14001 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14010 this.queryDelay = Math.max(this.queryDelay || 10,
14011 this.mode == 'local' ? 10 : 250);
14014 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14016 if(this.typeAhead){
14017 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14020 if(this.editable !== false){
14021 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14024 this.indicator = this.indicatorEl();
14026 if(this.indicator){
14027 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14028 this.indicator.hide();
14033 onDestroy : function(){
14035 this.view.setStore(null);
14036 this.view.el.removeAllListeners();
14037 this.view.el.remove();
14038 this.view.purgeListeners();
14041 this.list.dom.innerHTML = '';
14045 this.store.un('beforeload', this.onBeforeLoad, this);
14046 this.store.un('load', this.onLoad, this);
14047 this.store.un('loadexception', this.onLoadException, this);
14049 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14053 fireKey : function(e){
14054 if(e.isNavKeyPress() && !this.list.isVisible()){
14055 this.fireEvent("specialkey", this, e);
14060 onResize: function(w, h){
14061 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14063 // if(typeof w != 'number'){
14064 // // we do not handle it!?!?
14067 // var tw = this.trigger.getWidth();
14068 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14069 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14071 // this.inputEl().setWidth( this.adjustWidth('input', x));
14073 // //this.trigger.setStyle('left', x+'px');
14075 // if(this.list && this.listWidth === undefined){
14076 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14077 // this.list.setWidth(lw);
14078 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14086 * Allow or prevent the user from directly editing the field text. If false is passed,
14087 * the user will only be able to select from the items defined in the dropdown list. This method
14088 * is the runtime equivalent of setting the 'editable' config option at config time.
14089 * @param {Boolean} value True to allow the user to directly edit the field text
14091 setEditable : function(value){
14092 if(value == this.editable){
14095 this.editable = value;
14097 this.inputEl().dom.setAttribute('readOnly', true);
14098 this.inputEl().on('mousedown', this.onTriggerClick, this);
14099 this.inputEl().addClass('x-combo-noedit');
14101 this.inputEl().dom.setAttribute('readOnly', false);
14102 this.inputEl().un('mousedown', this.onTriggerClick, this);
14103 this.inputEl().removeClass('x-combo-noedit');
14109 onBeforeLoad : function(combo,opts){
14110 if(!this.hasFocus){
14114 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14116 this.restrictHeight();
14117 this.selectedIndex = -1;
14121 onLoad : function(){
14123 this.hasQuery = false;
14125 if(!this.hasFocus){
14129 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14130 this.loading.hide();
14133 if(this.store.getCount() > 0){
14136 this.restrictHeight();
14137 if(this.lastQuery == this.allQuery){
14138 if(this.editable && !this.tickable){
14139 this.inputEl().dom.select();
14143 !this.selectByValue(this.value, true) &&
14146 !this.store.lastOptions ||
14147 typeof(this.store.lastOptions.add) == 'undefined' ||
14148 this.store.lastOptions.add != true
14151 this.select(0, true);
14154 if(this.autoFocus){
14157 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14158 this.taTask.delay(this.typeAheadDelay);
14162 this.onEmptyResults();
14168 onLoadException : function()
14170 this.hasQuery = false;
14172 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14173 this.loading.hide();
14176 if(this.tickable && this.editable){
14181 // only causes errors at present
14182 //Roo.log(this.store.reader.jsonData);
14183 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14185 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14191 onTypeAhead : function(){
14192 if(this.store.getCount() > 0){
14193 var r = this.store.getAt(0);
14194 var newValue = r.data[this.displayField];
14195 var len = newValue.length;
14196 var selStart = this.getRawValue().length;
14198 if(selStart != len){
14199 this.setRawValue(newValue);
14200 this.selectText(selStart, newValue.length);
14206 onSelect : function(record, index){
14208 if(this.fireEvent('beforeselect', this, record, index) !== false){
14210 this.setFromData(index > -1 ? record.data : false);
14213 this.fireEvent('select', this, record, index);
14218 * Returns the currently selected field value or empty string if no value is set.
14219 * @return {String} value The selected value
14221 getValue : function()
14223 if(Roo.isIOS && this.useNativeIOS){
14224 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14228 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14231 if(this.valueField){
14232 return typeof this.value != 'undefined' ? this.value : '';
14234 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14238 getRawValue : function()
14240 if(Roo.isIOS && this.useNativeIOS){
14241 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14244 var v = this.inputEl().getValue();
14250 * Clears any text/value currently set in the field
14252 clearValue : function(){
14254 if(this.hiddenField){
14255 this.hiddenField.dom.value = '';
14258 this.setRawValue('');
14259 this.lastSelectionText = '';
14260 this.lastData = false;
14262 var close = this.closeTriggerEl();
14273 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14274 * will be displayed in the field. If the value does not match the data value of an existing item,
14275 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14276 * Otherwise the field will be blank (although the value will still be set).
14277 * @param {String} value The value to match
14279 setValue : function(v)
14281 if(Roo.isIOS && this.useNativeIOS){
14282 this.setIOSValue(v);
14292 if(this.valueField){
14293 var r = this.findRecord(this.valueField, v);
14295 text = r.data[this.displayField];
14296 }else if(this.valueNotFoundText !== undefined){
14297 text = this.valueNotFoundText;
14300 this.lastSelectionText = text;
14301 if(this.hiddenField){
14302 this.hiddenField.dom.value = v;
14304 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14307 var close = this.closeTriggerEl();
14310 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14316 * @property {Object} the last set data for the element
14321 * Sets the value of the field based on a object which is related to the record format for the store.
14322 * @param {Object} value the value to set as. or false on reset?
14324 setFromData : function(o){
14331 var dv = ''; // display value
14332 var vv = ''; // value value..
14334 if (this.displayField) {
14335 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14337 // this is an error condition!!!
14338 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14341 if(this.valueField){
14342 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14345 var close = this.closeTriggerEl();
14348 if(dv.length || vv * 1 > 0){
14350 this.blockFocus=true;
14356 if(this.hiddenField){
14357 this.hiddenField.dom.value = vv;
14359 this.lastSelectionText = dv;
14360 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14364 // no hidden field.. - we store the value in 'value', but still display
14365 // display field!!!!
14366 this.lastSelectionText = dv;
14367 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14374 reset : function(){
14375 // overridden so that last data is reset..
14382 this.setValue(this.originalValue);
14383 //this.clearInvalid();
14384 this.lastData = false;
14386 this.view.clearSelections();
14392 findRecord : function(prop, value){
14394 if(this.store.getCount() > 0){
14395 this.store.each(function(r){
14396 if(r.data[prop] == value){
14406 getName: function()
14408 // returns hidden if it's set..
14409 if (!this.rendered) {return ''};
14410 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14414 onViewMove : function(e, t){
14415 this.inKeyMode = false;
14419 onViewOver : function(e, t){
14420 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14423 var item = this.view.findItemFromChild(t);
14426 var index = this.view.indexOf(item);
14427 this.select(index, false);
14432 onViewClick : function(view, doFocus, el, e)
14434 var index = this.view.getSelectedIndexes()[0];
14436 var r = this.store.getAt(index);
14440 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14447 Roo.each(this.tickItems, function(v,k){
14449 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14451 _this.tickItems.splice(k, 1);
14453 if(typeof(e) == 'undefined' && view == false){
14454 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14466 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14467 this.tickItems.push(r.data);
14470 if(typeof(e) == 'undefined' && view == false){
14471 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14478 this.onSelect(r, index);
14480 if(doFocus !== false && !this.blockFocus){
14481 this.inputEl().focus();
14486 restrictHeight : function(){
14487 //this.innerList.dom.style.height = '';
14488 //var inner = this.innerList.dom;
14489 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14490 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14491 //this.list.beginUpdate();
14492 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14493 this.list.alignTo(this.inputEl(), this.listAlign);
14494 this.list.alignTo(this.inputEl(), this.listAlign);
14495 //this.list.endUpdate();
14499 onEmptyResults : function(){
14501 if(this.tickable && this.editable){
14502 this.hasFocus = false;
14503 this.restrictHeight();
14511 * Returns true if the dropdown list is expanded, else false.
14513 isExpanded : function(){
14514 return this.list.isVisible();
14518 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14519 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14520 * @param {String} value The data value of the item to select
14521 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14522 * selected item if it is not currently in view (defaults to true)
14523 * @return {Boolean} True if the value matched an item in the list, else false
14525 selectByValue : function(v, scrollIntoView){
14526 if(v !== undefined && v !== null){
14527 var r = this.findRecord(this.valueField || this.displayField, v);
14529 this.select(this.store.indexOf(r), scrollIntoView);
14537 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14538 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14539 * @param {Number} index The zero-based index of the list item to select
14540 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14541 * selected item if it is not currently in view (defaults to true)
14543 select : function(index, scrollIntoView){
14544 this.selectedIndex = index;
14545 this.view.select(index);
14546 if(scrollIntoView !== false){
14547 var el = this.view.getNode(index);
14549 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14552 this.list.scrollChildIntoView(el, false);
14558 selectNext : function(){
14559 var ct = this.store.getCount();
14561 if(this.selectedIndex == -1){
14563 }else if(this.selectedIndex < ct-1){
14564 this.select(this.selectedIndex+1);
14570 selectPrev : function(){
14571 var ct = this.store.getCount();
14573 if(this.selectedIndex == -1){
14575 }else if(this.selectedIndex != 0){
14576 this.select(this.selectedIndex-1);
14582 onKeyUp : function(e){
14583 if(this.editable !== false && !e.isSpecialKey()){
14584 this.lastKey = e.getKey();
14585 this.dqTask.delay(this.queryDelay);
14590 validateBlur : function(){
14591 return !this.list || !this.list.isVisible();
14595 initQuery : function(){
14597 var v = this.getRawValue();
14599 if(this.tickable && this.editable){
14600 v = this.tickableInputEl().getValue();
14607 doForce : function(){
14608 if(this.inputEl().dom.value.length > 0){
14609 this.inputEl().dom.value =
14610 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14616 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14617 * query allowing the query action to be canceled if needed.
14618 * @param {String} query The SQL query to execute
14619 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14620 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14621 * saved in the current store (defaults to false)
14623 doQuery : function(q, forceAll){
14625 if(q === undefined || q === null){
14630 forceAll: forceAll,
14634 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14639 forceAll = qe.forceAll;
14640 if(forceAll === true || (q.length >= this.minChars)){
14642 this.hasQuery = true;
14644 if(this.lastQuery != q || this.alwaysQuery){
14645 this.lastQuery = q;
14646 if(this.mode == 'local'){
14647 this.selectedIndex = -1;
14649 this.store.clearFilter();
14652 if(this.specialFilter){
14653 this.fireEvent('specialfilter', this);
14658 this.store.filter(this.displayField, q);
14661 this.store.fireEvent("datachanged", this.store);
14668 this.store.baseParams[this.queryParam] = q;
14670 var options = {params : this.getParams(q)};
14673 options.add = true;
14674 options.params.start = this.page * this.pageSize;
14677 this.store.load(options);
14680 * this code will make the page width larger, at the beginning, the list not align correctly,
14681 * we should expand the list on onLoad
14682 * so command out it
14687 this.selectedIndex = -1;
14692 this.loadNext = false;
14696 getParams : function(q){
14698 //p[this.queryParam] = q;
14702 p.limit = this.pageSize;
14708 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14710 collapse : function(){
14711 if(!this.isExpanded()){
14717 this.hasFocus = false;
14721 this.cancelBtn.hide();
14722 this.trigger.show();
14725 this.tickableInputEl().dom.value = '';
14726 this.tickableInputEl().blur();
14731 Roo.get(document).un('mousedown', this.collapseIf, this);
14732 Roo.get(document).un('mousewheel', this.collapseIf, this);
14733 if (!this.editable) {
14734 Roo.get(document).un('keydown', this.listKeyPress, this);
14736 this.fireEvent('collapse', this);
14742 collapseIf : function(e){
14743 var in_combo = e.within(this.el);
14744 var in_list = e.within(this.list);
14745 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14747 if (in_combo || in_list || is_list) {
14748 //e.stopPropagation();
14753 this.onTickableFooterButtonClick(e, false, false);
14761 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14763 expand : function(){
14765 if(this.isExpanded() || !this.hasFocus){
14769 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14770 this.list.setWidth(lw);
14776 this.restrictHeight();
14780 this.tickItems = Roo.apply([], this.item);
14783 this.cancelBtn.show();
14784 this.trigger.hide();
14787 this.tickableInputEl().focus();
14792 Roo.get(document).on('mousedown', this.collapseIf, this);
14793 Roo.get(document).on('mousewheel', this.collapseIf, this);
14794 if (!this.editable) {
14795 Roo.get(document).on('keydown', this.listKeyPress, this);
14798 this.fireEvent('expand', this);
14802 // Implements the default empty TriggerField.onTriggerClick function
14803 onTriggerClick : function(e)
14805 Roo.log('trigger click');
14807 if(this.disabled || !this.triggerList){
14812 this.loadNext = false;
14814 if(this.isExpanded()){
14816 if (!this.blockFocus) {
14817 this.inputEl().focus();
14821 this.hasFocus = true;
14822 if(this.triggerAction == 'all') {
14823 this.doQuery(this.allQuery, true);
14825 this.doQuery(this.getRawValue());
14827 if (!this.blockFocus) {
14828 this.inputEl().focus();
14833 onTickableTriggerClick : function(e)
14840 this.loadNext = false;
14841 this.hasFocus = true;
14843 if(this.triggerAction == 'all') {
14844 this.doQuery(this.allQuery, true);
14846 this.doQuery(this.getRawValue());
14850 onSearchFieldClick : function(e)
14852 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14853 this.onTickableFooterButtonClick(e, false, false);
14857 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14862 this.loadNext = false;
14863 this.hasFocus = true;
14865 if(this.triggerAction == 'all') {
14866 this.doQuery(this.allQuery, true);
14868 this.doQuery(this.getRawValue());
14872 listKeyPress : function(e)
14874 //Roo.log('listkeypress');
14875 // scroll to first matching element based on key pres..
14876 if (e.isSpecialKey()) {
14879 var k = String.fromCharCode(e.getKey()).toUpperCase();
14882 var csel = this.view.getSelectedNodes();
14883 var cselitem = false;
14885 var ix = this.view.indexOf(csel[0]);
14886 cselitem = this.store.getAt(ix);
14887 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14893 this.store.each(function(v) {
14895 // start at existing selection.
14896 if (cselitem.id == v.id) {
14902 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14903 match = this.store.indexOf(v);
14909 if (match === false) {
14910 return true; // no more action?
14913 this.view.select(match);
14914 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14915 sn.scrollIntoView(sn.dom.parentNode, false);
14918 onViewScroll : function(e, t){
14920 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){
14924 this.hasQuery = true;
14926 this.loading = this.list.select('.loading', true).first();
14928 if(this.loading === null){
14929 this.list.createChild({
14931 cls: 'loading roo-select2-more-results roo-select2-active',
14932 html: 'Loading more results...'
14935 this.loading = this.list.select('.loading', true).first();
14937 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14939 this.loading.hide();
14942 this.loading.show();
14947 this.loadNext = true;
14949 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
14954 addItem : function(o)
14956 var dv = ''; // display value
14958 if (this.displayField) {
14959 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14961 // this is an error condition!!!
14962 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14969 var choice = this.choices.createChild({
14971 cls: 'roo-select2-search-choice',
14980 cls: 'roo-select2-search-choice-close fa fa-times',
14985 }, this.searchField);
14987 var close = choice.select('a.roo-select2-search-choice-close', true).first();
14989 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
14997 this.inputEl().dom.value = '';
15002 onRemoveItem : function(e, _self, o)
15004 e.preventDefault();
15006 this.lastItem = Roo.apply([], this.item);
15008 var index = this.item.indexOf(o.data) * 1;
15011 Roo.log('not this item?!');
15015 this.item.splice(index, 1);
15020 this.fireEvent('remove', this, e);
15026 syncValue : function()
15028 if(!this.item.length){
15035 Roo.each(this.item, function(i){
15036 if(_this.valueField){
15037 value.push(i[_this.valueField]);
15044 this.value = value.join(',');
15046 if(this.hiddenField){
15047 this.hiddenField.dom.value = this.value;
15050 this.store.fireEvent("datachanged", this.store);
15055 clearItem : function()
15057 if(!this.multiple){
15063 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15071 if(this.tickable && !Roo.isTouch){
15072 this.view.refresh();
15076 inputEl: function ()
15078 if(Roo.isIOS && this.useNativeIOS){
15079 return this.el.select('select.roo-ios-select', true).first();
15082 if(Roo.isTouch && this.mobileTouchView){
15083 return this.el.select('input.form-control',true).first();
15087 return this.searchField;
15090 return this.el.select('input.form-control',true).first();
15093 onTickableFooterButtonClick : function(e, btn, el)
15095 e.preventDefault();
15097 this.lastItem = Roo.apply([], this.item);
15099 if(btn && btn.name == 'cancel'){
15100 this.tickItems = Roo.apply([], this.item);
15109 Roo.each(this.tickItems, function(o){
15117 validate : function()
15119 if(this.getVisibilityEl().hasClass('hidden')){
15123 var v = this.getRawValue();
15126 v = this.getValue();
15129 if(this.disabled || this.allowBlank || v.length){
15134 this.markInvalid();
15138 tickableInputEl : function()
15140 if(!this.tickable || !this.editable){
15141 return this.inputEl();
15144 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15148 getAutoCreateTouchView : function()
15153 cls: 'form-group' //input-group
15159 type : this.inputType,
15160 cls : 'form-control x-combo-noedit',
15161 autocomplete: 'new-password',
15162 placeholder : this.placeholder || '',
15167 input.name = this.name;
15171 input.cls += ' input-' + this.size;
15174 if (this.disabled) {
15175 input.disabled = true;
15186 inputblock.cls += ' input-group';
15188 inputblock.cn.unshift({
15190 cls : 'input-group-addon input-group-prepend input-group-text',
15195 if(this.removable && !this.multiple){
15196 inputblock.cls += ' roo-removable';
15198 inputblock.cn.push({
15201 cls : 'roo-combo-removable-btn close'
15205 if(this.hasFeedback && !this.allowBlank){
15207 inputblock.cls += ' has-feedback';
15209 inputblock.cn.push({
15211 cls: 'glyphicon form-control-feedback'
15218 inputblock.cls += (this.before) ? '' : ' input-group';
15220 inputblock.cn.push({
15222 cls : 'input-group-addon input-group-append input-group-text',
15228 var ibwrap = inputblock;
15233 cls: 'roo-select2-choices',
15237 cls: 'roo-select2-search-field',
15250 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15255 cls: 'form-hidden-field'
15261 if(!this.multiple && this.showToggleBtn){
15268 if (this.caret != false) {
15271 cls: 'fa fa-' + this.caret
15278 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15283 cls: 'combobox-clear',
15297 combobox.cls += ' roo-select2-container-multi';
15300 var align = this.labelAlign || this.parentLabelAlign();
15302 if (align ==='left' && this.fieldLabel.length) {
15307 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15308 tooltip : 'This field is required'
15312 cls : 'control-label col-form-label',
15313 html : this.fieldLabel
15324 var labelCfg = cfg.cn[1];
15325 var contentCfg = cfg.cn[2];
15328 if(this.indicatorpos == 'right'){
15333 cls : 'control-label col-form-label',
15337 html : this.fieldLabel
15341 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15342 tooltip : 'This field is required'
15355 labelCfg = cfg.cn[0];
15356 contentCfg = cfg.cn[1];
15361 if(this.labelWidth > 12){
15362 labelCfg.style = "width: " + this.labelWidth + 'px';
15365 if(this.labelWidth < 13 && this.labelmd == 0){
15366 this.labelmd = this.labelWidth;
15369 if(this.labellg > 0){
15370 labelCfg.cls += ' col-lg-' + this.labellg;
15371 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15374 if(this.labelmd > 0){
15375 labelCfg.cls += ' col-md-' + this.labelmd;
15376 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15379 if(this.labelsm > 0){
15380 labelCfg.cls += ' col-sm-' + this.labelsm;
15381 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15384 if(this.labelxs > 0){
15385 labelCfg.cls += ' col-xs-' + this.labelxs;
15386 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15390 } else if ( this.fieldLabel.length) {
15394 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15395 tooltip : 'This field is required'
15399 cls : 'control-label',
15400 html : this.fieldLabel
15411 if(this.indicatorpos == 'right'){
15415 cls : 'control-label',
15416 html : this.fieldLabel,
15420 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15421 tooltip : 'This field is required'
15438 var settings = this;
15440 ['xs','sm','md','lg'].map(function(size){
15441 if (settings[size]) {
15442 cfg.cls += ' col-' + size + '-' + settings[size];
15449 initTouchView : function()
15451 this.renderTouchView();
15453 this.touchViewEl.on('scroll', function(){
15454 this.el.dom.scrollTop = 0;
15457 this.originalValue = this.getValue();
15459 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15461 this.inputEl().on("click", this.showTouchView, this);
15462 if (this.triggerEl) {
15463 this.triggerEl.on("click", this.showTouchView, this);
15467 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15468 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15470 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15472 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15473 this.store.on('load', this.onTouchViewLoad, this);
15474 this.store.on('loadexception', this.onTouchViewLoadException, this);
15476 if(this.hiddenName){
15478 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15480 this.hiddenField.dom.value =
15481 this.hiddenValue !== undefined ? this.hiddenValue :
15482 this.value !== undefined ? this.value : '';
15484 this.el.dom.removeAttribute('name');
15485 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15489 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15490 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15493 if(this.removable && !this.multiple){
15494 var close = this.closeTriggerEl();
15496 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15497 close.on('click', this.removeBtnClick, this, close);
15501 * fix the bug in Safari iOS8
15503 this.inputEl().on("focus", function(e){
15504 document.activeElement.blur();
15507 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15514 renderTouchView : function()
15516 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15517 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15519 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15520 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15522 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15523 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15524 this.touchViewBodyEl.setStyle('overflow', 'auto');
15526 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15527 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15529 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15530 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15534 showTouchView : function()
15540 this.touchViewHeaderEl.hide();
15542 if(this.modalTitle.length){
15543 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15544 this.touchViewHeaderEl.show();
15547 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15548 this.touchViewEl.show();
15550 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15552 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15553 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15555 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15557 if(this.modalTitle.length){
15558 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15561 this.touchViewBodyEl.setHeight(bodyHeight);
15565 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15567 this.touchViewEl.addClass('in');
15570 if(this._touchViewMask){
15571 Roo.get(document.body).addClass("x-body-masked");
15572 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15573 this._touchViewMask.setStyle('z-index', 10000);
15574 this._touchViewMask.addClass('show');
15577 this.doTouchViewQuery();
15581 hideTouchView : function()
15583 this.touchViewEl.removeClass('in');
15587 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15589 this.touchViewEl.setStyle('display', 'none');
15592 if(this._touchViewMask){
15593 this._touchViewMask.removeClass('show');
15594 Roo.get(document.body).removeClass("x-body-masked");
15598 setTouchViewValue : function()
15605 Roo.each(this.tickItems, function(o){
15610 this.hideTouchView();
15613 doTouchViewQuery : function()
15622 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15626 if(!this.alwaysQuery || this.mode == 'local'){
15627 this.onTouchViewLoad();
15634 onTouchViewBeforeLoad : function(combo,opts)
15640 onTouchViewLoad : function()
15642 if(this.store.getCount() < 1){
15643 this.onTouchViewEmptyResults();
15647 this.clearTouchView();
15649 var rawValue = this.getRawValue();
15651 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15653 this.tickItems = [];
15655 this.store.data.each(function(d, rowIndex){
15656 var row = this.touchViewListGroup.createChild(template);
15658 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15659 row.addClass(d.data.cls);
15662 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15665 html : d.data[this.displayField]
15668 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15669 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15672 row.removeClass('selected');
15673 if(!this.multiple && this.valueField &&
15674 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15677 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15678 row.addClass('selected');
15681 if(this.multiple && this.valueField &&
15682 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15686 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15687 this.tickItems.push(d.data);
15690 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15694 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15696 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15698 if(this.modalTitle.length){
15699 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15702 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15704 if(this.mobile_restrict_height && listHeight < bodyHeight){
15705 this.touchViewBodyEl.setHeight(listHeight);
15710 if(firstChecked && listHeight > bodyHeight){
15711 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15716 onTouchViewLoadException : function()
15718 this.hideTouchView();
15721 onTouchViewEmptyResults : function()
15723 this.clearTouchView();
15725 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15727 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15731 clearTouchView : function()
15733 this.touchViewListGroup.dom.innerHTML = '';
15736 onTouchViewClick : function(e, el, o)
15738 e.preventDefault();
15741 var rowIndex = o.rowIndex;
15743 var r = this.store.getAt(rowIndex);
15745 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15747 if(!this.multiple){
15748 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15749 c.dom.removeAttribute('checked');
15752 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15754 this.setFromData(r.data);
15756 var close = this.closeTriggerEl();
15762 this.hideTouchView();
15764 this.fireEvent('select', this, r, rowIndex);
15769 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15770 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15771 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15775 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15776 this.addItem(r.data);
15777 this.tickItems.push(r.data);
15781 getAutoCreateNativeIOS : function()
15784 cls: 'form-group' //input-group,
15789 cls : 'roo-ios-select'
15793 combobox.name = this.name;
15796 if (this.disabled) {
15797 combobox.disabled = true;
15800 var settings = this;
15802 ['xs','sm','md','lg'].map(function(size){
15803 if (settings[size]) {
15804 cfg.cls += ' col-' + size + '-' + settings[size];
15814 initIOSView : function()
15816 this.store.on('load', this.onIOSViewLoad, this);
15821 onIOSViewLoad : function()
15823 if(this.store.getCount() < 1){
15827 this.clearIOSView();
15829 if(this.allowBlank) {
15831 var default_text = '-- SELECT --';
15833 if(this.placeholder.length){
15834 default_text = this.placeholder;
15837 if(this.emptyTitle.length){
15838 default_text += ' - ' + this.emptyTitle + ' -';
15841 var opt = this.inputEl().createChild({
15844 html : default_text
15848 o[this.valueField] = 0;
15849 o[this.displayField] = default_text;
15851 this.ios_options.push({
15858 this.store.data.each(function(d, rowIndex){
15862 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15863 html = d.data[this.displayField];
15868 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15869 value = d.data[this.valueField];
15878 if(this.value == d.data[this.valueField]){
15879 option['selected'] = true;
15882 var opt = this.inputEl().createChild(option);
15884 this.ios_options.push({
15891 this.inputEl().on('change', function(){
15892 this.fireEvent('select', this);
15897 clearIOSView: function()
15899 this.inputEl().dom.innerHTML = '';
15901 this.ios_options = [];
15904 setIOSValue: function(v)
15908 if(!this.ios_options){
15912 Roo.each(this.ios_options, function(opts){
15914 opts.el.dom.removeAttribute('selected');
15916 if(opts.data[this.valueField] != v){
15920 opts.el.dom.setAttribute('selected', true);
15926 * @cfg {Boolean} grow
15930 * @cfg {Number} growMin
15934 * @cfg {Number} growMax
15943 Roo.apply(Roo.bootstrap.ComboBox, {
15947 cls: 'modal-header',
15969 cls: 'list-group-item',
15973 cls: 'roo-combobox-list-group-item-value'
15977 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
15991 listItemCheckbox : {
15993 cls: 'list-group-item',
15997 cls: 'roo-combobox-list-group-item-value'
16001 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16017 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16022 cls: 'modal-footer',
16030 cls: 'col-xs-6 text-left',
16033 cls: 'btn btn-danger roo-touch-view-cancel',
16039 cls: 'col-xs-6 text-right',
16042 cls: 'btn btn-success roo-touch-view-ok',
16053 Roo.apply(Roo.bootstrap.ComboBox, {
16055 touchViewTemplate : {
16057 cls: 'modal fade roo-combobox-touch-view',
16061 cls: 'modal-dialog',
16062 style : 'position:fixed', // we have to fix position....
16066 cls: 'modal-content',
16068 Roo.bootstrap.ComboBox.header,
16069 Roo.bootstrap.ComboBox.body,
16070 Roo.bootstrap.ComboBox.footer
16079 * Ext JS Library 1.1.1
16080 * Copyright(c) 2006-2007, Ext JS, LLC.
16082 * Originally Released Under LGPL - original licence link has changed is not relivant.
16085 * <script type="text/javascript">
16090 * @extends Roo.util.Observable
16091 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16092 * This class also supports single and multi selection modes. <br>
16093 * Create a data model bound view:
16095 var store = new Roo.data.Store(...);
16097 var view = new Roo.View({
16099 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16101 singleSelect: true,
16102 selectedClass: "ydataview-selected",
16106 // listen for node click?
16107 view.on("click", function(vw, index, node, e){
16108 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16112 dataModel.load("foobar.xml");
16114 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16116 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16117 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16119 * Note: old style constructor is still suported (container, template, config)
16122 * Create a new View
16123 * @param {Object} config The config object
16126 Roo.View = function(config, depreciated_tpl, depreciated_config){
16128 this.parent = false;
16130 if (typeof(depreciated_tpl) == 'undefined') {
16131 // new way.. - universal constructor.
16132 Roo.apply(this, config);
16133 this.el = Roo.get(this.el);
16136 this.el = Roo.get(config);
16137 this.tpl = depreciated_tpl;
16138 Roo.apply(this, depreciated_config);
16140 this.wrapEl = this.el.wrap().wrap();
16141 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16144 if(typeof(this.tpl) == "string"){
16145 this.tpl = new Roo.Template(this.tpl);
16147 // support xtype ctors..
16148 this.tpl = new Roo.factory(this.tpl, Roo);
16152 this.tpl.compile();
16157 * @event beforeclick
16158 * Fires before a click is processed. Returns false to cancel the default action.
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
16164 "beforeclick" : true,
16167 * Fires when a template node is 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
16176 * Fires when a template node is double 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
16184 * @event contextmenu
16185 * Fires when a template node is right clicked.
16186 * @param {Roo.View} this
16187 * @param {Number} index The index of the target node
16188 * @param {HTMLElement} node The target node
16189 * @param {Roo.EventObject} e The raw event object
16191 "contextmenu" : true,
16193 * @event selectionchange
16194 * Fires when the selected nodes change.
16195 * @param {Roo.View} this
16196 * @param {Array} selections Array of the selected nodes
16198 "selectionchange" : true,
16201 * @event beforeselect
16202 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16203 * @param {Roo.View} this
16204 * @param {HTMLElement} node The node to be selected
16205 * @param {Array} selections Array of currently selected nodes
16207 "beforeselect" : true,
16209 * @event preparedata
16210 * Fires on every row to render, to allow you to change the data.
16211 * @param {Roo.View} this
16212 * @param {Object} data to be rendered (change this)
16214 "preparedata" : true
16222 "click": this.onClick,
16223 "dblclick": this.onDblClick,
16224 "contextmenu": this.onContextMenu,
16228 this.selections = [];
16230 this.cmp = new Roo.CompositeElementLite([]);
16232 this.store = Roo.factory(this.store, Roo.data);
16233 this.setStore(this.store, true);
16236 if ( this.footer && this.footer.xtype) {
16238 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16240 this.footer.dataSource = this.store;
16241 this.footer.container = fctr;
16242 this.footer = Roo.factory(this.footer, Roo);
16243 fctr.insertFirst(this.el);
16245 // this is a bit insane - as the paging toolbar seems to detach the el..
16246 // dom.parentNode.parentNode.parentNode
16247 // they get detached?
16251 Roo.View.superclass.constructor.call(this);
16256 Roo.extend(Roo.View, Roo.util.Observable, {
16259 * @cfg {Roo.data.Store} store Data store to load data from.
16264 * @cfg {String|Roo.Element} el The container element.
16269 * @cfg {String|Roo.Template} tpl The template used by this View
16273 * @cfg {String} dataName the named area of the template to use as the data area
16274 * Works with domtemplates roo-name="name"
16278 * @cfg {String} selectedClass The css class to add to selected nodes
16280 selectedClass : "x-view-selected",
16282 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16287 * @cfg {String} text to display on mask (default Loading)
16291 * @cfg {Boolean} multiSelect Allow multiple selection
16293 multiSelect : false,
16295 * @cfg {Boolean} singleSelect Allow single selection
16297 singleSelect: false,
16300 * @cfg {Boolean} toggleSelect - selecting
16302 toggleSelect : false,
16305 * @cfg {Boolean} tickable - selecting
16310 * Returns the element this view is bound to.
16311 * @return {Roo.Element}
16313 getEl : function(){
16314 return this.wrapEl;
16320 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16322 refresh : function(){
16323 //Roo.log('refresh');
16326 // if we are using something like 'domtemplate', then
16327 // the what gets used is:
16328 // t.applySubtemplate(NAME, data, wrapping data..)
16329 // the outer template then get' applied with
16330 // the store 'extra data'
16331 // and the body get's added to the
16332 // roo-name="data" node?
16333 // <span class='roo-tpl-{name}'></span> ?????
16337 this.clearSelections();
16338 this.el.update("");
16340 var records = this.store.getRange();
16341 if(records.length < 1) {
16343 // is this valid?? = should it render a template??
16345 this.el.update(this.emptyText);
16349 if (this.dataName) {
16350 this.el.update(t.apply(this.store.meta)); //????
16351 el = this.el.child('.roo-tpl-' + this.dataName);
16354 for(var i = 0, len = records.length; i < len; i++){
16355 var data = this.prepareData(records[i].data, i, records[i]);
16356 this.fireEvent("preparedata", this, data, i, records[i]);
16358 var d = Roo.apply({}, data);
16361 Roo.apply(d, {'roo-id' : Roo.id()});
16365 Roo.each(this.parent.item, function(item){
16366 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16369 Roo.apply(d, {'roo-data-checked' : 'checked'});
16373 html[html.length] = Roo.util.Format.trim(
16375 t.applySubtemplate(this.dataName, d, this.store.meta) :
16382 el.update(html.join(""));
16383 this.nodes = el.dom.childNodes;
16384 this.updateIndexes(0);
16389 * Function to override to reformat the data that is sent to
16390 * the template for each node.
16391 * DEPRICATED - use the preparedata event handler.
16392 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16393 * a JSON object for an UpdateManager bound view).
16395 prepareData : function(data, index, record)
16397 this.fireEvent("preparedata", this, data, index, record);
16401 onUpdate : function(ds, record){
16402 // Roo.log('on update');
16403 this.clearSelections();
16404 var index = this.store.indexOf(record);
16405 var n = this.nodes[index];
16406 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16407 n.parentNode.removeChild(n);
16408 this.updateIndexes(index, index);
16414 onAdd : function(ds, records, index)
16416 //Roo.log(['on Add', ds, records, index] );
16417 this.clearSelections();
16418 if(this.nodes.length == 0){
16422 var n = this.nodes[index];
16423 for(var i = 0, len = records.length; i < len; i++){
16424 var d = this.prepareData(records[i].data, i, records[i]);
16426 this.tpl.insertBefore(n, d);
16429 this.tpl.append(this.el, d);
16432 this.updateIndexes(index);
16435 onRemove : function(ds, record, index){
16436 // Roo.log('onRemove');
16437 this.clearSelections();
16438 var el = this.dataName ?
16439 this.el.child('.roo-tpl-' + this.dataName) :
16442 el.dom.removeChild(this.nodes[index]);
16443 this.updateIndexes(index);
16447 * Refresh an individual node.
16448 * @param {Number} index
16450 refreshNode : function(index){
16451 this.onUpdate(this.store, this.store.getAt(index));
16454 updateIndexes : function(startIndex, endIndex){
16455 var ns = this.nodes;
16456 startIndex = startIndex || 0;
16457 endIndex = endIndex || ns.length - 1;
16458 for(var i = startIndex; i <= endIndex; i++){
16459 ns[i].nodeIndex = i;
16464 * Changes the data store this view uses and refresh the view.
16465 * @param {Store} store
16467 setStore : function(store, initial){
16468 if(!initial && this.store){
16469 this.store.un("datachanged", this.refresh);
16470 this.store.un("add", this.onAdd);
16471 this.store.un("remove", this.onRemove);
16472 this.store.un("update", this.onUpdate);
16473 this.store.un("clear", this.refresh);
16474 this.store.un("beforeload", this.onBeforeLoad);
16475 this.store.un("load", this.onLoad);
16476 this.store.un("loadexception", this.onLoad);
16480 store.on("datachanged", this.refresh, this);
16481 store.on("add", this.onAdd, this);
16482 store.on("remove", this.onRemove, this);
16483 store.on("update", this.onUpdate, this);
16484 store.on("clear", this.refresh, this);
16485 store.on("beforeload", this.onBeforeLoad, this);
16486 store.on("load", this.onLoad, this);
16487 store.on("loadexception", this.onLoad, this);
16495 * onbeforeLoad - masks the loading area.
16498 onBeforeLoad : function(store,opts)
16500 //Roo.log('onBeforeLoad');
16502 this.el.update("");
16504 this.el.mask(this.mask ? this.mask : "Loading" );
16506 onLoad : function ()
16513 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16514 * @param {HTMLElement} node
16515 * @return {HTMLElement} The template node
16517 findItemFromChild : function(node){
16518 var el = this.dataName ?
16519 this.el.child('.roo-tpl-' + this.dataName,true) :
16522 if(!node || node.parentNode == el){
16525 var p = node.parentNode;
16526 while(p && p != el){
16527 if(p.parentNode == el){
16536 onClick : function(e){
16537 var item = this.findItemFromChild(e.getTarget());
16539 var index = this.indexOf(item);
16540 if(this.onItemClick(item, index, e) !== false){
16541 this.fireEvent("click", this, index, item, e);
16544 this.clearSelections();
16549 onContextMenu : function(e){
16550 var item = this.findItemFromChild(e.getTarget());
16552 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16557 onDblClick : function(e){
16558 var item = this.findItemFromChild(e.getTarget());
16560 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16564 onItemClick : function(item, index, e)
16566 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16569 if (this.toggleSelect) {
16570 var m = this.isSelected(item) ? 'unselect' : 'select';
16573 _t[m](item, true, false);
16576 if(this.multiSelect || this.singleSelect){
16577 if(this.multiSelect && e.shiftKey && this.lastSelection){
16578 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16580 this.select(item, this.multiSelect && e.ctrlKey);
16581 this.lastSelection = item;
16584 if(!this.tickable){
16585 e.preventDefault();
16593 * Get the number of selected nodes.
16596 getSelectionCount : function(){
16597 return this.selections.length;
16601 * Get the currently selected nodes.
16602 * @return {Array} An array of HTMLElements
16604 getSelectedNodes : function(){
16605 return this.selections;
16609 * Get the indexes of the selected nodes.
16612 getSelectedIndexes : function(){
16613 var indexes = [], s = this.selections;
16614 for(var i = 0, len = s.length; i < len; i++){
16615 indexes.push(s[i].nodeIndex);
16621 * Clear all selections
16622 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16624 clearSelections : function(suppressEvent){
16625 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16626 this.cmp.elements = this.selections;
16627 this.cmp.removeClass(this.selectedClass);
16628 this.selections = [];
16629 if(!suppressEvent){
16630 this.fireEvent("selectionchange", this, this.selections);
16636 * Returns true if the passed node is selected
16637 * @param {HTMLElement/Number} node The node or node index
16638 * @return {Boolean}
16640 isSelected : function(node){
16641 var s = this.selections;
16645 node = this.getNode(node);
16646 return s.indexOf(node) !== -1;
16651 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
16652 * @param {Boolean} keepExisting (optional) true to keep existing selections
16653 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16655 select : function(nodeInfo, keepExisting, suppressEvent){
16656 if(nodeInfo instanceof Array){
16658 this.clearSelections(true);
16660 for(var i = 0, len = nodeInfo.length; i < len; i++){
16661 this.select(nodeInfo[i], true, true);
16665 var node = this.getNode(nodeInfo);
16666 if(!node || this.isSelected(node)){
16667 return; // already selected.
16670 this.clearSelections(true);
16673 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16674 Roo.fly(node).addClass(this.selectedClass);
16675 this.selections.push(node);
16676 if(!suppressEvent){
16677 this.fireEvent("selectionchange", this, this.selections);
16685 * @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
16686 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16687 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16689 unselect : function(nodeInfo, keepExisting, suppressEvent)
16691 if(nodeInfo instanceof Array){
16692 Roo.each(this.selections, function(s) {
16693 this.unselect(s, nodeInfo);
16697 var node = this.getNode(nodeInfo);
16698 if(!node || !this.isSelected(node)){
16699 //Roo.log("not selected");
16700 return; // not selected.
16704 Roo.each(this.selections, function(s) {
16706 Roo.fly(node).removeClass(this.selectedClass);
16713 this.selections= ns;
16714 this.fireEvent("selectionchange", this, this.selections);
16718 * Gets a template node.
16719 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16720 * @return {HTMLElement} The node or null if it wasn't found
16722 getNode : function(nodeInfo){
16723 if(typeof nodeInfo == "string"){
16724 return document.getElementById(nodeInfo);
16725 }else if(typeof nodeInfo == "number"){
16726 return this.nodes[nodeInfo];
16732 * Gets a range template nodes.
16733 * @param {Number} startIndex
16734 * @param {Number} endIndex
16735 * @return {Array} An array of nodes
16737 getNodes : function(start, end){
16738 var ns = this.nodes;
16739 start = start || 0;
16740 end = typeof end == "undefined" ? ns.length - 1 : end;
16743 for(var i = start; i <= end; i++){
16747 for(var i = start; i >= end; i--){
16755 * Finds the index of the passed node
16756 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16757 * @return {Number} The index of the node or -1
16759 indexOf : function(node){
16760 node = this.getNode(node);
16761 if(typeof node.nodeIndex == "number"){
16762 return node.nodeIndex;
16764 var ns = this.nodes;
16765 for(var i = 0, len = ns.length; i < len; i++){
16776 * based on jquery fullcalendar
16780 Roo.bootstrap = Roo.bootstrap || {};
16782 * @class Roo.bootstrap.Calendar
16783 * @extends Roo.bootstrap.Component
16784 * Bootstrap Calendar class
16785 * @cfg {Boolean} loadMask (true|false) default false
16786 * @cfg {Object} header generate the user specific header of the calendar, default false
16789 * Create a new Container
16790 * @param {Object} config The config object
16795 Roo.bootstrap.Calendar = function(config){
16796 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16800 * Fires when a date is selected
16801 * @param {DatePicker} this
16802 * @param {Date} date The selected date
16806 * @event monthchange
16807 * Fires when the displayed month changes
16808 * @param {DatePicker} this
16809 * @param {Date} date The selected month
16811 'monthchange': true,
16813 * @event evententer
16814 * Fires when mouse over an event
16815 * @param {Calendar} this
16816 * @param {event} Event
16818 'evententer': true,
16820 * @event eventleave
16821 * Fires when the mouse leaves an
16822 * @param {Calendar} this
16825 'eventleave': true,
16827 * @event eventclick
16828 * Fires when the mouse click an
16829 * @param {Calendar} this
16838 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16841 * @cfg {Number} startDay
16842 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16850 getAutoCreate : function(){
16853 var fc_button = function(name, corner, style, content ) {
16854 return Roo.apply({},{
16856 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16858 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16861 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16872 style : 'width:100%',
16879 cls : 'fc-header-left',
16881 fc_button('prev', 'left', 'arrow', '‹' ),
16882 fc_button('next', 'right', 'arrow', '›' ),
16883 { tag: 'span', cls: 'fc-header-space' },
16884 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16892 cls : 'fc-header-center',
16896 cls: 'fc-header-title',
16899 html : 'month / year'
16907 cls : 'fc-header-right',
16909 /* fc_button('month', 'left', '', 'month' ),
16910 fc_button('week', '', '', 'week' ),
16911 fc_button('day', 'right', '', 'day' )
16923 header = this.header;
16926 var cal_heads = function() {
16928 // fixme - handle this.
16930 for (var i =0; i < Date.dayNames.length; i++) {
16931 var d = Date.dayNames[i];
16934 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16935 html : d.substring(0,3)
16939 ret[0].cls += ' fc-first';
16940 ret[6].cls += ' fc-last';
16943 var cal_cell = function(n) {
16946 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
16951 cls: 'fc-day-number',
16955 cls: 'fc-day-content',
16959 style: 'position: relative;' // height: 17px;
16971 var cal_rows = function() {
16974 for (var r = 0; r < 6; r++) {
16981 for (var i =0; i < Date.dayNames.length; i++) {
16982 var d = Date.dayNames[i];
16983 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
16986 row.cn[0].cls+=' fc-first';
16987 row.cn[0].cn[0].style = 'min-height:90px';
16988 row.cn[6].cls+=' fc-last';
16992 ret[0].cls += ' fc-first';
16993 ret[4].cls += ' fc-prev-last';
16994 ret[5].cls += ' fc-last';
17001 cls: 'fc-border-separate',
17002 style : 'width:100%',
17010 cls : 'fc-first fc-last',
17028 cls : 'fc-content',
17029 style : "position: relative;",
17032 cls : 'fc-view fc-view-month fc-grid',
17033 style : 'position: relative',
17034 unselectable : 'on',
17037 cls : 'fc-event-container',
17038 style : 'position:absolute;z-index:8;top:0;left:0;'
17056 initEvents : function()
17059 throw "can not find store for calendar";
17065 style: "text-align:center",
17069 style: "background-color:white;width:50%;margin:250 auto",
17073 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17084 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17086 var size = this.el.select('.fc-content', true).first().getSize();
17087 this.maskEl.setSize(size.width, size.height);
17088 this.maskEl.enableDisplayMode("block");
17089 if(!this.loadMask){
17090 this.maskEl.hide();
17093 this.store = Roo.factory(this.store, Roo.data);
17094 this.store.on('load', this.onLoad, this);
17095 this.store.on('beforeload', this.onBeforeLoad, this);
17099 this.cells = this.el.select('.fc-day',true);
17100 //Roo.log(this.cells);
17101 this.textNodes = this.el.query('.fc-day-number');
17102 this.cells.addClassOnOver('fc-state-hover');
17104 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17105 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17106 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17107 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17109 this.on('monthchange', this.onMonthChange, this);
17111 this.update(new Date().clearTime());
17114 resize : function() {
17115 var sz = this.el.getSize();
17117 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17118 this.el.select('.fc-day-content div',true).setHeight(34);
17123 showPrevMonth : function(e){
17124 this.update(this.activeDate.add("mo", -1));
17126 showToday : function(e){
17127 this.update(new Date().clearTime());
17130 showNextMonth : function(e){
17131 this.update(this.activeDate.add("mo", 1));
17135 showPrevYear : function(){
17136 this.update(this.activeDate.add("y", -1));
17140 showNextYear : function(){
17141 this.update(this.activeDate.add("y", 1));
17146 update : function(date)
17148 var vd = this.activeDate;
17149 this.activeDate = date;
17150 // if(vd && this.el){
17151 // var t = date.getTime();
17152 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17153 // Roo.log('using add remove');
17155 // this.fireEvent('monthchange', this, date);
17157 // this.cells.removeClass("fc-state-highlight");
17158 // this.cells.each(function(c){
17159 // if(c.dateValue == t){
17160 // c.addClass("fc-state-highlight");
17161 // setTimeout(function(){
17162 // try{c.dom.firstChild.focus();}catch(e){}
17172 var days = date.getDaysInMonth();
17174 var firstOfMonth = date.getFirstDateOfMonth();
17175 var startingPos = firstOfMonth.getDay()-this.startDay;
17177 if(startingPos < this.startDay){
17181 var pm = date.add(Date.MONTH, -1);
17182 var prevStart = pm.getDaysInMonth()-startingPos;
17184 this.cells = this.el.select('.fc-day',true);
17185 this.textNodes = this.el.query('.fc-day-number');
17186 this.cells.addClassOnOver('fc-state-hover');
17188 var cells = this.cells.elements;
17189 var textEls = this.textNodes;
17191 Roo.each(cells, function(cell){
17192 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17195 days += startingPos;
17197 // convert everything to numbers so it's fast
17198 var day = 86400000;
17199 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17202 //Roo.log(prevStart);
17204 var today = new Date().clearTime().getTime();
17205 var sel = date.clearTime().getTime();
17206 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17207 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17208 var ddMatch = this.disabledDatesRE;
17209 var ddText = this.disabledDatesText;
17210 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17211 var ddaysText = this.disabledDaysText;
17212 var format = this.format;
17214 var setCellClass = function(cal, cell){
17218 //Roo.log('set Cell Class');
17220 var t = d.getTime();
17224 cell.dateValue = t;
17226 cell.className += " fc-today";
17227 cell.className += " fc-state-highlight";
17228 cell.title = cal.todayText;
17231 // disable highlight in other month..
17232 //cell.className += " fc-state-highlight";
17237 cell.className = " fc-state-disabled";
17238 cell.title = cal.minText;
17242 cell.className = " fc-state-disabled";
17243 cell.title = cal.maxText;
17247 if(ddays.indexOf(d.getDay()) != -1){
17248 cell.title = ddaysText;
17249 cell.className = " fc-state-disabled";
17252 if(ddMatch && format){
17253 var fvalue = d.dateFormat(format);
17254 if(ddMatch.test(fvalue)){
17255 cell.title = ddText.replace("%0", fvalue);
17256 cell.className = " fc-state-disabled";
17260 if (!cell.initialClassName) {
17261 cell.initialClassName = cell.dom.className;
17264 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17269 for(; i < startingPos; i++) {
17270 textEls[i].innerHTML = (++prevStart);
17271 d.setDate(d.getDate()+1);
17273 cells[i].className = "fc-past fc-other-month";
17274 setCellClass(this, cells[i]);
17279 for(; i < days; i++){
17280 intDay = i - startingPos + 1;
17281 textEls[i].innerHTML = (intDay);
17282 d.setDate(d.getDate()+1);
17284 cells[i].className = ''; // "x-date-active";
17285 setCellClass(this, cells[i]);
17289 for(; i < 42; i++) {
17290 textEls[i].innerHTML = (++extraDays);
17291 d.setDate(d.getDate()+1);
17293 cells[i].className = "fc-future fc-other-month";
17294 setCellClass(this, cells[i]);
17297 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17299 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17301 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17302 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17304 if(totalRows != 6){
17305 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17306 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17309 this.fireEvent('monthchange', this, date);
17313 if(!this.internalRender){
17314 var main = this.el.dom.firstChild;
17315 var w = main.offsetWidth;
17316 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17317 Roo.fly(main).setWidth(w);
17318 this.internalRender = true;
17319 // opera does not respect the auto grow header center column
17320 // then, after it gets a width opera refuses to recalculate
17321 // without a second pass
17322 if(Roo.isOpera && !this.secondPass){
17323 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17324 this.secondPass = true;
17325 this.update.defer(10, this, [date]);
17332 findCell : function(dt) {
17333 dt = dt.clearTime().getTime();
17335 this.cells.each(function(c){
17336 //Roo.log("check " +c.dateValue + '?=' + dt);
17337 if(c.dateValue == dt){
17347 findCells : function(ev) {
17348 var s = ev.start.clone().clearTime().getTime();
17350 var e= ev.end.clone().clearTime().getTime();
17353 this.cells.each(function(c){
17354 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17356 if(c.dateValue > e){
17359 if(c.dateValue < s){
17368 // findBestRow: function(cells)
17372 // for (var i =0 ; i < cells.length;i++) {
17373 // ret = Math.max(cells[i].rows || 0,ret);
17380 addItem : function(ev)
17382 // look for vertical location slot in
17383 var cells = this.findCells(ev);
17385 // ev.row = this.findBestRow(cells);
17387 // work out the location.
17391 for(var i =0; i < cells.length; i++) {
17393 cells[i].row = cells[0].row;
17396 cells[i].row = cells[i].row + 1;
17406 if (crow.start.getY() == cells[i].getY()) {
17408 crow.end = cells[i];
17425 cells[0].events.push(ev);
17427 this.calevents.push(ev);
17430 clearEvents: function() {
17432 if(!this.calevents){
17436 Roo.each(this.cells.elements, function(c){
17442 Roo.each(this.calevents, function(e) {
17443 Roo.each(e.els, function(el) {
17444 el.un('mouseenter' ,this.onEventEnter, this);
17445 el.un('mouseleave' ,this.onEventLeave, this);
17450 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17456 renderEvents: function()
17460 this.cells.each(function(c) {
17469 if(c.row != c.events.length){
17470 r = 4 - (4 - (c.row - c.events.length));
17473 c.events = ev.slice(0, r);
17474 c.more = ev.slice(r);
17476 if(c.more.length && c.more.length == 1){
17477 c.events.push(c.more.pop());
17480 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17484 this.cells.each(function(c) {
17486 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17489 for (var e = 0; e < c.events.length; e++){
17490 var ev = c.events[e];
17491 var rows = ev.rows;
17493 for(var i = 0; i < rows.length; i++) {
17495 // how many rows should it span..
17498 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17499 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17501 unselectable : "on",
17504 cls: 'fc-event-inner',
17508 // cls: 'fc-event-time',
17509 // html : cells.length > 1 ? '' : ev.time
17513 cls: 'fc-event-title',
17514 html : String.format('{0}', ev.title)
17521 cls: 'ui-resizable-handle ui-resizable-e',
17522 html : '  '
17529 cfg.cls += ' fc-event-start';
17531 if ((i+1) == rows.length) {
17532 cfg.cls += ' fc-event-end';
17535 var ctr = _this.el.select('.fc-event-container',true).first();
17536 var cg = ctr.createChild(cfg);
17538 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17539 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17541 var r = (c.more.length) ? 1 : 0;
17542 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17543 cg.setWidth(ebox.right - sbox.x -2);
17545 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17546 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17547 cg.on('click', _this.onEventClick, _this, ev);
17558 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17559 style : 'position: absolute',
17560 unselectable : "on",
17563 cls: 'fc-event-inner',
17567 cls: 'fc-event-title',
17575 cls: 'ui-resizable-handle ui-resizable-e',
17576 html : '  '
17582 var ctr = _this.el.select('.fc-event-container',true).first();
17583 var cg = ctr.createChild(cfg);
17585 var sbox = c.select('.fc-day-content',true).first().getBox();
17586 var ebox = c.select('.fc-day-content',true).first().getBox();
17588 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17589 cg.setWidth(ebox.right - sbox.x -2);
17591 cg.on('click', _this.onMoreEventClick, _this, c.more);
17601 onEventEnter: function (e, el,event,d) {
17602 this.fireEvent('evententer', this, el, event);
17605 onEventLeave: function (e, el,event,d) {
17606 this.fireEvent('eventleave', this, el, event);
17609 onEventClick: function (e, el,event,d) {
17610 this.fireEvent('eventclick', this, el, event);
17613 onMonthChange: function () {
17617 onMoreEventClick: function(e, el, more)
17621 this.calpopover.placement = 'right';
17622 this.calpopover.setTitle('More');
17624 this.calpopover.setContent('');
17626 var ctr = this.calpopover.el.select('.popover-content', true).first();
17628 Roo.each(more, function(m){
17630 cls : 'fc-event-hori fc-event-draggable',
17633 var cg = ctr.createChild(cfg);
17635 cg.on('click', _this.onEventClick, _this, m);
17638 this.calpopover.show(el);
17643 onLoad: function ()
17645 this.calevents = [];
17648 if(this.store.getCount() > 0){
17649 this.store.data.each(function(d){
17652 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17653 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17654 time : d.data.start_time,
17655 title : d.data.title,
17656 description : d.data.description,
17657 venue : d.data.venue
17662 this.renderEvents();
17664 if(this.calevents.length && this.loadMask){
17665 this.maskEl.hide();
17669 onBeforeLoad: function()
17671 this.clearEvents();
17673 this.maskEl.show();
17687 * @class Roo.bootstrap.Popover
17688 * @extends Roo.bootstrap.Component
17689 * Bootstrap Popover class
17690 * @cfg {String} html contents of the popover (or false to use children..)
17691 * @cfg {String} title of popover (or false to hide)
17692 * @cfg {String} placement how it is placed
17693 * @cfg {String} trigger click || hover (or false to trigger manually)
17694 * @cfg {String} over what (parent or false to trigger manually.)
17695 * @cfg {Number} delay - delay before showing
17698 * Create a new Popover
17699 * @param {Object} config The config object
17702 Roo.bootstrap.Popover = function(config){
17703 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17709 * After the popover show
17711 * @param {Roo.bootstrap.Popover} this
17716 * After the popover hide
17718 * @param {Roo.bootstrap.Popover} this
17724 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17726 title: 'Fill in a title',
17729 placement : 'right',
17730 trigger : 'hover', // hover
17736 can_build_overlaid : false,
17738 getChildContainer : function()
17740 return this.el.select('.popover-content',true).first();
17743 getAutoCreate : function(){
17746 cls : 'popover roo-dynamic',
17747 style: 'display:block',
17753 cls : 'popover-inner',
17757 cls: 'popover-title popover-header',
17761 cls : 'popover-content popover-body',
17772 setTitle: function(str)
17775 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17777 setContent: function(str)
17780 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17782 // as it get's added to the bottom of the page.
17783 onRender : function(ct, position)
17785 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17787 var cfg = Roo.apply({}, this.getAutoCreate());
17791 cfg.cls += ' ' + this.cls;
17794 cfg.style = this.style;
17796 //Roo.log("adding to ");
17797 this.el = Roo.get(document.body).createChild(cfg, position);
17798 // Roo.log(this.el);
17803 initEvents : function()
17805 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17806 this.el.enableDisplayMode('block');
17808 if (this.over === false) {
17811 if (this.triggers === false) {
17814 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17815 var triggers = this.trigger ? this.trigger.split(' ') : [];
17816 Roo.each(triggers, function(trigger) {
17818 if (trigger == 'click') {
17819 on_el.on('click', this.toggle, this);
17820 } else if (trigger != 'manual') {
17821 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17822 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17824 on_el.on(eventIn ,this.enter, this);
17825 on_el.on(eventOut, this.leave, this);
17836 toggle : function () {
17837 this.hoverState == 'in' ? this.leave() : this.enter();
17840 enter : function () {
17842 clearTimeout(this.timeout);
17844 this.hoverState = 'in';
17846 if (!this.delay || !this.delay.show) {
17851 this.timeout = setTimeout(function () {
17852 if (_t.hoverState == 'in') {
17855 }, this.delay.show)
17858 leave : function() {
17859 clearTimeout(this.timeout);
17861 this.hoverState = 'out';
17863 if (!this.delay || !this.delay.hide) {
17868 this.timeout = setTimeout(function () {
17869 if (_t.hoverState == 'out') {
17872 }, this.delay.hide)
17875 show : function (on_el)
17878 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17882 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17883 if (this.html !== false) {
17884 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17886 this.el.removeClass([
17887 'fade','top','bottom', 'left', 'right','in',
17888 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17890 if (!this.title.length) {
17891 this.el.select('.popover-title',true).hide();
17894 var placement = typeof this.placement == 'function' ?
17895 this.placement.call(this, this.el, on_el) :
17898 var autoToken = /\s?auto?\s?/i;
17899 var autoPlace = autoToken.test(placement);
17901 placement = placement.replace(autoToken, '') || 'top';
17905 //this.el.setXY([0,0]);
17907 this.el.dom.style.display='block';
17908 this.el.addClass(placement);
17910 //this.el.appendTo(on_el);
17912 var p = this.getPosition();
17913 var box = this.el.getBox();
17918 var align = Roo.bootstrap.Popover.alignment[placement];
17921 this.el.alignTo(on_el, align[0],align[1]);
17922 //var arrow = this.el.select('.arrow',true).first();
17923 //arrow.set(align[2],
17925 this.el.addClass('in');
17928 if (this.el.hasClass('fade')) {
17932 this.hoverState = 'in';
17934 this.fireEvent('show', this);
17939 this.el.setXY([0,0]);
17940 this.el.removeClass('in');
17942 this.hoverState = null;
17944 this.fireEvent('hide', this);
17949 Roo.bootstrap.Popover.alignment = {
17950 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
17951 'right' : ['l-r', [10,0], 'left bs-popover-left'],
17952 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
17953 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
17964 * @class Roo.bootstrap.Progress
17965 * @extends Roo.bootstrap.Component
17966 * Bootstrap Progress class
17967 * @cfg {Boolean} striped striped of the progress bar
17968 * @cfg {Boolean} active animated of the progress bar
17972 * Create a new Progress
17973 * @param {Object} config The config object
17976 Roo.bootstrap.Progress = function(config){
17977 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
17980 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
17985 getAutoCreate : function(){
17993 cfg.cls += ' progress-striped';
17997 cfg.cls += ' active';
18016 * @class Roo.bootstrap.ProgressBar
18017 * @extends Roo.bootstrap.Component
18018 * Bootstrap ProgressBar class
18019 * @cfg {Number} aria_valuenow aria-value now
18020 * @cfg {Number} aria_valuemin aria-value min
18021 * @cfg {Number} aria_valuemax aria-value max
18022 * @cfg {String} label label for the progress bar
18023 * @cfg {String} panel (success | info | warning | danger )
18024 * @cfg {String} role role of the progress bar
18025 * @cfg {String} sr_only text
18029 * Create a new ProgressBar
18030 * @param {Object} config The config object
18033 Roo.bootstrap.ProgressBar = function(config){
18034 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18037 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18041 aria_valuemax : 100,
18047 getAutoCreate : function()
18052 cls: 'progress-bar',
18053 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18065 cfg.role = this.role;
18068 if(this.aria_valuenow){
18069 cfg['aria-valuenow'] = this.aria_valuenow;
18072 if(this.aria_valuemin){
18073 cfg['aria-valuemin'] = this.aria_valuemin;
18076 if(this.aria_valuemax){
18077 cfg['aria-valuemax'] = this.aria_valuemax;
18080 if(this.label && !this.sr_only){
18081 cfg.html = this.label;
18085 cfg.cls += ' progress-bar-' + this.panel;
18091 update : function(aria_valuenow)
18093 this.aria_valuenow = aria_valuenow;
18095 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18110 * @class Roo.bootstrap.TabGroup
18111 * @extends Roo.bootstrap.Column
18112 * Bootstrap Column class
18113 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18114 * @cfg {Boolean} carousel true to make the group behave like a carousel
18115 * @cfg {Boolean} bullets show bullets for the panels
18116 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18117 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18118 * @cfg {Boolean} showarrow (true|false) show arrow default true
18121 * Create a new TabGroup
18122 * @param {Object} config The config object
18125 Roo.bootstrap.TabGroup = function(config){
18126 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18128 this.navId = Roo.id();
18131 Roo.bootstrap.TabGroup.register(this);
18135 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18138 transition : false,
18143 slideOnTouch : false,
18146 getAutoCreate : function()
18148 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18150 cfg.cls += ' tab-content';
18152 if (this.carousel) {
18153 cfg.cls += ' carousel slide';
18156 cls : 'carousel-inner',
18160 if(this.bullets && !Roo.isTouch){
18163 cls : 'carousel-bullets',
18167 if(this.bullets_cls){
18168 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18175 cfg.cn[0].cn.push(bullets);
18178 if(this.showarrow){
18179 cfg.cn[0].cn.push({
18181 class : 'carousel-arrow',
18185 class : 'carousel-prev',
18189 class : 'fa fa-chevron-left'
18195 class : 'carousel-next',
18199 class : 'fa fa-chevron-right'
18212 initEvents: function()
18214 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18215 // this.el.on("touchstart", this.onTouchStart, this);
18218 if(this.autoslide){
18221 this.slideFn = window.setInterval(function() {
18222 _this.showPanelNext();
18226 if(this.showarrow){
18227 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18228 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18234 // onTouchStart : function(e, el, o)
18236 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18240 // this.showPanelNext();
18244 getChildContainer : function()
18246 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18250 * register a Navigation item
18251 * @param {Roo.bootstrap.NavItem} the navitem to add
18253 register : function(item)
18255 this.tabs.push( item);
18256 item.navId = this.navId; // not really needed..
18261 getActivePanel : function()
18264 Roo.each(this.tabs, function(t) {
18274 getPanelByName : function(n)
18277 Roo.each(this.tabs, function(t) {
18278 if (t.tabId == n) {
18286 indexOfPanel : function(p)
18289 Roo.each(this.tabs, function(t,i) {
18290 if (t.tabId == p.tabId) {
18299 * show a specific panel
18300 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18301 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18303 showPanel : function (pan)
18305 if(this.transition || typeof(pan) == 'undefined'){
18306 Roo.log("waiting for the transitionend");
18310 if (typeof(pan) == 'number') {
18311 pan = this.tabs[pan];
18314 if (typeof(pan) == 'string') {
18315 pan = this.getPanelByName(pan);
18318 var cur = this.getActivePanel();
18321 Roo.log('pan or acitve pan is undefined');
18325 if (pan.tabId == this.getActivePanel().tabId) {
18329 if (false === cur.fireEvent('beforedeactivate')) {
18333 if(this.bullets > 0 && !Roo.isTouch){
18334 this.setActiveBullet(this.indexOfPanel(pan));
18337 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18339 this.transition = true;
18340 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18341 var lr = dir == 'next' ? 'left' : 'right';
18342 pan.el.addClass(dir); // or prev
18343 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18344 cur.el.addClass(lr); // or right
18345 pan.el.addClass(lr);
18348 cur.el.on('transitionend', function() {
18349 Roo.log("trans end?");
18351 pan.el.removeClass([lr,dir]);
18352 pan.setActive(true);
18354 cur.el.removeClass([lr]);
18355 cur.setActive(false);
18357 _this.transition = false;
18359 }, this, { single: true } );
18364 cur.setActive(false);
18365 pan.setActive(true);
18370 showPanelNext : function()
18372 var i = this.indexOfPanel(this.getActivePanel());
18374 if (i >= this.tabs.length - 1 && !this.autoslide) {
18378 if (i >= this.tabs.length - 1 && this.autoslide) {
18382 this.showPanel(this.tabs[i+1]);
18385 showPanelPrev : function()
18387 var i = this.indexOfPanel(this.getActivePanel());
18389 if (i < 1 && !this.autoslide) {
18393 if (i < 1 && this.autoslide) {
18394 i = this.tabs.length;
18397 this.showPanel(this.tabs[i-1]);
18401 addBullet: function()
18403 if(!this.bullets || Roo.isTouch){
18406 var ctr = this.el.select('.carousel-bullets',true).first();
18407 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18408 var bullet = ctr.createChild({
18409 cls : 'bullet bullet-' + i
18410 },ctr.dom.lastChild);
18415 bullet.on('click', (function(e, el, o, ii, t){
18417 e.preventDefault();
18419 this.showPanel(ii);
18421 if(this.autoslide && this.slideFn){
18422 clearInterval(this.slideFn);
18423 this.slideFn = window.setInterval(function() {
18424 _this.showPanelNext();
18428 }).createDelegate(this, [i, bullet], true));
18433 setActiveBullet : function(i)
18439 Roo.each(this.el.select('.bullet', true).elements, function(el){
18440 el.removeClass('selected');
18443 var bullet = this.el.select('.bullet-' + i, true).first();
18449 bullet.addClass('selected');
18460 Roo.apply(Roo.bootstrap.TabGroup, {
18464 * register a Navigation Group
18465 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18467 register : function(navgrp)
18469 this.groups[navgrp.navId] = navgrp;
18473 * fetch a Navigation Group based on the navigation ID
18474 * if one does not exist , it will get created.
18475 * @param {string} the navgroup to add
18476 * @returns {Roo.bootstrap.NavGroup} the navgroup
18478 get: function(navId) {
18479 if (typeof(this.groups[navId]) == 'undefined') {
18480 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18482 return this.groups[navId] ;
18497 * @class Roo.bootstrap.TabPanel
18498 * @extends Roo.bootstrap.Component
18499 * Bootstrap TabPanel class
18500 * @cfg {Boolean} active panel active
18501 * @cfg {String} html panel content
18502 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18503 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18504 * @cfg {String} href click to link..
18508 * Create a new TabPanel
18509 * @param {Object} config The config object
18512 Roo.bootstrap.TabPanel = function(config){
18513 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18517 * Fires when the active status changes
18518 * @param {Roo.bootstrap.TabPanel} this
18519 * @param {Boolean} state the new state
18524 * @event beforedeactivate
18525 * Fires before a tab is de-activated - can be used to do validation on a form.
18526 * @param {Roo.bootstrap.TabPanel} this
18527 * @return {Boolean} false if there is an error
18530 'beforedeactivate': true
18533 this.tabId = this.tabId || Roo.id();
18537 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18545 getAutoCreate : function(){
18548 // item is needed for carousel - not sure if it has any effect otherwise
18549 cls: 'tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18550 html: this.html || ''
18554 cfg.cls += ' active';
18558 cfg.tabId = this.tabId;
18565 initEvents: function()
18567 var p = this.parent();
18569 this.navId = this.navId || p.navId;
18571 if (typeof(this.navId) != 'undefined') {
18572 // not really needed.. but just in case.. parent should be a NavGroup.
18573 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18577 var i = tg.tabs.length - 1;
18579 if(this.active && tg.bullets > 0 && i < tg.bullets){
18580 tg.setActiveBullet(i);
18584 this.el.on('click', this.onClick, this);
18587 this.el.on("touchstart", this.onTouchStart, this);
18588 this.el.on("touchmove", this.onTouchMove, this);
18589 this.el.on("touchend", this.onTouchEnd, this);
18594 onRender : function(ct, position)
18596 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18599 setActive : function(state)
18601 Roo.log("panel - set active " + this.tabId + "=" + state);
18603 this.active = state;
18605 this.el.removeClass('active');
18607 } else if (!this.el.hasClass('active')) {
18608 this.el.addClass('active');
18611 this.fireEvent('changed', this, state);
18614 onClick : function(e)
18616 e.preventDefault();
18618 if(!this.href.length){
18622 window.location.href = this.href;
18631 onTouchStart : function(e)
18633 this.swiping = false;
18635 this.startX = e.browserEvent.touches[0].clientX;
18636 this.startY = e.browserEvent.touches[0].clientY;
18639 onTouchMove : function(e)
18641 this.swiping = true;
18643 this.endX = e.browserEvent.touches[0].clientX;
18644 this.endY = e.browserEvent.touches[0].clientY;
18647 onTouchEnd : function(e)
18654 var tabGroup = this.parent();
18656 if(this.endX > this.startX){ // swiping right
18657 tabGroup.showPanelPrev();
18661 if(this.startX > this.endX){ // swiping left
18662 tabGroup.showPanelNext();
18681 * @class Roo.bootstrap.DateField
18682 * @extends Roo.bootstrap.Input
18683 * Bootstrap DateField class
18684 * @cfg {Number} weekStart default 0
18685 * @cfg {String} viewMode default empty, (months|years)
18686 * @cfg {String} minViewMode default empty, (months|years)
18687 * @cfg {Number} startDate default -Infinity
18688 * @cfg {Number} endDate default Infinity
18689 * @cfg {Boolean} todayHighlight default false
18690 * @cfg {Boolean} todayBtn default false
18691 * @cfg {Boolean} calendarWeeks default false
18692 * @cfg {Object} daysOfWeekDisabled default empty
18693 * @cfg {Boolean} singleMode default false (true | false)
18695 * @cfg {Boolean} keyboardNavigation default true
18696 * @cfg {String} language default en
18699 * Create a new DateField
18700 * @param {Object} config The config object
18703 Roo.bootstrap.DateField = function(config){
18704 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18708 * Fires when this field show.
18709 * @param {Roo.bootstrap.DateField} this
18710 * @param {Mixed} date The date value
18715 * Fires when this field hide.
18716 * @param {Roo.bootstrap.DateField} this
18717 * @param {Mixed} date The date value
18722 * Fires when select a date.
18723 * @param {Roo.bootstrap.DateField} this
18724 * @param {Mixed} date The date value
18728 * @event beforeselect
18729 * Fires when before select a date.
18730 * @param {Roo.bootstrap.DateField} this
18731 * @param {Mixed} date The date value
18733 beforeselect : true
18737 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18740 * @cfg {String} format
18741 * The default date format string which can be overriden for localization support. The format must be
18742 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18746 * @cfg {String} altFormats
18747 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18748 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18750 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18758 todayHighlight : false,
18764 keyboardNavigation: true,
18766 calendarWeeks: false,
18768 startDate: -Infinity,
18772 daysOfWeekDisabled: [],
18776 singleMode : false,
18778 UTCDate: function()
18780 return new Date(Date.UTC.apply(Date, arguments));
18783 UTCToday: function()
18785 var today = new Date();
18786 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18789 getDate: function() {
18790 var d = this.getUTCDate();
18791 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18794 getUTCDate: function() {
18798 setDate: function(d) {
18799 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18802 setUTCDate: function(d) {
18804 this.setValue(this.formatDate(this.date));
18807 onRender: function(ct, position)
18810 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18812 this.language = this.language || 'en';
18813 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18814 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18816 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18817 this.format = this.format || 'm/d/y';
18818 this.isInline = false;
18819 this.isInput = true;
18820 this.component = this.el.select('.add-on', true).first() || false;
18821 this.component = (this.component && this.component.length === 0) ? false : this.component;
18822 this.hasInput = this.component && this.inputEl().length;
18824 if (typeof(this.minViewMode === 'string')) {
18825 switch (this.minViewMode) {
18827 this.minViewMode = 1;
18830 this.minViewMode = 2;
18833 this.minViewMode = 0;
18838 if (typeof(this.viewMode === 'string')) {
18839 switch (this.viewMode) {
18852 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18854 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18856 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18858 this.picker().on('mousedown', this.onMousedown, this);
18859 this.picker().on('click', this.onClick, this);
18861 this.picker().addClass('datepicker-dropdown');
18863 this.startViewMode = this.viewMode;
18865 if(this.singleMode){
18866 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18867 v.setVisibilityMode(Roo.Element.DISPLAY);
18871 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18872 v.setStyle('width', '189px');
18876 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18877 if(!this.calendarWeeks){
18882 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18883 v.attr('colspan', function(i, val){
18884 return parseInt(val) + 1;
18889 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18891 this.setStartDate(this.startDate);
18892 this.setEndDate(this.endDate);
18894 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18901 if(this.isInline) {
18906 picker : function()
18908 return this.pickerEl;
18909 // return this.el.select('.datepicker', true).first();
18912 fillDow: function()
18914 var dowCnt = this.weekStart;
18923 if(this.calendarWeeks){
18931 while (dowCnt < this.weekStart + 7) {
18935 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
18939 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
18942 fillMonths: function()
18945 var months = this.picker().select('>.datepicker-months td', true).first();
18947 months.dom.innerHTML = '';
18953 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
18956 months.createChild(month);
18963 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;
18965 if (this.date < this.startDate) {
18966 this.viewDate = new Date(this.startDate);
18967 } else if (this.date > this.endDate) {
18968 this.viewDate = new Date(this.endDate);
18970 this.viewDate = new Date(this.date);
18978 var d = new Date(this.viewDate),
18979 year = d.getUTCFullYear(),
18980 month = d.getUTCMonth(),
18981 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
18982 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
18983 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
18984 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
18985 currentDate = this.date && this.date.valueOf(),
18986 today = this.UTCToday();
18988 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
18990 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18992 // this.picker.select('>tfoot th.today').
18993 // .text(dates[this.language].today)
18994 // .toggle(this.todayBtn !== false);
18996 this.updateNavArrows();
18999 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19001 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19003 prevMonth.setUTCDate(day);
19005 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19007 var nextMonth = new Date(prevMonth);
19009 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19011 nextMonth = nextMonth.valueOf();
19013 var fillMonths = false;
19015 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19017 while(prevMonth.valueOf() <= nextMonth) {
19020 if (prevMonth.getUTCDay() === this.weekStart) {
19022 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19030 if(this.calendarWeeks){
19031 // ISO 8601: First week contains first thursday.
19032 // ISO also states week starts on Monday, but we can be more abstract here.
19034 // Start of current week: based on weekstart/current date
19035 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19036 // Thursday of this week
19037 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19038 // First Thursday of year, year from thursday
19039 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19040 // Calendar week: ms between thursdays, div ms per day, div 7 days
19041 calWeek = (th - yth) / 864e5 / 7 + 1;
19043 fillMonths.cn.push({
19051 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19053 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19056 if (this.todayHighlight &&
19057 prevMonth.getUTCFullYear() == today.getFullYear() &&
19058 prevMonth.getUTCMonth() == today.getMonth() &&
19059 prevMonth.getUTCDate() == today.getDate()) {
19060 clsName += ' today';
19063 if (currentDate && prevMonth.valueOf() === currentDate) {
19064 clsName += ' active';
19067 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19068 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19069 clsName += ' disabled';
19072 fillMonths.cn.push({
19074 cls: 'day ' + clsName,
19075 html: prevMonth.getDate()
19078 prevMonth.setDate(prevMonth.getDate()+1);
19081 var currentYear = this.date && this.date.getUTCFullYear();
19082 var currentMonth = this.date && this.date.getUTCMonth();
19084 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19086 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19087 v.removeClass('active');
19089 if(currentYear === year && k === currentMonth){
19090 v.addClass('active');
19093 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19094 v.addClass('disabled');
19100 year = parseInt(year/10, 10) * 10;
19102 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19104 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19107 for (var i = -1; i < 11; i++) {
19108 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19110 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19118 showMode: function(dir)
19121 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19124 Roo.each(this.picker().select('>div',true).elements, function(v){
19125 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19128 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19133 if(this.isInline) {
19137 this.picker().removeClass(['bottom', 'top']);
19139 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19141 * place to the top of element!
19145 this.picker().addClass('top');
19146 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19151 this.picker().addClass('bottom');
19153 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19156 parseDate : function(value)
19158 if(!value || value instanceof Date){
19161 var v = Date.parseDate(value, this.format);
19162 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19163 v = Date.parseDate(value, 'Y-m-d');
19165 if(!v && this.altFormats){
19166 if(!this.altFormatsArray){
19167 this.altFormatsArray = this.altFormats.split("|");
19169 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19170 v = Date.parseDate(value, this.altFormatsArray[i]);
19176 formatDate : function(date, fmt)
19178 return (!date || !(date instanceof Date)) ?
19179 date : date.dateFormat(fmt || this.format);
19182 onFocus : function()
19184 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19188 onBlur : function()
19190 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19192 var d = this.inputEl().getValue();
19199 showPopup : function()
19201 this.picker().show();
19205 this.fireEvent('showpopup', this, this.date);
19208 hidePopup : function()
19210 if(this.isInline) {
19213 this.picker().hide();
19214 this.viewMode = this.startViewMode;
19217 this.fireEvent('hidepopup', this, this.date);
19221 onMousedown: function(e)
19223 e.stopPropagation();
19224 e.preventDefault();
19229 Roo.bootstrap.DateField.superclass.keyup.call(this);
19233 setValue: function(v)
19235 if(this.fireEvent('beforeselect', this, v) !== false){
19236 var d = new Date(this.parseDate(v) ).clearTime();
19238 if(isNaN(d.getTime())){
19239 this.date = this.viewDate = '';
19240 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19244 v = this.formatDate(d);
19246 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19248 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19252 this.fireEvent('select', this, this.date);
19256 getValue: function()
19258 return this.formatDate(this.date);
19261 fireKey: function(e)
19263 if (!this.picker().isVisible()){
19264 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19270 var dateChanged = false,
19272 newDate, newViewDate;
19277 e.preventDefault();
19281 if (!this.keyboardNavigation) {
19284 dir = e.keyCode == 37 ? -1 : 1;
19287 newDate = this.moveYear(this.date, dir);
19288 newViewDate = this.moveYear(this.viewDate, dir);
19289 } else if (e.shiftKey){
19290 newDate = this.moveMonth(this.date, dir);
19291 newViewDate = this.moveMonth(this.viewDate, dir);
19293 newDate = new Date(this.date);
19294 newDate.setUTCDate(this.date.getUTCDate() + dir);
19295 newViewDate = new Date(this.viewDate);
19296 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19298 if (this.dateWithinRange(newDate)){
19299 this.date = newDate;
19300 this.viewDate = newViewDate;
19301 this.setValue(this.formatDate(this.date));
19303 e.preventDefault();
19304 dateChanged = true;
19309 if (!this.keyboardNavigation) {
19312 dir = e.keyCode == 38 ? -1 : 1;
19314 newDate = this.moveYear(this.date, dir);
19315 newViewDate = this.moveYear(this.viewDate, dir);
19316 } else if (e.shiftKey){
19317 newDate = this.moveMonth(this.date, dir);
19318 newViewDate = this.moveMonth(this.viewDate, dir);
19320 newDate = new Date(this.date);
19321 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19322 newViewDate = new Date(this.viewDate);
19323 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19325 if (this.dateWithinRange(newDate)){
19326 this.date = newDate;
19327 this.viewDate = newViewDate;
19328 this.setValue(this.formatDate(this.date));
19330 e.preventDefault();
19331 dateChanged = true;
19335 this.setValue(this.formatDate(this.date));
19337 e.preventDefault();
19340 this.setValue(this.formatDate(this.date));
19354 onClick: function(e)
19356 e.stopPropagation();
19357 e.preventDefault();
19359 var target = e.getTarget();
19361 if(target.nodeName.toLowerCase() === 'i'){
19362 target = Roo.get(target).dom.parentNode;
19365 var nodeName = target.nodeName;
19366 var className = target.className;
19367 var html = target.innerHTML;
19368 //Roo.log(nodeName);
19370 switch(nodeName.toLowerCase()) {
19372 switch(className) {
19378 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19379 switch(this.viewMode){
19381 this.viewDate = this.moveMonth(this.viewDate, dir);
19385 this.viewDate = this.moveYear(this.viewDate, dir);
19391 var date = new Date();
19392 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19394 this.setValue(this.formatDate(this.date));
19401 if (className.indexOf('disabled') < 0) {
19402 this.viewDate.setUTCDate(1);
19403 if (className.indexOf('month') > -1) {
19404 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19406 var year = parseInt(html, 10) || 0;
19407 this.viewDate.setUTCFullYear(year);
19411 if(this.singleMode){
19412 this.setValue(this.formatDate(this.viewDate));
19423 //Roo.log(className);
19424 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19425 var day = parseInt(html, 10) || 1;
19426 var year = this.viewDate.getUTCFullYear(),
19427 month = this.viewDate.getUTCMonth();
19429 if (className.indexOf('old') > -1) {
19436 } else if (className.indexOf('new') > -1) {
19444 //Roo.log([year,month,day]);
19445 this.date = this.UTCDate(year, month, day,0,0,0,0);
19446 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19448 //Roo.log(this.formatDate(this.date));
19449 this.setValue(this.formatDate(this.date));
19456 setStartDate: function(startDate)
19458 this.startDate = startDate || -Infinity;
19459 if (this.startDate !== -Infinity) {
19460 this.startDate = this.parseDate(this.startDate);
19463 this.updateNavArrows();
19466 setEndDate: function(endDate)
19468 this.endDate = endDate || Infinity;
19469 if (this.endDate !== Infinity) {
19470 this.endDate = this.parseDate(this.endDate);
19473 this.updateNavArrows();
19476 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19478 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19479 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19480 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19482 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19483 return parseInt(d, 10);
19486 this.updateNavArrows();
19489 updateNavArrows: function()
19491 if(this.singleMode){
19495 var d = new Date(this.viewDate),
19496 year = d.getUTCFullYear(),
19497 month = d.getUTCMonth();
19499 Roo.each(this.picker().select('.prev', true).elements, function(v){
19501 switch (this.viewMode) {
19504 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19510 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19517 Roo.each(this.picker().select('.next', true).elements, function(v){
19519 switch (this.viewMode) {
19522 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19528 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19536 moveMonth: function(date, dir)
19541 var new_date = new Date(date.valueOf()),
19542 day = new_date.getUTCDate(),
19543 month = new_date.getUTCMonth(),
19544 mag = Math.abs(dir),
19546 dir = dir > 0 ? 1 : -1;
19549 // If going back one month, make sure month is not current month
19550 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19552 return new_date.getUTCMonth() == month;
19554 // If going forward one month, make sure month is as expected
19555 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19557 return new_date.getUTCMonth() != new_month;
19559 new_month = month + dir;
19560 new_date.setUTCMonth(new_month);
19561 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19562 if (new_month < 0 || new_month > 11) {
19563 new_month = (new_month + 12) % 12;
19566 // For magnitudes >1, move one month at a time...
19567 for (var i=0; i<mag; i++) {
19568 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19569 new_date = this.moveMonth(new_date, dir);
19571 // ...then reset the day, keeping it in the new month
19572 new_month = new_date.getUTCMonth();
19573 new_date.setUTCDate(day);
19575 return new_month != new_date.getUTCMonth();
19578 // Common date-resetting loop -- if date is beyond end of month, make it
19581 new_date.setUTCDate(--day);
19582 new_date.setUTCMonth(new_month);
19587 moveYear: function(date, dir)
19589 return this.moveMonth(date, dir*12);
19592 dateWithinRange: function(date)
19594 return date >= this.startDate && date <= this.endDate;
19600 this.picker().remove();
19603 validateValue : function(value)
19605 if(this.getVisibilityEl().hasClass('hidden')){
19609 if(value.length < 1) {
19610 if(this.allowBlank){
19616 if(value.length < this.minLength){
19619 if(value.length > this.maxLength){
19623 var vt = Roo.form.VTypes;
19624 if(!vt[this.vtype](value, this)){
19628 if(typeof this.validator == "function"){
19629 var msg = this.validator(value);
19635 if(this.regex && !this.regex.test(value)){
19639 if(typeof(this.parseDate(value)) == 'undefined'){
19643 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19647 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19657 this.date = this.viewDate = '';
19659 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19664 Roo.apply(Roo.bootstrap.DateField, {
19675 html: '<i class="fa fa-arrow-left"/>'
19685 html: '<i class="fa fa-arrow-right"/>'
19727 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19728 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19729 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19730 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19731 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19744 navFnc: 'FullYear',
19749 navFnc: 'FullYear',
19754 Roo.apply(Roo.bootstrap.DateField, {
19758 cls: 'datepicker dropdown-menu roo-dynamic',
19762 cls: 'datepicker-days',
19766 cls: 'table-condensed',
19768 Roo.bootstrap.DateField.head,
19772 Roo.bootstrap.DateField.footer
19779 cls: 'datepicker-months',
19783 cls: 'table-condensed',
19785 Roo.bootstrap.DateField.head,
19786 Roo.bootstrap.DateField.content,
19787 Roo.bootstrap.DateField.footer
19794 cls: 'datepicker-years',
19798 cls: 'table-condensed',
19800 Roo.bootstrap.DateField.head,
19801 Roo.bootstrap.DateField.content,
19802 Roo.bootstrap.DateField.footer
19821 * @class Roo.bootstrap.TimeField
19822 * @extends Roo.bootstrap.Input
19823 * Bootstrap DateField class
19827 * Create a new TimeField
19828 * @param {Object} config The config object
19831 Roo.bootstrap.TimeField = function(config){
19832 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19836 * Fires when this field show.
19837 * @param {Roo.bootstrap.DateField} thisthis
19838 * @param {Mixed} date The date value
19843 * Fires when this field hide.
19844 * @param {Roo.bootstrap.DateField} this
19845 * @param {Mixed} date The date value
19850 * Fires when select a date.
19851 * @param {Roo.bootstrap.DateField} this
19852 * @param {Mixed} date The date value
19858 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19861 * @cfg {String} format
19862 * The default time format string which can be overriden for localization support. The format must be
19863 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19867 onRender: function(ct, position)
19870 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19872 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19874 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19876 this.pop = this.picker().select('>.datepicker-time',true).first();
19877 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19879 this.picker().on('mousedown', this.onMousedown, this);
19880 this.picker().on('click', this.onClick, this);
19882 this.picker().addClass('datepicker-dropdown');
19887 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19888 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19889 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19890 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19891 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19892 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19896 fireKey: function(e){
19897 if (!this.picker().isVisible()){
19898 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19904 e.preventDefault();
19912 this.onTogglePeriod();
19915 this.onIncrementMinutes();
19918 this.onDecrementMinutes();
19927 onClick: function(e) {
19928 e.stopPropagation();
19929 e.preventDefault();
19932 picker : function()
19934 return this.el.select('.datepicker', true).first();
19937 fillTime: function()
19939 var time = this.pop.select('tbody', true).first();
19941 time.dom.innerHTML = '';
19956 cls: 'hours-up glyphicon glyphicon-chevron-up'
19976 cls: 'minutes-up glyphicon glyphicon-chevron-up'
19997 cls: 'timepicker-hour',
20012 cls: 'timepicker-minute',
20027 cls: 'btn btn-primary period',
20049 cls: 'hours-down glyphicon glyphicon-chevron-down'
20069 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20087 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20094 var hours = this.time.getHours();
20095 var minutes = this.time.getMinutes();
20108 hours = hours - 12;
20112 hours = '0' + hours;
20116 minutes = '0' + minutes;
20119 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20120 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20121 this.pop.select('button', true).first().dom.innerHTML = period;
20127 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20129 var cls = ['bottom'];
20131 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20138 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20143 this.picker().addClass(cls.join('-'));
20147 Roo.each(cls, function(c){
20149 _this.picker().setTop(_this.inputEl().getHeight());
20153 _this.picker().setTop(0 - _this.picker().getHeight());
20158 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20162 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20169 onFocus : function()
20171 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20175 onBlur : function()
20177 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20183 this.picker().show();
20188 this.fireEvent('show', this, this.date);
20193 this.picker().hide();
20196 this.fireEvent('hide', this, this.date);
20199 setTime : function()
20202 this.setValue(this.time.format(this.format));
20204 this.fireEvent('select', this, this.date);
20209 onMousedown: function(e){
20210 e.stopPropagation();
20211 e.preventDefault();
20214 onIncrementHours: function()
20216 Roo.log('onIncrementHours');
20217 this.time = this.time.add(Date.HOUR, 1);
20222 onDecrementHours: function()
20224 Roo.log('onDecrementHours');
20225 this.time = this.time.add(Date.HOUR, -1);
20229 onIncrementMinutes: function()
20231 Roo.log('onIncrementMinutes');
20232 this.time = this.time.add(Date.MINUTE, 1);
20236 onDecrementMinutes: function()
20238 Roo.log('onDecrementMinutes');
20239 this.time = this.time.add(Date.MINUTE, -1);
20243 onTogglePeriod: function()
20245 Roo.log('onTogglePeriod');
20246 this.time = this.time.add(Date.HOUR, 12);
20253 Roo.apply(Roo.bootstrap.TimeField, {
20283 cls: 'btn btn-info ok',
20295 Roo.apply(Roo.bootstrap.TimeField, {
20299 cls: 'datepicker dropdown-menu',
20303 cls: 'datepicker-time',
20307 cls: 'table-condensed',
20309 Roo.bootstrap.TimeField.content,
20310 Roo.bootstrap.TimeField.footer
20329 * @class Roo.bootstrap.MonthField
20330 * @extends Roo.bootstrap.Input
20331 * Bootstrap MonthField class
20333 * @cfg {String} language default en
20336 * Create a new MonthField
20337 * @param {Object} config The config object
20340 Roo.bootstrap.MonthField = function(config){
20341 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20346 * Fires when this field show.
20347 * @param {Roo.bootstrap.MonthField} this
20348 * @param {Mixed} date The date value
20353 * Fires when this field hide.
20354 * @param {Roo.bootstrap.MonthField} this
20355 * @param {Mixed} date The date value
20360 * Fires when select a date.
20361 * @param {Roo.bootstrap.MonthField} this
20362 * @param {String} oldvalue The old value
20363 * @param {String} newvalue The new value
20369 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20371 onRender: function(ct, position)
20374 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20376 this.language = this.language || 'en';
20377 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20378 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20380 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20381 this.isInline = false;
20382 this.isInput = true;
20383 this.component = this.el.select('.add-on', true).first() || false;
20384 this.component = (this.component && this.component.length === 0) ? false : this.component;
20385 this.hasInput = this.component && this.inputEL().length;
20387 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20389 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20391 this.picker().on('mousedown', this.onMousedown, this);
20392 this.picker().on('click', this.onClick, this);
20394 this.picker().addClass('datepicker-dropdown');
20396 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20397 v.setStyle('width', '189px');
20404 if(this.isInline) {
20410 setValue: function(v, suppressEvent)
20412 var o = this.getValue();
20414 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20418 if(suppressEvent !== true){
20419 this.fireEvent('select', this, o, v);
20424 getValue: function()
20429 onClick: function(e)
20431 e.stopPropagation();
20432 e.preventDefault();
20434 var target = e.getTarget();
20436 if(target.nodeName.toLowerCase() === 'i'){
20437 target = Roo.get(target).dom.parentNode;
20440 var nodeName = target.nodeName;
20441 var className = target.className;
20442 var html = target.innerHTML;
20444 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20448 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20450 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20456 picker : function()
20458 return this.pickerEl;
20461 fillMonths: function()
20464 var months = this.picker().select('>.datepicker-months td', true).first();
20466 months.dom.innerHTML = '';
20472 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20475 months.createChild(month);
20484 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20485 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20488 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20489 e.removeClass('active');
20491 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20492 e.addClass('active');
20499 if(this.isInline) {
20503 this.picker().removeClass(['bottom', 'top']);
20505 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20507 * place to the top of element!
20511 this.picker().addClass('top');
20512 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20517 this.picker().addClass('bottom');
20519 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20522 onFocus : function()
20524 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20528 onBlur : function()
20530 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20532 var d = this.inputEl().getValue();
20541 this.picker().show();
20542 this.picker().select('>.datepicker-months', true).first().show();
20546 this.fireEvent('show', this, this.date);
20551 if(this.isInline) {
20554 this.picker().hide();
20555 this.fireEvent('hide', this, this.date);
20559 onMousedown: function(e)
20561 e.stopPropagation();
20562 e.preventDefault();
20567 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20571 fireKey: function(e)
20573 if (!this.picker().isVisible()){
20574 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20585 e.preventDefault();
20589 dir = e.keyCode == 37 ? -1 : 1;
20591 this.vIndex = this.vIndex + dir;
20593 if(this.vIndex < 0){
20597 if(this.vIndex > 11){
20601 if(isNaN(this.vIndex)){
20605 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20611 dir = e.keyCode == 38 ? -1 : 1;
20613 this.vIndex = this.vIndex + dir * 4;
20615 if(this.vIndex < 0){
20619 if(this.vIndex > 11){
20623 if(isNaN(this.vIndex)){
20627 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20632 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20633 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20637 e.preventDefault();
20640 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20641 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20657 this.picker().remove();
20662 Roo.apply(Roo.bootstrap.MonthField, {
20681 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20682 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20687 Roo.apply(Roo.bootstrap.MonthField, {
20691 cls: 'datepicker dropdown-menu roo-dynamic',
20695 cls: 'datepicker-months',
20699 cls: 'table-condensed',
20701 Roo.bootstrap.DateField.content
20721 * @class Roo.bootstrap.CheckBox
20722 * @extends Roo.bootstrap.Input
20723 * Bootstrap CheckBox class
20725 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20726 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20727 * @cfg {String} boxLabel The text that appears beside the checkbox
20728 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20729 * @cfg {Boolean} checked initnal the element
20730 * @cfg {Boolean} inline inline the element (default false)
20731 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20732 * @cfg {String} tooltip label tooltip
20735 * Create a new CheckBox
20736 * @param {Object} config The config object
20739 Roo.bootstrap.CheckBox = function(config){
20740 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20745 * Fires when the element is checked or unchecked.
20746 * @param {Roo.bootstrap.CheckBox} this This input
20747 * @param {Boolean} checked The new checked value
20752 * Fires when the element is click.
20753 * @param {Roo.bootstrap.CheckBox} this This input
20760 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20762 inputType: 'checkbox',
20771 getAutoCreate : function()
20773 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20779 cfg.cls = 'form-group ' + this.inputType; //input-group
20782 cfg.cls += ' ' + this.inputType + '-inline';
20788 type : this.inputType,
20789 value : this.inputValue,
20790 cls : 'roo-' + this.inputType, //'form-box',
20791 placeholder : this.placeholder || ''
20795 if(this.inputType != 'radio'){
20799 cls : 'roo-hidden-value',
20800 value : this.checked ? this.inputValue : this.valueOff
20805 if (this.weight) { // Validity check?
20806 cfg.cls += " " + this.inputType + "-" + this.weight;
20809 if (this.disabled) {
20810 input.disabled=true;
20814 input.checked = this.checked;
20819 input.name = this.name;
20821 if(this.inputType != 'radio'){
20822 hidden.name = this.name;
20823 input.name = '_hidden_' + this.name;
20828 input.cls += ' input-' + this.size;
20833 ['xs','sm','md','lg'].map(function(size){
20834 if (settings[size]) {
20835 cfg.cls += ' col-' + size + '-' + settings[size];
20839 var inputblock = input;
20841 if (this.before || this.after) {
20844 cls : 'input-group',
20849 inputblock.cn.push({
20851 cls : 'input-group-addon',
20856 inputblock.cn.push(input);
20858 if(this.inputType != 'radio'){
20859 inputblock.cn.push(hidden);
20863 inputblock.cn.push({
20865 cls : 'input-group-addon',
20872 if (align ==='left' && this.fieldLabel.length) {
20873 // Roo.log("left and has label");
20878 cls : 'control-label',
20879 html : this.fieldLabel
20889 if(this.labelWidth > 12){
20890 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20893 if(this.labelWidth < 13 && this.labelmd == 0){
20894 this.labelmd = this.labelWidth;
20897 if(this.labellg > 0){
20898 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20899 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20902 if(this.labelmd > 0){
20903 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20904 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20907 if(this.labelsm > 0){
20908 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20909 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20912 if(this.labelxs > 0){
20913 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20914 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20917 } else if ( this.fieldLabel.length) {
20918 // Roo.log(" label");
20922 tag: this.boxLabel ? 'span' : 'label',
20924 cls: 'control-label box-input-label',
20925 //cls : 'input-group-addon',
20926 html : this.fieldLabel
20935 // Roo.log(" no label && no align");
20936 cfg.cn = [ inputblock ] ;
20942 var boxLabelCfg = {
20944 //'for': id, // box label is handled by onclick - so no for...
20946 html: this.boxLabel
20950 boxLabelCfg.tooltip = this.tooltip;
20953 cfg.cn.push(boxLabelCfg);
20956 if(this.inputType != 'radio'){
20957 cfg.cn.push(hidden);
20965 * return the real input element.
20967 inputEl: function ()
20969 return this.el.select('input.roo-' + this.inputType,true).first();
20971 hiddenEl: function ()
20973 return this.el.select('input.roo-hidden-value',true).first();
20976 labelEl: function()
20978 return this.el.select('label.control-label',true).first();
20980 /* depricated... */
20984 return this.labelEl();
20987 boxLabelEl: function()
20989 return this.el.select('label.box-label',true).first();
20992 initEvents : function()
20994 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
20996 this.inputEl().on('click', this.onClick, this);
20998 if (this.boxLabel) {
20999 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21002 this.startValue = this.getValue();
21005 Roo.bootstrap.CheckBox.register(this);
21009 onClick : function(e)
21011 if(this.fireEvent('click', this, e) !== false){
21012 this.setChecked(!this.checked);
21017 setChecked : function(state,suppressEvent)
21019 this.startValue = this.getValue();
21021 if(this.inputType == 'radio'){
21023 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21024 e.dom.checked = false;
21027 this.inputEl().dom.checked = true;
21029 this.inputEl().dom.value = this.inputValue;
21031 if(suppressEvent !== true){
21032 this.fireEvent('check', this, true);
21040 this.checked = state;
21042 this.inputEl().dom.checked = state;
21045 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21047 if(suppressEvent !== true){
21048 this.fireEvent('check', this, state);
21054 getValue : function()
21056 if(this.inputType == 'radio'){
21057 return this.getGroupValue();
21060 return this.hiddenEl().dom.value;
21064 getGroupValue : function()
21066 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21070 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21073 setValue : function(v,suppressEvent)
21075 if(this.inputType == 'radio'){
21076 this.setGroupValue(v, suppressEvent);
21080 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21085 setGroupValue : function(v, suppressEvent)
21087 this.startValue = this.getValue();
21089 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21090 e.dom.checked = false;
21092 if(e.dom.value == v){
21093 e.dom.checked = true;
21097 if(suppressEvent !== true){
21098 this.fireEvent('check', this, true);
21106 validate : function()
21108 if(this.getVisibilityEl().hasClass('hidden')){
21114 (this.inputType == 'radio' && this.validateRadio()) ||
21115 (this.inputType == 'checkbox' && this.validateCheckbox())
21121 this.markInvalid();
21125 validateRadio : function()
21127 if(this.getVisibilityEl().hasClass('hidden')){
21131 if(this.allowBlank){
21137 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21138 if(!e.dom.checked){
21150 validateCheckbox : function()
21153 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21154 //return (this.getValue() == this.inputValue) ? true : false;
21157 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21165 for(var i in group){
21166 if(group[i].el.isVisible(true)){
21174 for(var i in group){
21179 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21186 * Mark this field as valid
21188 markValid : function()
21192 this.fireEvent('valid', this);
21194 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21197 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21204 if(this.inputType == 'radio'){
21205 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21206 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21207 e.findParent('.form-group', false, true).addClass(_this.validClass);
21214 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21215 this.el.findParent('.form-group', false, true).addClass(this.validClass);
21219 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21225 for(var i in group){
21226 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21227 group[i].el.findParent('.form-group', false, true).addClass(this.validClass);
21232 * Mark this field as invalid
21233 * @param {String} msg The validation message
21235 markInvalid : function(msg)
21237 if(this.allowBlank){
21243 this.fireEvent('invalid', this, msg);
21245 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21248 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21252 label.markInvalid();
21255 if(this.inputType == 'radio'){
21256 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21257 e.findParent('.form-group', false, true).removeClass([_this.invalidClass, _this.validClass]);
21258 e.findParent('.form-group', false, true).addClass(_this.invalidClass);
21265 this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21266 this.el.findParent('.form-group', false, true).addClass(this.invalidClass);
21270 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21276 for(var i in group){
21277 group[i].el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21278 group[i].el.findParent('.form-group', false, true).addClass(this.invalidClass);
21283 clearInvalid : function()
21285 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21287 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21289 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21291 if (label && label.iconEl) {
21292 label.iconEl.removeClass(label.validClass);
21293 label.iconEl.removeClass(label.invalidClass);
21297 disable : function()
21299 if(this.inputType != 'radio'){
21300 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21307 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21308 _this.getActionEl().addClass(this.disabledClass);
21309 e.dom.disabled = true;
21313 this.disabled = true;
21314 this.fireEvent("disable", this);
21318 enable : function()
21320 if(this.inputType != 'radio'){
21321 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21328 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21329 _this.getActionEl().removeClass(this.disabledClass);
21330 e.dom.disabled = false;
21334 this.disabled = false;
21335 this.fireEvent("enable", this);
21339 setBoxLabel : function(v)
21344 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21350 Roo.apply(Roo.bootstrap.CheckBox, {
21355 * register a CheckBox Group
21356 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21358 register : function(checkbox)
21360 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21361 this.groups[checkbox.groupId] = {};
21364 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21368 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21372 * fetch a CheckBox Group based on the group ID
21373 * @param {string} the group ID
21374 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21376 get: function(groupId) {
21377 if (typeof(this.groups[groupId]) == 'undefined') {
21381 return this.groups[groupId] ;
21394 * @class Roo.bootstrap.Radio
21395 * @extends Roo.bootstrap.Component
21396 * Bootstrap Radio class
21397 * @cfg {String} boxLabel - the label associated
21398 * @cfg {String} value - the value of radio
21401 * Create a new Radio
21402 * @param {Object} config The config object
21404 Roo.bootstrap.Radio = function(config){
21405 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21409 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21415 getAutoCreate : function()
21419 cls : 'form-group radio',
21424 html : this.boxLabel
21432 initEvents : function()
21434 this.parent().register(this);
21436 this.el.on('click', this.onClick, this);
21440 onClick : function(e)
21442 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21443 this.setChecked(true);
21447 setChecked : function(state, suppressEvent)
21449 this.parent().setValue(this.value, suppressEvent);
21453 setBoxLabel : function(v)
21458 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21473 * @class Roo.bootstrap.SecurePass
21474 * @extends Roo.bootstrap.Input
21475 * Bootstrap SecurePass class
21479 * Create a new SecurePass
21480 * @param {Object} config The config object
21483 Roo.bootstrap.SecurePass = function (config) {
21484 // these go here, so the translation tool can replace them..
21486 PwdEmpty: "Please type a password, and then retype it to confirm.",
21487 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21488 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21489 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21490 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21491 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21492 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21493 TooWeak: "Your password is Too Weak."
21495 this.meterLabel = "Password strength:";
21496 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21497 this.meterClass = [
21498 "roo-password-meter-tooweak",
21499 "roo-password-meter-weak",
21500 "roo-password-meter-medium",
21501 "roo-password-meter-strong",
21502 "roo-password-meter-grey"
21507 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21510 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21512 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21514 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21515 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21516 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21517 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21518 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21519 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21520 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21530 * @cfg {String/Object} Label for the strength meter (defaults to
21531 * 'Password strength:')
21536 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21537 * ['Weak', 'Medium', 'Strong'])
21540 pwdStrengths: false,
21553 initEvents: function ()
21555 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21557 if (this.el.is('input[type=password]') && Roo.isSafari) {
21558 this.el.on('keydown', this.SafariOnKeyDown, this);
21561 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21564 onRender: function (ct, position)
21566 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21567 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21568 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21570 this.trigger.createChild({
21575 cls: 'roo-password-meter-grey col-xs-12',
21578 //width: this.meterWidth + 'px'
21582 cls: 'roo-password-meter-text'
21588 if (this.hideTrigger) {
21589 this.trigger.setDisplayed(false);
21591 this.setSize(this.width || '', this.height || '');
21594 onDestroy: function ()
21596 if (this.trigger) {
21597 this.trigger.removeAllListeners();
21598 this.trigger.remove();
21601 this.wrap.remove();
21603 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21606 checkStrength: function ()
21608 var pwd = this.inputEl().getValue();
21609 if (pwd == this._lastPwd) {
21614 if (this.ClientSideStrongPassword(pwd)) {
21616 } else if (this.ClientSideMediumPassword(pwd)) {
21618 } else if (this.ClientSideWeakPassword(pwd)) {
21624 Roo.log('strength1: ' + strength);
21626 //var pm = this.trigger.child('div/div/div').dom;
21627 var pm = this.trigger.child('div/div');
21628 pm.removeClass(this.meterClass);
21629 pm.addClass(this.meterClass[strength]);
21632 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21634 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21636 this._lastPwd = pwd;
21640 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21642 this._lastPwd = '';
21644 var pm = this.trigger.child('div/div');
21645 pm.removeClass(this.meterClass);
21646 pm.addClass('roo-password-meter-grey');
21649 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21652 this.inputEl().dom.type='password';
21655 validateValue: function (value)
21658 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21661 if (value.length == 0) {
21662 if (this.allowBlank) {
21663 this.clearInvalid();
21667 this.markInvalid(this.errors.PwdEmpty);
21668 this.errorMsg = this.errors.PwdEmpty;
21676 if ('[\x21-\x7e]*'.match(value)) {
21677 this.markInvalid(this.errors.PwdBadChar);
21678 this.errorMsg = this.errors.PwdBadChar;
21681 if (value.length < 6) {
21682 this.markInvalid(this.errors.PwdShort);
21683 this.errorMsg = this.errors.PwdShort;
21686 if (value.length > 16) {
21687 this.markInvalid(this.errors.PwdLong);
21688 this.errorMsg = this.errors.PwdLong;
21692 if (this.ClientSideStrongPassword(value)) {
21694 } else if (this.ClientSideMediumPassword(value)) {
21696 } else if (this.ClientSideWeakPassword(value)) {
21703 if (strength < 2) {
21704 //this.markInvalid(this.errors.TooWeak);
21705 this.errorMsg = this.errors.TooWeak;
21710 console.log('strength2: ' + strength);
21712 //var pm = this.trigger.child('div/div/div').dom;
21714 var pm = this.trigger.child('div/div');
21715 pm.removeClass(this.meterClass);
21716 pm.addClass(this.meterClass[strength]);
21718 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21720 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21722 this.errorMsg = '';
21726 CharacterSetChecks: function (type)
21729 this.fResult = false;
21732 isctype: function (character, type)
21735 case this.kCapitalLetter:
21736 if (character >= 'A' && character <= 'Z') {
21741 case this.kSmallLetter:
21742 if (character >= 'a' && character <= 'z') {
21748 if (character >= '0' && character <= '9') {
21753 case this.kPunctuation:
21754 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21765 IsLongEnough: function (pwd, size)
21767 return !(pwd == null || isNaN(size) || pwd.length < size);
21770 SpansEnoughCharacterSets: function (word, nb)
21772 if (!this.IsLongEnough(word, nb))
21777 var characterSetChecks = new Array(
21778 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21779 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21782 for (var index = 0; index < word.length; ++index) {
21783 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21784 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21785 characterSetChecks[nCharSet].fResult = true;
21792 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21793 if (characterSetChecks[nCharSet].fResult) {
21798 if (nCharSets < nb) {
21804 ClientSideStrongPassword: function (pwd)
21806 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21809 ClientSideMediumPassword: function (pwd)
21811 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21814 ClientSideWeakPassword: function (pwd)
21816 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21819 })//<script type="text/javascript">
21822 * Based Ext JS Library 1.1.1
21823 * Copyright(c) 2006-2007, Ext JS, LLC.
21829 * @class Roo.HtmlEditorCore
21830 * @extends Roo.Component
21831 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21833 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21836 Roo.HtmlEditorCore = function(config){
21839 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21844 * @event initialize
21845 * Fires when the editor is fully initialized (including the iframe)
21846 * @param {Roo.HtmlEditorCore} this
21851 * Fires when the editor is first receives the focus. Any insertion must wait
21852 * until after this event.
21853 * @param {Roo.HtmlEditorCore} this
21857 * @event beforesync
21858 * Fires before the textarea is updated with content from the editor iframe. Return false
21859 * to cancel the sync.
21860 * @param {Roo.HtmlEditorCore} this
21861 * @param {String} html
21865 * @event beforepush
21866 * Fires before the iframe editor is updated with content from the textarea. Return false
21867 * to cancel the push.
21868 * @param {Roo.HtmlEditorCore} this
21869 * @param {String} html
21874 * Fires when the textarea is updated with content from the editor iframe.
21875 * @param {Roo.HtmlEditorCore} this
21876 * @param {String} html
21881 * Fires when the iframe editor is updated with content from the textarea.
21882 * @param {Roo.HtmlEditorCore} this
21883 * @param {String} html
21888 * @event editorevent
21889 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21890 * @param {Roo.HtmlEditorCore} this
21896 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21898 // defaults : white / black...
21899 this.applyBlacklists();
21906 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
21910 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
21916 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
21921 * @cfg {Number} height (in pixels)
21925 * @cfg {Number} width (in pixels)
21930 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
21933 stylesheets: false,
21938 // private properties
21939 validationEvent : false,
21941 initialized : false,
21943 sourceEditMode : false,
21944 onFocus : Roo.emptyFn,
21946 hideMode:'offsets',
21950 // blacklist + whitelisted elements..
21957 * Protected method that will not generally be called directly. It
21958 * is called when the editor initializes the iframe with HTML contents. Override this method if you
21959 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
21961 getDocMarkup : function(){
21965 // inherit styels from page...??
21966 if (this.stylesheets === false) {
21968 Roo.get(document.head).select('style').each(function(node) {
21969 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21972 Roo.get(document.head).select('link').each(function(node) {
21973 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
21976 } else if (!this.stylesheets.length) {
21978 st = '<style type="text/css">' +
21979 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
21982 st = '<style type="text/css">' +
21987 st += '<style type="text/css">' +
21988 'IMG { cursor: pointer } ' +
21991 var cls = 'roo-htmleditor-body';
21993 if(this.bodyCls.length){
21994 cls += ' ' + this.bodyCls;
21997 return '<html><head>' + st +
21998 //<style type="text/css">' +
21999 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22001 ' </head><body class="' + cls + '"></body></html>';
22005 onRender : function(ct, position)
22008 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22009 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22012 this.el.dom.style.border = '0 none';
22013 this.el.dom.setAttribute('tabIndex', -1);
22014 this.el.addClass('x-hidden hide');
22018 if(Roo.isIE){ // fix IE 1px bogus margin
22019 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22023 this.frameId = Roo.id();
22027 var iframe = this.owner.wrap.createChild({
22029 cls: 'form-control', // bootstrap..
22031 name: this.frameId,
22032 frameBorder : 'no',
22033 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22038 this.iframe = iframe.dom;
22040 this.assignDocWin();
22042 this.doc.designMode = 'on';
22045 this.doc.write(this.getDocMarkup());
22049 var task = { // must defer to wait for browser to be ready
22051 //console.log("run task?" + this.doc.readyState);
22052 this.assignDocWin();
22053 if(this.doc.body || this.doc.readyState == 'complete'){
22055 this.doc.designMode="on";
22059 Roo.TaskMgr.stop(task);
22060 this.initEditor.defer(10, this);
22067 Roo.TaskMgr.start(task);
22072 onResize : function(w, h)
22074 Roo.log('resize: ' +w + ',' + h );
22075 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22079 if(typeof w == 'number'){
22081 this.iframe.style.width = w + 'px';
22083 if(typeof h == 'number'){
22085 this.iframe.style.height = h + 'px';
22087 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22094 * Toggles the editor between standard and source edit mode.
22095 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22097 toggleSourceEdit : function(sourceEditMode){
22099 this.sourceEditMode = sourceEditMode === true;
22101 if(this.sourceEditMode){
22103 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22106 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22107 //this.iframe.className = '';
22110 //this.setSize(this.owner.wrap.getSize());
22111 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22118 * Protected method that will not generally be called directly. If you need/want
22119 * custom HTML cleanup, this is the method you should override.
22120 * @param {String} html The HTML to be cleaned
22121 * return {String} The cleaned HTML
22123 cleanHtml : function(html){
22124 html = String(html);
22125 if(html.length > 5){
22126 if(Roo.isSafari){ // strip safari nonsense
22127 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22130 if(html == ' '){
22137 * HTML Editor -> Textarea
22138 * Protected method that will not generally be called directly. Syncs the contents
22139 * of the editor iframe with the textarea.
22141 syncValue : function(){
22142 if(this.initialized){
22143 var bd = (this.doc.body || this.doc.documentElement);
22144 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22145 var html = bd.innerHTML;
22147 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22148 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22150 html = '<div style="'+m[0]+'">' + html + '</div>';
22153 html = this.cleanHtml(html);
22154 // fix up the special chars.. normaly like back quotes in word...
22155 // however we do not want to do this with chinese..
22156 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22157 var cc = b.charCodeAt();
22159 (cc >= 0x4E00 && cc < 0xA000 ) ||
22160 (cc >= 0x3400 && cc < 0x4E00 ) ||
22161 (cc >= 0xf900 && cc < 0xfb00 )
22167 if(this.owner.fireEvent('beforesync', this, html) !== false){
22168 this.el.dom.value = html;
22169 this.owner.fireEvent('sync', this, html);
22175 * Protected method that will not generally be called directly. Pushes the value of the textarea
22176 * into the iframe editor.
22178 pushValue : function(){
22179 if(this.initialized){
22180 var v = this.el.dom.value.trim();
22182 // if(v.length < 1){
22186 if(this.owner.fireEvent('beforepush', this, v) !== false){
22187 var d = (this.doc.body || this.doc.documentElement);
22189 this.cleanUpPaste();
22190 this.el.dom.value = d.innerHTML;
22191 this.owner.fireEvent('push', this, v);
22197 deferFocus : function(){
22198 this.focus.defer(10, this);
22202 focus : function(){
22203 if(this.win && !this.sourceEditMode){
22210 assignDocWin: function()
22212 var iframe = this.iframe;
22215 this.doc = iframe.contentWindow.document;
22216 this.win = iframe.contentWindow;
22218 // if (!Roo.get(this.frameId)) {
22221 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22222 // this.win = Roo.get(this.frameId).dom.contentWindow;
22224 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22228 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22229 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22234 initEditor : function(){
22235 //console.log("INIT EDITOR");
22236 this.assignDocWin();
22240 this.doc.designMode="on";
22242 this.doc.write(this.getDocMarkup());
22245 var dbody = (this.doc.body || this.doc.documentElement);
22246 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22247 // this copies styles from the containing element into thsi one..
22248 // not sure why we need all of this..
22249 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22251 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22252 //ss['background-attachment'] = 'fixed'; // w3c
22253 dbody.bgProperties = 'fixed'; // ie
22254 //Roo.DomHelper.applyStyles(dbody, ss);
22255 Roo.EventManager.on(this.doc, {
22256 //'mousedown': this.onEditorEvent,
22257 'mouseup': this.onEditorEvent,
22258 'dblclick': this.onEditorEvent,
22259 'click': this.onEditorEvent,
22260 'keyup': this.onEditorEvent,
22265 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22267 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22268 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22270 this.initialized = true;
22272 this.owner.fireEvent('initialize', this);
22277 onDestroy : function(){
22283 //for (var i =0; i < this.toolbars.length;i++) {
22284 // // fixme - ask toolbars for heights?
22285 // this.toolbars[i].onDestroy();
22288 //this.wrap.dom.innerHTML = '';
22289 //this.wrap.remove();
22294 onFirstFocus : function(){
22296 this.assignDocWin();
22299 this.activated = true;
22302 if(Roo.isGecko){ // prevent silly gecko errors
22304 var s = this.win.getSelection();
22305 if(!s.focusNode || s.focusNode.nodeType != 3){
22306 var r = s.getRangeAt(0);
22307 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22312 this.execCmd('useCSS', true);
22313 this.execCmd('styleWithCSS', false);
22316 this.owner.fireEvent('activate', this);
22320 adjustFont: function(btn){
22321 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22322 //if(Roo.isSafari){ // safari
22325 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22326 if(Roo.isSafari){ // safari
22327 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22328 v = (v < 10) ? 10 : v;
22329 v = (v > 48) ? 48 : v;
22330 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22335 v = Math.max(1, v+adjust);
22337 this.execCmd('FontSize', v );
22340 onEditorEvent : function(e)
22342 this.owner.fireEvent('editorevent', this, e);
22343 // this.updateToolbar();
22344 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22347 insertTag : function(tg)
22349 // could be a bit smarter... -> wrap the current selected tRoo..
22350 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22352 range = this.createRange(this.getSelection());
22353 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22354 wrappingNode.appendChild(range.extractContents());
22355 range.insertNode(wrappingNode);
22362 this.execCmd("formatblock", tg);
22366 insertText : function(txt)
22370 var range = this.createRange();
22371 range.deleteContents();
22372 //alert(Sender.getAttribute('label'));
22374 range.insertNode(this.doc.createTextNode(txt));
22380 * Executes a Midas editor command on the editor document and performs necessary focus and
22381 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22382 * @param {String} cmd The Midas command
22383 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22385 relayCmd : function(cmd, value){
22387 this.execCmd(cmd, value);
22388 this.owner.fireEvent('editorevent', this);
22389 //this.updateToolbar();
22390 this.owner.deferFocus();
22394 * Executes a Midas editor command directly on the editor document.
22395 * For visual commands, you should use {@link #relayCmd} instead.
22396 * <b>This should only be called after the editor is initialized.</b>
22397 * @param {String} cmd The Midas command
22398 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22400 execCmd : function(cmd, value){
22401 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22408 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22410 * @param {String} text | dom node..
22412 insertAtCursor : function(text)
22415 if(!this.activated){
22421 var r = this.doc.selection.createRange();
22432 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22436 // from jquery ui (MIT licenced)
22438 var win = this.win;
22440 if (win.getSelection && win.getSelection().getRangeAt) {
22441 range = win.getSelection().getRangeAt(0);
22442 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22443 range.insertNode(node);
22444 } else if (win.document.selection && win.document.selection.createRange) {
22445 // no firefox support
22446 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22447 win.document.selection.createRange().pasteHTML(txt);
22449 // no firefox support
22450 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22451 this.execCmd('InsertHTML', txt);
22460 mozKeyPress : function(e){
22462 var c = e.getCharCode(), cmd;
22465 c = String.fromCharCode(c).toLowerCase();
22479 this.cleanUpPaste.defer(100, this);
22487 e.preventDefault();
22495 fixKeys : function(){ // load time branching for fastest keydown performance
22497 return function(e){
22498 var k = e.getKey(), r;
22501 r = this.doc.selection.createRange();
22504 r.pasteHTML('    ');
22511 r = this.doc.selection.createRange();
22513 var target = r.parentElement();
22514 if(!target || target.tagName.toLowerCase() != 'li'){
22516 r.pasteHTML('<br />');
22522 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22523 this.cleanUpPaste.defer(100, this);
22529 }else if(Roo.isOpera){
22530 return function(e){
22531 var k = e.getKey();
22535 this.execCmd('InsertHTML','    ');
22538 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22539 this.cleanUpPaste.defer(100, this);
22544 }else if(Roo.isSafari){
22545 return function(e){
22546 var k = e.getKey();
22550 this.execCmd('InsertText','\t');
22554 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22555 this.cleanUpPaste.defer(100, this);
22563 getAllAncestors: function()
22565 var p = this.getSelectedNode();
22568 a.push(p); // push blank onto stack..
22569 p = this.getParentElement();
22573 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22577 a.push(this.doc.body);
22581 lastSelNode : false,
22584 getSelection : function()
22586 this.assignDocWin();
22587 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22590 getSelectedNode: function()
22592 // this may only work on Gecko!!!
22594 // should we cache this!!!!
22599 var range = this.createRange(this.getSelection()).cloneRange();
22602 var parent = range.parentElement();
22604 var testRange = range.duplicate();
22605 testRange.moveToElementText(parent);
22606 if (testRange.inRange(range)) {
22609 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22612 parent = parent.parentElement;
22617 // is ancestor a text element.
22618 var ac = range.commonAncestorContainer;
22619 if (ac.nodeType == 3) {
22620 ac = ac.parentNode;
22623 var ar = ac.childNodes;
22626 var other_nodes = [];
22627 var has_other_nodes = false;
22628 for (var i=0;i<ar.length;i++) {
22629 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22632 // fullly contained node.
22634 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22639 // probably selected..
22640 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22641 other_nodes.push(ar[i]);
22645 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22650 has_other_nodes = true;
22652 if (!nodes.length && other_nodes.length) {
22653 nodes= other_nodes;
22655 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22661 createRange: function(sel)
22663 // this has strange effects when using with
22664 // top toolbar - not sure if it's a great idea.
22665 //this.editor.contentWindow.focus();
22666 if (typeof sel != "undefined") {
22668 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22670 return this.doc.createRange();
22673 return this.doc.createRange();
22676 getParentElement: function()
22679 this.assignDocWin();
22680 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22682 var range = this.createRange(sel);
22685 var p = range.commonAncestorContainer;
22686 while (p.nodeType == 3) { // text node
22697 * Range intersection.. the hard stuff...
22701 * [ -- selected range --- ]
22705 * if end is before start or hits it. fail.
22706 * if start is after end or hits it fail.
22708 * if either hits (but other is outside. - then it's not
22714 // @see http://www.thismuchiknow.co.uk/?p=64.
22715 rangeIntersectsNode : function(range, node)
22717 var nodeRange = node.ownerDocument.createRange();
22719 nodeRange.selectNode(node);
22721 nodeRange.selectNodeContents(node);
22724 var rangeStartRange = range.cloneRange();
22725 rangeStartRange.collapse(true);
22727 var rangeEndRange = range.cloneRange();
22728 rangeEndRange.collapse(false);
22730 var nodeStartRange = nodeRange.cloneRange();
22731 nodeStartRange.collapse(true);
22733 var nodeEndRange = nodeRange.cloneRange();
22734 nodeEndRange.collapse(false);
22736 return rangeStartRange.compareBoundaryPoints(
22737 Range.START_TO_START, nodeEndRange) == -1 &&
22738 rangeEndRange.compareBoundaryPoints(
22739 Range.START_TO_START, nodeStartRange) == 1;
22743 rangeCompareNode : function(range, node)
22745 var nodeRange = node.ownerDocument.createRange();
22747 nodeRange.selectNode(node);
22749 nodeRange.selectNodeContents(node);
22753 range.collapse(true);
22755 nodeRange.collapse(true);
22757 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22758 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22760 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22762 var nodeIsBefore = ss == 1;
22763 var nodeIsAfter = ee == -1;
22765 if (nodeIsBefore && nodeIsAfter) {
22768 if (!nodeIsBefore && nodeIsAfter) {
22769 return 1; //right trailed.
22772 if (nodeIsBefore && !nodeIsAfter) {
22773 return 2; // left trailed.
22779 // private? - in a new class?
22780 cleanUpPaste : function()
22782 // cleans up the whole document..
22783 Roo.log('cleanuppaste');
22785 this.cleanUpChildren(this.doc.body);
22786 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22787 if (clean != this.doc.body.innerHTML) {
22788 this.doc.body.innerHTML = clean;
22793 cleanWordChars : function(input) {// change the chars to hex code
22794 var he = Roo.HtmlEditorCore;
22796 var output = input;
22797 Roo.each(he.swapCodes, function(sw) {
22798 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22800 output = output.replace(swapper, sw[1]);
22807 cleanUpChildren : function (n)
22809 if (!n.childNodes.length) {
22812 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22813 this.cleanUpChild(n.childNodes[i]);
22820 cleanUpChild : function (node)
22823 //console.log(node);
22824 if (node.nodeName == "#text") {
22825 // clean up silly Windows -- stuff?
22828 if (node.nodeName == "#comment") {
22829 node.parentNode.removeChild(node);
22830 // clean up silly Windows -- stuff?
22833 var lcname = node.tagName.toLowerCase();
22834 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22835 // whitelist of tags..
22837 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22839 node.parentNode.removeChild(node);
22844 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22846 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22847 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22849 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22850 // remove_keep_children = true;
22853 if (remove_keep_children) {
22854 this.cleanUpChildren(node);
22855 // inserts everything just before this node...
22856 while (node.childNodes.length) {
22857 var cn = node.childNodes[0];
22858 node.removeChild(cn);
22859 node.parentNode.insertBefore(cn, node);
22861 node.parentNode.removeChild(node);
22865 if (!node.attributes || !node.attributes.length) {
22866 this.cleanUpChildren(node);
22870 function cleanAttr(n,v)
22873 if (v.match(/^\./) || v.match(/^\//)) {
22876 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22879 if (v.match(/^#/)) {
22882 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22883 node.removeAttribute(n);
22887 var cwhite = this.cwhite;
22888 var cblack = this.cblack;
22890 function cleanStyle(n,v)
22892 if (v.match(/expression/)) { //XSS?? should we even bother..
22893 node.removeAttribute(n);
22897 var parts = v.split(/;/);
22900 Roo.each(parts, function(p) {
22901 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
22905 var l = p.split(':').shift().replace(/\s+/g,'');
22906 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
22908 if ( cwhite.length && cblack.indexOf(l) > -1) {
22909 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22910 //node.removeAttribute(n);
22914 // only allow 'c whitelisted system attributes'
22915 if ( cwhite.length && cwhite.indexOf(l) < 0) {
22916 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
22917 //node.removeAttribute(n);
22927 if (clean.length) {
22928 node.setAttribute(n, clean.join(';'));
22930 node.removeAttribute(n);
22936 for (var i = node.attributes.length-1; i > -1 ; i--) {
22937 var a = node.attributes[i];
22940 if (a.name.toLowerCase().substr(0,2)=='on') {
22941 node.removeAttribute(a.name);
22944 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
22945 node.removeAttribute(a.name);
22948 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
22949 cleanAttr(a.name,a.value); // fixme..
22952 if (a.name == 'style') {
22953 cleanStyle(a.name,a.value);
22956 /// clean up MS crap..
22957 // tecnically this should be a list of valid class'es..
22960 if (a.name == 'class') {
22961 if (a.value.match(/^Mso/)) {
22962 node.className = '';
22965 if (a.value.match(/^body$/)) {
22966 node.className = '';
22977 this.cleanUpChildren(node);
22983 * Clean up MS wordisms...
22985 cleanWord : function(node)
22990 this.cleanWord(this.doc.body);
22993 if (node.nodeName == "#text") {
22994 // clean up silly Windows -- stuff?
22997 if (node.nodeName == "#comment") {
22998 node.parentNode.removeChild(node);
22999 // clean up silly Windows -- stuff?
23003 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23004 node.parentNode.removeChild(node);
23008 // remove - but keep children..
23009 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23010 while (node.childNodes.length) {
23011 var cn = node.childNodes[0];
23012 node.removeChild(cn);
23013 node.parentNode.insertBefore(cn, node);
23015 node.parentNode.removeChild(node);
23016 this.iterateChildren(node, this.cleanWord);
23020 if (node.className.length) {
23022 var cn = node.className.split(/\W+/);
23024 Roo.each(cn, function(cls) {
23025 if (cls.match(/Mso[a-zA-Z]+/)) {
23030 node.className = cna.length ? cna.join(' ') : '';
23032 node.removeAttribute("class");
23036 if (node.hasAttribute("lang")) {
23037 node.removeAttribute("lang");
23040 if (node.hasAttribute("style")) {
23042 var styles = node.getAttribute("style").split(";");
23044 Roo.each(styles, function(s) {
23045 if (!s.match(/:/)) {
23048 var kv = s.split(":");
23049 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23052 // what ever is left... we allow.
23055 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23056 if (!nstyle.length) {
23057 node.removeAttribute('style');
23060 this.iterateChildren(node, this.cleanWord);
23066 * iterateChildren of a Node, calling fn each time, using this as the scole..
23067 * @param {DomNode} node node to iterate children of.
23068 * @param {Function} fn method of this class to call on each item.
23070 iterateChildren : function(node, fn)
23072 if (!node.childNodes.length) {
23075 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23076 fn.call(this, node.childNodes[i])
23082 * cleanTableWidths.
23084 * Quite often pasting from word etc.. results in tables with column and widths.
23085 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23088 cleanTableWidths : function(node)
23093 this.cleanTableWidths(this.doc.body);
23098 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23101 Roo.log(node.tagName);
23102 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23103 this.iterateChildren(node, this.cleanTableWidths);
23106 if (node.hasAttribute('width')) {
23107 node.removeAttribute('width');
23111 if (node.hasAttribute("style")) {
23114 var styles = node.getAttribute("style").split(";");
23116 Roo.each(styles, function(s) {
23117 if (!s.match(/:/)) {
23120 var kv = s.split(":");
23121 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23124 // what ever is left... we allow.
23127 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23128 if (!nstyle.length) {
23129 node.removeAttribute('style');
23133 this.iterateChildren(node, this.cleanTableWidths);
23141 domToHTML : function(currentElement, depth, nopadtext) {
23143 depth = depth || 0;
23144 nopadtext = nopadtext || false;
23146 if (!currentElement) {
23147 return this.domToHTML(this.doc.body);
23150 //Roo.log(currentElement);
23152 var allText = false;
23153 var nodeName = currentElement.nodeName;
23154 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23156 if (nodeName == '#text') {
23158 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23163 if (nodeName != 'BODY') {
23166 // Prints the node tagName, such as <A>, <IMG>, etc
23169 for(i = 0; i < currentElement.attributes.length;i++) {
23171 var aname = currentElement.attributes.item(i).name;
23172 if (!currentElement.attributes.item(i).value.length) {
23175 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23178 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23187 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23190 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23195 // Traverse the tree
23197 var currentElementChild = currentElement.childNodes.item(i);
23198 var allText = true;
23199 var innerHTML = '';
23201 while (currentElementChild) {
23202 // Formatting code (indent the tree so it looks nice on the screen)
23203 var nopad = nopadtext;
23204 if (lastnode == 'SPAN') {
23208 if (currentElementChild.nodeName == '#text') {
23209 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23210 toadd = nopadtext ? toadd : toadd.trim();
23211 if (!nopad && toadd.length > 80) {
23212 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23214 innerHTML += toadd;
23217 currentElementChild = currentElement.childNodes.item(i);
23223 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23225 // Recursively traverse the tree structure of the child node
23226 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23227 lastnode = currentElementChild.nodeName;
23229 currentElementChild=currentElement.childNodes.item(i);
23235 // The remaining code is mostly for formatting the tree
23236 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23241 ret+= "</"+tagName+">";
23247 applyBlacklists : function()
23249 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23250 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23254 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23255 if (b.indexOf(tag) > -1) {
23258 this.white.push(tag);
23262 Roo.each(w, function(tag) {
23263 if (b.indexOf(tag) > -1) {
23266 if (this.white.indexOf(tag) > -1) {
23269 this.white.push(tag);
23274 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23275 if (w.indexOf(tag) > -1) {
23278 this.black.push(tag);
23282 Roo.each(b, function(tag) {
23283 if (w.indexOf(tag) > -1) {
23286 if (this.black.indexOf(tag) > -1) {
23289 this.black.push(tag);
23294 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23295 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23299 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23300 if (b.indexOf(tag) > -1) {
23303 this.cwhite.push(tag);
23307 Roo.each(w, function(tag) {
23308 if (b.indexOf(tag) > -1) {
23311 if (this.cwhite.indexOf(tag) > -1) {
23314 this.cwhite.push(tag);
23319 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23320 if (w.indexOf(tag) > -1) {
23323 this.cblack.push(tag);
23327 Roo.each(b, function(tag) {
23328 if (w.indexOf(tag) > -1) {
23331 if (this.cblack.indexOf(tag) > -1) {
23334 this.cblack.push(tag);
23339 setStylesheets : function(stylesheets)
23341 if(typeof(stylesheets) == 'string'){
23342 Roo.get(this.iframe.contentDocument.head).createChild({
23344 rel : 'stylesheet',
23353 Roo.each(stylesheets, function(s) {
23358 Roo.get(_this.iframe.contentDocument.head).createChild({
23360 rel : 'stylesheet',
23369 removeStylesheets : function()
23373 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23378 setStyle : function(style)
23380 Roo.get(this.iframe.contentDocument.head).createChild({
23389 // hide stuff that is not compatible
23403 * @event specialkey
23407 * @cfg {String} fieldClass @hide
23410 * @cfg {String} focusClass @hide
23413 * @cfg {String} autoCreate @hide
23416 * @cfg {String} inputType @hide
23419 * @cfg {String} invalidClass @hide
23422 * @cfg {String} invalidText @hide
23425 * @cfg {String} msgFx @hide
23428 * @cfg {String} validateOnBlur @hide
23432 Roo.HtmlEditorCore.white = [
23433 'area', 'br', 'img', 'input', 'hr', 'wbr',
23435 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23436 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23437 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23438 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23439 'table', 'ul', 'xmp',
23441 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23444 'dir', 'menu', 'ol', 'ul', 'dl',
23450 Roo.HtmlEditorCore.black = [
23451 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23453 'base', 'basefont', 'bgsound', 'blink', 'body',
23454 'frame', 'frameset', 'head', 'html', 'ilayer',
23455 'iframe', 'layer', 'link', 'meta', 'object',
23456 'script', 'style' ,'title', 'xml' // clean later..
23458 Roo.HtmlEditorCore.clean = [
23459 'script', 'style', 'title', 'xml'
23461 Roo.HtmlEditorCore.remove = [
23466 Roo.HtmlEditorCore.ablack = [
23470 Roo.HtmlEditorCore.aclean = [
23471 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23475 Roo.HtmlEditorCore.pwhite= [
23476 'http', 'https', 'mailto'
23479 // white listed style attributes.
23480 Roo.HtmlEditorCore.cwhite= [
23481 // 'text-align', /// default is to allow most things..
23487 // black listed style attributes.
23488 Roo.HtmlEditorCore.cblack= [
23489 // 'font-size' -- this can be set by the project
23493 Roo.HtmlEditorCore.swapCodes =[
23512 * @class Roo.bootstrap.HtmlEditor
23513 * @extends Roo.bootstrap.TextArea
23514 * Bootstrap HtmlEditor class
23517 * Create a new HtmlEditor
23518 * @param {Object} config The config object
23521 Roo.bootstrap.HtmlEditor = function(config){
23522 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23523 if (!this.toolbars) {
23524 this.toolbars = [];
23527 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23530 * @event initialize
23531 * Fires when the editor is fully initialized (including the iframe)
23532 * @param {HtmlEditor} this
23537 * Fires when the editor is first receives the focus. Any insertion must wait
23538 * until after this event.
23539 * @param {HtmlEditor} this
23543 * @event beforesync
23544 * Fires before the textarea is updated with content from the editor iframe. Return false
23545 * to cancel the sync.
23546 * @param {HtmlEditor} this
23547 * @param {String} html
23551 * @event beforepush
23552 * Fires before the iframe editor is updated with content from the textarea. Return false
23553 * to cancel the push.
23554 * @param {HtmlEditor} this
23555 * @param {String} html
23560 * Fires when the textarea is updated with content from the editor iframe.
23561 * @param {HtmlEditor} this
23562 * @param {String} html
23567 * Fires when the iframe editor is updated with content from the textarea.
23568 * @param {HtmlEditor} this
23569 * @param {String} html
23573 * @event editmodechange
23574 * Fires when the editor switches edit modes
23575 * @param {HtmlEditor} this
23576 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23578 editmodechange: true,
23580 * @event editorevent
23581 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23582 * @param {HtmlEditor} this
23586 * @event firstfocus
23587 * Fires when on first focus - needed by toolbars..
23588 * @param {HtmlEditor} this
23593 * Auto save the htmlEditor value as a file into Events
23594 * @param {HtmlEditor} this
23598 * @event savedpreview
23599 * preview the saved version of htmlEditor
23600 * @param {HtmlEditor} this
23607 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23611 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23616 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23621 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23626 * @cfg {Number} height (in pixels)
23630 * @cfg {Number} width (in pixels)
23635 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23638 stylesheets: false,
23643 // private properties
23644 validationEvent : false,
23646 initialized : false,
23649 onFocus : Roo.emptyFn,
23651 hideMode:'offsets',
23653 tbContainer : false,
23657 toolbarContainer :function() {
23658 return this.wrap.select('.x-html-editor-tb',true).first();
23662 * Protected method that will not generally be called directly. It
23663 * is called when the editor creates its toolbar. Override this method if you need to
23664 * add custom toolbar buttons.
23665 * @param {HtmlEditor} editor
23667 createToolbar : function(){
23668 Roo.log('renewing');
23669 Roo.log("create toolbars");
23671 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23672 this.toolbars[0].render(this.toolbarContainer());
23676 // if (!editor.toolbars || !editor.toolbars.length) {
23677 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23680 // for (var i =0 ; i < editor.toolbars.length;i++) {
23681 // editor.toolbars[i] = Roo.factory(
23682 // typeof(editor.toolbars[i]) == 'string' ?
23683 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23684 // Roo.bootstrap.HtmlEditor);
23685 // editor.toolbars[i].init(editor);
23691 onRender : function(ct, position)
23693 // Roo.log("Call onRender: " + this.xtype);
23695 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23697 this.wrap = this.inputEl().wrap({
23698 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23701 this.editorcore.onRender(ct, position);
23703 if (this.resizable) {
23704 this.resizeEl = new Roo.Resizable(this.wrap, {
23708 minHeight : this.height,
23709 height: this.height,
23710 handles : this.resizable,
23713 resize : function(r, w, h) {
23714 _t.onResize(w,h); // -something
23720 this.createToolbar(this);
23723 if(!this.width && this.resizable){
23724 this.setSize(this.wrap.getSize());
23726 if (this.resizeEl) {
23727 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23728 // should trigger onReize..
23734 onResize : function(w, h)
23736 Roo.log('resize: ' +w + ',' + h );
23737 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23741 if(this.inputEl() ){
23742 if(typeof w == 'number'){
23743 var aw = w - this.wrap.getFrameWidth('lr');
23744 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23747 if(typeof h == 'number'){
23748 var tbh = -11; // fixme it needs to tool bar size!
23749 for (var i =0; i < this.toolbars.length;i++) {
23750 // fixme - ask toolbars for heights?
23751 tbh += this.toolbars[i].el.getHeight();
23752 //if (this.toolbars[i].footer) {
23753 // tbh += this.toolbars[i].footer.el.getHeight();
23761 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23762 ah -= 5; // knock a few pixes off for look..
23763 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23767 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23768 this.editorcore.onResize(ew,eh);
23773 * Toggles the editor between standard and source edit mode.
23774 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23776 toggleSourceEdit : function(sourceEditMode)
23778 this.editorcore.toggleSourceEdit(sourceEditMode);
23780 if(this.editorcore.sourceEditMode){
23781 Roo.log('editor - showing textarea');
23784 // Roo.log(this.syncValue());
23786 this.inputEl().removeClass(['hide', 'x-hidden']);
23787 this.inputEl().dom.removeAttribute('tabIndex');
23788 this.inputEl().focus();
23790 Roo.log('editor - hiding textarea');
23792 // Roo.log(this.pushValue());
23795 this.inputEl().addClass(['hide', 'x-hidden']);
23796 this.inputEl().dom.setAttribute('tabIndex', -1);
23797 //this.deferFocus();
23800 if(this.resizable){
23801 this.setSize(this.wrap.getSize());
23804 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23807 // private (for BoxComponent)
23808 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23810 // private (for BoxComponent)
23811 getResizeEl : function(){
23815 // private (for BoxComponent)
23816 getPositionEl : function(){
23821 initEvents : function(){
23822 this.originalValue = this.getValue();
23826 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23829 // markInvalid : Roo.emptyFn,
23831 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23834 // clearInvalid : Roo.emptyFn,
23836 setValue : function(v){
23837 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23838 this.editorcore.pushValue();
23843 deferFocus : function(){
23844 this.focus.defer(10, this);
23848 focus : function(){
23849 this.editorcore.focus();
23855 onDestroy : function(){
23861 for (var i =0; i < this.toolbars.length;i++) {
23862 // fixme - ask toolbars for heights?
23863 this.toolbars[i].onDestroy();
23866 this.wrap.dom.innerHTML = '';
23867 this.wrap.remove();
23872 onFirstFocus : function(){
23873 //Roo.log("onFirstFocus");
23874 this.editorcore.onFirstFocus();
23875 for (var i =0; i < this.toolbars.length;i++) {
23876 this.toolbars[i].onFirstFocus();
23882 syncValue : function()
23884 this.editorcore.syncValue();
23887 pushValue : function()
23889 this.editorcore.pushValue();
23893 // hide stuff that is not compatible
23907 * @event specialkey
23911 * @cfg {String} fieldClass @hide
23914 * @cfg {String} focusClass @hide
23917 * @cfg {String} autoCreate @hide
23920 * @cfg {String} inputType @hide
23923 * @cfg {String} invalidClass @hide
23926 * @cfg {String} invalidText @hide
23929 * @cfg {String} msgFx @hide
23932 * @cfg {String} validateOnBlur @hide
23941 Roo.namespace('Roo.bootstrap.htmleditor');
23943 * @class Roo.bootstrap.HtmlEditorToolbar1
23948 new Roo.bootstrap.HtmlEditor({
23951 new Roo.bootstrap.HtmlEditorToolbar1({
23952 disable : { fonts: 1 , format: 1, ..., ... , ...],
23958 * @cfg {Object} disable List of elements to disable..
23959 * @cfg {Array} btns List of additional buttons.
23963 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
23966 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
23969 Roo.apply(this, config);
23971 // default disabled, based on 'good practice'..
23972 this.disable = this.disable || {};
23973 Roo.applyIf(this.disable, {
23976 specialElements : true
23978 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
23980 this.editor = config.editor;
23981 this.editorcore = config.editor.editorcore;
23983 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
23985 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
23986 // dont call parent... till later.
23988 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
23993 editorcore : false,
23998 "h1","h2","h3","h4","h5","h6",
24000 "abbr", "acronym", "address", "cite", "samp", "var",
24004 onRender : function(ct, position)
24006 // Roo.log("Call onRender: " + this.xtype);
24008 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24010 this.el.dom.style.marginBottom = '0';
24012 var editorcore = this.editorcore;
24013 var editor= this.editor;
24016 var btn = function(id,cmd , toggle, handler, html){
24018 var event = toggle ? 'toggle' : 'click';
24023 xns: Roo.bootstrap,
24027 enableToggle:toggle !== false,
24029 pressed : toggle ? false : null,
24032 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24033 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24039 // var cb_box = function...
24044 xns: Roo.bootstrap,
24049 xns: Roo.bootstrap,
24053 Roo.each(this.formats, function(f) {
24054 style.menu.items.push({
24056 xns: Roo.bootstrap,
24057 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24062 editorcore.insertTag(this.tagname);
24069 children.push(style);
24071 btn('bold',false,true);
24072 btn('italic',false,true);
24073 btn('align-left', 'justifyleft',true);
24074 btn('align-center', 'justifycenter',true);
24075 btn('align-right' , 'justifyright',true);
24076 btn('link', false, false, function(btn) {
24077 //Roo.log("create link?");
24078 var url = prompt(this.createLinkText, this.defaultLinkValue);
24079 if(url && url != 'http:/'+'/'){
24080 this.editorcore.relayCmd('createlink', url);
24083 btn('list','insertunorderedlist',true);
24084 btn('pencil', false,true, function(btn){
24086 this.toggleSourceEdit(btn.pressed);
24089 if (this.editor.btns.length > 0) {
24090 for (var i = 0; i<this.editor.btns.length; i++) {
24091 children.push(this.editor.btns[i]);
24099 xns: Roo.bootstrap,
24104 xns: Roo.bootstrap,
24109 cog.menu.items.push({
24111 xns: Roo.bootstrap,
24112 html : Clean styles,
24117 editorcore.insertTag(this.tagname);
24126 this.xtype = 'NavSimplebar';
24128 for(var i=0;i< children.length;i++) {
24130 this.buttons.add(this.addxtypeChild(children[i]));
24134 editor.on('editorevent', this.updateToolbar, this);
24136 onBtnClick : function(id)
24138 this.editorcore.relayCmd(id);
24139 this.editorcore.focus();
24143 * Protected method that will not generally be called directly. It triggers
24144 * a toolbar update by reading the markup state of the current selection in the editor.
24146 updateToolbar: function(){
24148 if(!this.editorcore.activated){
24149 this.editor.onFirstFocus(); // is this neeed?
24153 var btns = this.buttons;
24154 var doc = this.editorcore.doc;
24155 btns.get('bold').setActive(doc.queryCommandState('bold'));
24156 btns.get('italic').setActive(doc.queryCommandState('italic'));
24157 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24159 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24160 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24161 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24163 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24164 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24167 var ans = this.editorcore.getAllAncestors();
24168 if (this.formatCombo) {
24171 var store = this.formatCombo.store;
24172 this.formatCombo.setValue("");
24173 for (var i =0; i < ans.length;i++) {
24174 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24176 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24184 // hides menus... - so this cant be on a menu...
24185 Roo.bootstrap.MenuMgr.hideAll();
24187 Roo.bootstrap.MenuMgr.hideAll();
24188 //this.editorsyncValue();
24190 onFirstFocus: function() {
24191 this.buttons.each(function(item){
24195 toggleSourceEdit : function(sourceEditMode){
24198 if(sourceEditMode){
24199 Roo.log("disabling buttons");
24200 this.buttons.each( function(item){
24201 if(item.cmd != 'pencil'){
24207 Roo.log("enabling buttons");
24208 if(this.editorcore.initialized){
24209 this.buttons.each( function(item){
24215 Roo.log("calling toggole on editor");
24216 // tell the editor that it's been pressed..
24217 this.editor.toggleSourceEdit(sourceEditMode);
24227 * @class Roo.bootstrap.Table.AbstractSelectionModel
24228 * @extends Roo.util.Observable
24229 * Abstract base class for grid SelectionModels. It provides the interface that should be
24230 * implemented by descendant classes. This class should not be directly instantiated.
24233 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24234 this.locked = false;
24235 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24239 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24240 /** @ignore Called by the grid automatically. Do not call directly. */
24241 init : function(grid){
24247 * Locks the selections.
24250 this.locked = true;
24254 * Unlocks the selections.
24256 unlock : function(){
24257 this.locked = false;
24261 * Returns true if the selections are locked.
24262 * @return {Boolean}
24264 isLocked : function(){
24265 return this.locked;
24269 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24270 * @class Roo.bootstrap.Table.RowSelectionModel
24271 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24272 * It supports multiple selections and keyboard selection/navigation.
24274 * @param {Object} config
24277 Roo.bootstrap.Table.RowSelectionModel = function(config){
24278 Roo.apply(this, config);
24279 this.selections = new Roo.util.MixedCollection(false, function(o){
24284 this.lastActive = false;
24288 * @event selectionchange
24289 * Fires when the selection changes
24290 * @param {SelectionModel} this
24292 "selectionchange" : true,
24294 * @event afterselectionchange
24295 * Fires after the selection changes (eg. by key press or clicking)
24296 * @param {SelectionModel} this
24298 "afterselectionchange" : true,
24300 * @event beforerowselect
24301 * Fires when a row is selected being selected, return false to cancel.
24302 * @param {SelectionModel} this
24303 * @param {Number} rowIndex The selected index
24304 * @param {Boolean} keepExisting False if other selections will be cleared
24306 "beforerowselect" : true,
24309 * Fires when a row is selected.
24310 * @param {SelectionModel} this
24311 * @param {Number} rowIndex The selected index
24312 * @param {Roo.data.Record} r The record
24314 "rowselect" : true,
24316 * @event rowdeselect
24317 * Fires when a row is deselected.
24318 * @param {SelectionModel} this
24319 * @param {Number} rowIndex The selected index
24321 "rowdeselect" : true
24323 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24324 this.locked = false;
24327 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24329 * @cfg {Boolean} singleSelect
24330 * True to allow selection of only one row at a time (defaults to false)
24332 singleSelect : false,
24335 initEvents : function()
24338 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24339 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24340 //}else{ // allow click to work like normal
24341 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24343 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24344 this.grid.on("rowclick", this.handleMouseDown, this);
24346 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24347 "up" : function(e){
24349 this.selectPrevious(e.shiftKey);
24350 }else if(this.last !== false && this.lastActive !== false){
24351 var last = this.last;
24352 this.selectRange(this.last, this.lastActive-1);
24353 this.grid.getView().focusRow(this.lastActive);
24354 if(last !== false){
24358 this.selectFirstRow();
24360 this.fireEvent("afterselectionchange", this);
24362 "down" : function(e){
24364 this.selectNext(e.shiftKey);
24365 }else if(this.last !== false && this.lastActive !== false){
24366 var last = this.last;
24367 this.selectRange(this.last, this.lastActive+1);
24368 this.grid.getView().focusRow(this.lastActive);
24369 if(last !== false){
24373 this.selectFirstRow();
24375 this.fireEvent("afterselectionchange", this);
24379 this.grid.store.on('load', function(){
24380 this.selections.clear();
24383 var view = this.grid.view;
24384 view.on("refresh", this.onRefresh, this);
24385 view.on("rowupdated", this.onRowUpdated, this);
24386 view.on("rowremoved", this.onRemove, this);
24391 onRefresh : function()
24393 var ds = this.grid.store, i, v = this.grid.view;
24394 var s = this.selections;
24395 s.each(function(r){
24396 if((i = ds.indexOfId(r.id)) != -1){
24405 onRemove : function(v, index, r){
24406 this.selections.remove(r);
24410 onRowUpdated : function(v, index, r){
24411 if(this.isSelected(r)){
24412 v.onRowSelect(index);
24418 * @param {Array} records The records to select
24419 * @param {Boolean} keepExisting (optional) True to keep existing selections
24421 selectRecords : function(records, keepExisting)
24424 this.clearSelections();
24426 var ds = this.grid.store;
24427 for(var i = 0, len = records.length; i < len; i++){
24428 this.selectRow(ds.indexOf(records[i]), true);
24433 * Gets the number of selected rows.
24436 getCount : function(){
24437 return this.selections.length;
24441 * Selects the first row in the grid.
24443 selectFirstRow : function(){
24448 * Select the last row.
24449 * @param {Boolean} keepExisting (optional) True to keep existing selections
24451 selectLastRow : function(keepExisting){
24452 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24453 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24457 * Selects the row immediately following the last selected row.
24458 * @param {Boolean} keepExisting (optional) True to keep existing selections
24460 selectNext : function(keepExisting)
24462 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24463 this.selectRow(this.last+1, keepExisting);
24464 this.grid.getView().focusRow(this.last);
24469 * Selects the row that precedes the last selected row.
24470 * @param {Boolean} keepExisting (optional) True to keep existing selections
24472 selectPrevious : function(keepExisting){
24474 this.selectRow(this.last-1, keepExisting);
24475 this.grid.getView().focusRow(this.last);
24480 * Returns the selected records
24481 * @return {Array} Array of selected records
24483 getSelections : function(){
24484 return [].concat(this.selections.items);
24488 * Returns the first selected record.
24491 getSelected : function(){
24492 return this.selections.itemAt(0);
24497 * Clears all selections.
24499 clearSelections : function(fast)
24505 var ds = this.grid.store;
24506 var s = this.selections;
24507 s.each(function(r){
24508 this.deselectRow(ds.indexOfId(r.id));
24512 this.selections.clear();
24519 * Selects all rows.
24521 selectAll : function(){
24525 this.selections.clear();
24526 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24527 this.selectRow(i, true);
24532 * Returns True if there is a selection.
24533 * @return {Boolean}
24535 hasSelection : function(){
24536 return this.selections.length > 0;
24540 * Returns True if the specified row is selected.
24541 * @param {Number/Record} record The record or index of the record to check
24542 * @return {Boolean}
24544 isSelected : function(index){
24545 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24546 return (r && this.selections.key(r.id) ? true : false);
24550 * Returns True if the specified record id is selected.
24551 * @param {String} id The id of record to check
24552 * @return {Boolean}
24554 isIdSelected : function(id){
24555 return (this.selections.key(id) ? true : false);
24560 handleMouseDBClick : function(e, t){
24564 handleMouseDown : function(e, t)
24566 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24567 if(this.isLocked() || rowIndex < 0 ){
24570 if(e.shiftKey && this.last !== false){
24571 var last = this.last;
24572 this.selectRange(last, rowIndex, e.ctrlKey);
24573 this.last = last; // reset the last
24577 var isSelected = this.isSelected(rowIndex);
24578 //Roo.log("select row:" + rowIndex);
24580 this.deselectRow(rowIndex);
24582 this.selectRow(rowIndex, true);
24586 if(e.button !== 0 && isSelected){
24587 alert('rowIndex 2: ' + rowIndex);
24588 view.focusRow(rowIndex);
24589 }else if(e.ctrlKey && isSelected){
24590 this.deselectRow(rowIndex);
24591 }else if(!isSelected){
24592 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24593 view.focusRow(rowIndex);
24597 this.fireEvent("afterselectionchange", this);
24600 handleDragableRowClick : function(grid, rowIndex, e)
24602 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24603 this.selectRow(rowIndex, false);
24604 grid.view.focusRow(rowIndex);
24605 this.fireEvent("afterselectionchange", this);
24610 * Selects multiple rows.
24611 * @param {Array} rows Array of the indexes of the row to select
24612 * @param {Boolean} keepExisting (optional) True to keep existing selections
24614 selectRows : function(rows, keepExisting){
24616 this.clearSelections();
24618 for(var i = 0, len = rows.length; i < len; i++){
24619 this.selectRow(rows[i], true);
24624 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24625 * @param {Number} startRow The index of the first row in the range
24626 * @param {Number} endRow The index of the last row in the range
24627 * @param {Boolean} keepExisting (optional) True to retain existing selections
24629 selectRange : function(startRow, endRow, keepExisting){
24634 this.clearSelections();
24636 if(startRow <= endRow){
24637 for(var i = startRow; i <= endRow; i++){
24638 this.selectRow(i, true);
24641 for(var i = startRow; i >= endRow; i--){
24642 this.selectRow(i, true);
24648 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24649 * @param {Number} startRow The index of the first row in the range
24650 * @param {Number} endRow The index of the last row in the range
24652 deselectRange : function(startRow, endRow, preventViewNotify){
24656 for(var i = startRow; i <= endRow; i++){
24657 this.deselectRow(i, preventViewNotify);
24663 * @param {Number} row The index of the row to select
24664 * @param {Boolean} keepExisting (optional) True to keep existing selections
24666 selectRow : function(index, keepExisting, preventViewNotify)
24668 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24671 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24672 if(!keepExisting || this.singleSelect){
24673 this.clearSelections();
24676 var r = this.grid.store.getAt(index);
24677 //console.log('selectRow - record id :' + r.id);
24679 this.selections.add(r);
24680 this.last = this.lastActive = index;
24681 if(!preventViewNotify){
24682 var proxy = new Roo.Element(
24683 this.grid.getRowDom(index)
24685 proxy.addClass('bg-info info');
24687 this.fireEvent("rowselect", this, index, r);
24688 this.fireEvent("selectionchange", this);
24694 * @param {Number} row The index of the row to deselect
24696 deselectRow : function(index, preventViewNotify)
24701 if(this.last == index){
24704 if(this.lastActive == index){
24705 this.lastActive = false;
24708 var r = this.grid.store.getAt(index);
24713 this.selections.remove(r);
24714 //.console.log('deselectRow - record id :' + r.id);
24715 if(!preventViewNotify){
24717 var proxy = new Roo.Element(
24718 this.grid.getRowDom(index)
24720 proxy.removeClass('bg-info info');
24722 this.fireEvent("rowdeselect", this, index);
24723 this.fireEvent("selectionchange", this);
24727 restoreLast : function(){
24729 this.last = this._last;
24734 acceptsNav : function(row, col, cm){
24735 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24739 onEditorKey : function(field, e){
24740 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24745 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24747 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24749 }else if(k == e.ENTER && !e.ctrlKey){
24753 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24755 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24757 }else if(k == e.ESC){
24761 g.startEditing(newCell[0], newCell[1]);
24767 * Ext JS Library 1.1.1
24768 * Copyright(c) 2006-2007, Ext JS, LLC.
24770 * Originally Released Under LGPL - original licence link has changed is not relivant.
24773 * <script type="text/javascript">
24777 * @class Roo.bootstrap.PagingToolbar
24778 * @extends Roo.bootstrap.NavSimplebar
24779 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24781 * Create a new PagingToolbar
24782 * @param {Object} config The config object
24783 * @param {Roo.data.Store} store
24785 Roo.bootstrap.PagingToolbar = function(config)
24787 // old args format still supported... - xtype is prefered..
24788 // created from xtype...
24790 this.ds = config.dataSource;
24792 if (config.store && !this.ds) {
24793 this.store= Roo.factory(config.store, Roo.data);
24794 this.ds = this.store;
24795 this.ds.xmodule = this.xmodule || false;
24798 this.toolbarItems = [];
24799 if (config.items) {
24800 this.toolbarItems = config.items;
24803 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24808 this.bind(this.ds);
24811 if (Roo.bootstrap.version == 4) {
24812 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24814 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24819 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24821 * @cfg {Roo.data.Store} dataSource
24822 * The underlying data store providing the paged data
24825 * @cfg {String/HTMLElement/Element} container
24826 * container The id or element that will contain the toolbar
24829 * @cfg {Boolean} displayInfo
24830 * True to display the displayMsg (defaults to false)
24833 * @cfg {Number} pageSize
24834 * The number of records to display per page (defaults to 20)
24838 * @cfg {String} displayMsg
24839 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24841 displayMsg : 'Displaying {0} - {1} of {2}',
24843 * @cfg {String} emptyMsg
24844 * The message to display when no records are found (defaults to "No data to display")
24846 emptyMsg : 'No data to display',
24848 * Customizable piece of the default paging text (defaults to "Page")
24851 beforePageText : "Page",
24853 * Customizable piece of the default paging text (defaults to "of %0")
24856 afterPageText : "of {0}",
24858 * Customizable piece of the default paging text (defaults to "First Page")
24861 firstText : "First Page",
24863 * Customizable piece of the default paging text (defaults to "Previous Page")
24866 prevText : "Previous Page",
24868 * Customizable piece of the default paging text (defaults to "Next Page")
24871 nextText : "Next Page",
24873 * Customizable piece of the default paging text (defaults to "Last Page")
24876 lastText : "Last Page",
24878 * Customizable piece of the default paging text (defaults to "Refresh")
24881 refreshText : "Refresh",
24885 onRender : function(ct, position)
24887 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24888 this.navgroup.parentId = this.id;
24889 this.navgroup.onRender(this.el, null);
24890 // add the buttons to the navgroup
24892 if(this.displayInfo){
24893 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24894 this.displayEl = this.el.select('.x-paging-info', true).first();
24895 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24896 // this.displayEl = navel.el.select('span',true).first();
24902 Roo.each(_this.buttons, function(e){ // this might need to use render????
24903 Roo.factory(e).render(_this.el);
24907 Roo.each(_this.toolbarItems, function(e) {
24908 _this.navgroup.addItem(e);
24912 this.first = this.navgroup.addItem({
24913 tooltip: this.firstText,
24914 cls: "prev btn-outline-secondary",
24915 html : ' <i class="fa fa-step-backward"></i>',
24917 preventDefault: true,
24918 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
24921 this.prev = this.navgroup.addItem({
24922 tooltip: this.prevText,
24923 cls: "prev btn-outline-secondary",
24924 html : ' <i class="fa fa-backward"></i>',
24926 preventDefault: true,
24927 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
24929 //this.addSeparator();
24932 var field = this.navgroup.addItem( {
24934 cls : 'x-paging-position btn-outline-secondary',
24936 html : this.beforePageText +
24937 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
24938 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
24941 this.field = field.el.select('input', true).first();
24942 this.field.on("keydown", this.onPagingKeydown, this);
24943 this.field.on("focus", function(){this.dom.select();});
24946 this.afterTextEl = field.el.select('.x-paging-after',true).first();
24947 //this.field.setHeight(18);
24948 //this.addSeparator();
24949 this.next = this.navgroup.addItem({
24950 tooltip: this.nextText,
24951 cls: "next btn-outline-secondary",
24952 html : ' <i class="fa fa-forward"></i>',
24954 preventDefault: true,
24955 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
24957 this.last = this.navgroup.addItem({
24958 tooltip: this.lastText,
24959 html : ' <i class="fa fa-step-forward"></i>',
24960 cls: "next btn-outline-secondary",
24962 preventDefault: true,
24963 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
24965 //this.addSeparator();
24966 this.loading = this.navgroup.addItem({
24967 tooltip: this.refreshText,
24968 cls: "btn-outline-secondary",
24969 html : ' <i class="fa fa-refresh"></i>',
24970 preventDefault: true,
24971 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
24977 updateInfo : function(){
24978 if(this.displayEl){
24979 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
24980 var msg = count == 0 ?
24984 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
24986 this.displayEl.update(msg);
24991 onLoad : function(ds, r, o)
24993 this.cursor = o.params.start ? o.params.start : 0;
24995 var d = this.getPageData(),
25000 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25001 this.field.dom.value = ap;
25002 this.first.setDisabled(ap == 1);
25003 this.prev.setDisabled(ap == 1);
25004 this.next.setDisabled(ap == ps);
25005 this.last.setDisabled(ap == ps);
25006 this.loading.enable();
25011 getPageData : function(){
25012 var total = this.ds.getTotalCount();
25015 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25016 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25021 onLoadError : function(){
25022 this.loading.enable();
25026 onPagingKeydown : function(e){
25027 var k = e.getKey();
25028 var d = this.getPageData();
25030 var v = this.field.dom.value, pageNum;
25031 if(!v || isNaN(pageNum = parseInt(v, 10))){
25032 this.field.dom.value = d.activePage;
25035 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25036 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25039 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))
25041 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25042 this.field.dom.value = pageNum;
25043 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25046 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25048 var v = this.field.dom.value, pageNum;
25049 var increment = (e.shiftKey) ? 10 : 1;
25050 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25053 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25054 this.field.dom.value = d.activePage;
25057 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25059 this.field.dom.value = parseInt(v, 10) + increment;
25060 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25061 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25068 beforeLoad : function(){
25070 this.loading.disable();
25075 onClick : function(which){
25084 ds.load({params:{start: 0, limit: this.pageSize}});
25087 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25090 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25093 var total = ds.getTotalCount();
25094 var extra = total % this.pageSize;
25095 var lastStart = extra ? (total - extra) : total-this.pageSize;
25096 ds.load({params:{start: lastStart, limit: this.pageSize}});
25099 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25105 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25106 * @param {Roo.data.Store} store The data store to unbind
25108 unbind : function(ds){
25109 ds.un("beforeload", this.beforeLoad, this);
25110 ds.un("load", this.onLoad, this);
25111 ds.un("loadexception", this.onLoadError, this);
25112 ds.un("remove", this.updateInfo, this);
25113 ds.un("add", this.updateInfo, this);
25114 this.ds = undefined;
25118 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25119 * @param {Roo.data.Store} store The data store to bind
25121 bind : function(ds){
25122 ds.on("beforeload", this.beforeLoad, this);
25123 ds.on("load", this.onLoad, this);
25124 ds.on("loadexception", this.onLoadError, this);
25125 ds.on("remove", this.updateInfo, this);
25126 ds.on("add", this.updateInfo, this);
25137 * @class Roo.bootstrap.MessageBar
25138 * @extends Roo.bootstrap.Component
25139 * Bootstrap MessageBar class
25140 * @cfg {String} html contents of the MessageBar
25141 * @cfg {String} weight (info | success | warning | danger) default info
25142 * @cfg {String} beforeClass insert the bar before the given class
25143 * @cfg {Boolean} closable (true | false) default false
25144 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25147 * Create a new Element
25148 * @param {Object} config The config object
25151 Roo.bootstrap.MessageBar = function(config){
25152 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25155 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25161 beforeClass: 'bootstrap-sticky-wrap',
25163 getAutoCreate : function(){
25167 cls: 'alert alert-dismissable alert-' + this.weight,
25172 html: this.html || ''
25178 cfg.cls += ' alert-messages-fixed';
25192 onRender : function(ct, position)
25194 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25197 var cfg = Roo.apply({}, this.getAutoCreate());
25201 cfg.cls += ' ' + this.cls;
25204 cfg.style = this.style;
25206 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25208 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25211 this.el.select('>button.close').on('click', this.hide, this);
25217 if (!this.rendered) {
25223 this.fireEvent('show', this);
25229 if (!this.rendered) {
25235 this.fireEvent('hide', this);
25238 update : function()
25240 // var e = this.el.dom.firstChild;
25242 // if(this.closable){
25243 // e = e.nextSibling;
25246 // e.data = this.html || '';
25248 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25264 * @class Roo.bootstrap.Graph
25265 * @extends Roo.bootstrap.Component
25266 * Bootstrap Graph class
25270 @cfg {String} graphtype bar | vbar | pie
25271 @cfg {number} g_x coodinator | centre x (pie)
25272 @cfg {number} g_y coodinator | centre y (pie)
25273 @cfg {number} g_r radius (pie)
25274 @cfg {number} g_height height of the chart (respected by all elements in the set)
25275 @cfg {number} g_width width of the chart (respected by all elements in the set)
25276 @cfg {Object} title The title of the chart
25279 -opts (object) options for the chart
25281 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25282 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25284 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.
25285 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25287 o stretch (boolean)
25289 -opts (object) options for the pie
25292 o startAngle (number)
25293 o endAngle (number)
25297 * Create a new Input
25298 * @param {Object} config The config object
25301 Roo.bootstrap.Graph = function(config){
25302 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25308 * The img click event for the img.
25309 * @param {Roo.EventObject} e
25315 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25326 //g_colors: this.colors,
25333 getAutoCreate : function(){
25344 onRender : function(ct,position){
25347 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25349 if (typeof(Raphael) == 'undefined') {
25350 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25354 this.raphael = Raphael(this.el.dom);
25356 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25357 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25358 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25359 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25361 r.text(160, 10, "Single Series Chart").attr(txtattr);
25362 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25363 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25364 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25366 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25367 r.barchart(330, 10, 300, 220, data1);
25368 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25369 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25372 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25373 // r.barchart(30, 30, 560, 250, xdata, {
25374 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25375 // axis : "0 0 1 1",
25376 // axisxlabels : xdata
25377 // //yvalues : cols,
25380 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25382 // this.load(null,xdata,{
25383 // axis : "0 0 1 1",
25384 // axisxlabels : xdata
25389 load : function(graphtype,xdata,opts)
25391 this.raphael.clear();
25393 graphtype = this.graphtype;
25398 var r = this.raphael,
25399 fin = function () {
25400 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25402 fout = function () {
25403 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25405 pfin = function() {
25406 this.sector.stop();
25407 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25410 this.label[0].stop();
25411 this.label[0].attr({ r: 7.5 });
25412 this.label[1].attr({ "font-weight": 800 });
25415 pfout = function() {
25416 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25419 this.label[0].animate({ r: 5 }, 500, "bounce");
25420 this.label[1].attr({ "font-weight": 400 });
25426 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25429 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25432 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25433 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25435 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25442 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25447 setTitle: function(o)
25452 initEvents: function() {
25455 this.el.on('click', this.onClick, this);
25459 onClick : function(e)
25461 Roo.log('img onclick');
25462 this.fireEvent('click', this, e);
25474 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25477 * @class Roo.bootstrap.dash.NumberBox
25478 * @extends Roo.bootstrap.Component
25479 * Bootstrap NumberBox class
25480 * @cfg {String} headline Box headline
25481 * @cfg {String} content Box content
25482 * @cfg {String} icon Box icon
25483 * @cfg {String} footer Footer text
25484 * @cfg {String} fhref Footer href
25487 * Create a new NumberBox
25488 * @param {Object} config The config object
25492 Roo.bootstrap.dash.NumberBox = function(config){
25493 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25497 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25506 getAutoCreate : function(){
25510 cls : 'small-box ',
25518 cls : 'roo-headline',
25519 html : this.headline
25523 cls : 'roo-content',
25524 html : this.content
25538 cls : 'ion ' + this.icon
25547 cls : 'small-box-footer',
25548 href : this.fhref || '#',
25552 cfg.cn.push(footer);
25559 onRender : function(ct,position){
25560 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25567 setHeadline: function (value)
25569 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25572 setFooter: function (value, href)
25574 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25577 this.el.select('a.small-box-footer',true).first().attr('href', href);
25582 setContent: function (value)
25584 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25587 initEvents: function()
25601 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25604 * @class Roo.bootstrap.dash.TabBox
25605 * @extends Roo.bootstrap.Component
25606 * Bootstrap TabBox class
25607 * @cfg {String} title Title of the TabBox
25608 * @cfg {String} icon Icon of the TabBox
25609 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25610 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25613 * Create a new TabBox
25614 * @param {Object} config The config object
25618 Roo.bootstrap.dash.TabBox = function(config){
25619 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25624 * When a pane is added
25625 * @param {Roo.bootstrap.dash.TabPane} pane
25629 * @event activatepane
25630 * When a pane is activated
25631 * @param {Roo.bootstrap.dash.TabPane} pane
25633 "activatepane" : true
25641 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25646 tabScrollable : false,
25648 getChildContainer : function()
25650 return this.el.select('.tab-content', true).first();
25653 getAutoCreate : function(){
25657 cls: 'pull-left header',
25665 cls: 'fa ' + this.icon
25671 cls: 'nav nav-tabs pull-right',
25677 if(this.tabScrollable){
25684 cls: 'nav nav-tabs pull-right',
25695 cls: 'nav-tabs-custom',
25700 cls: 'tab-content no-padding',
25708 initEvents : function()
25710 //Roo.log('add add pane handler');
25711 this.on('addpane', this.onAddPane, this);
25714 * Updates the box title
25715 * @param {String} html to set the title to.
25717 setTitle : function(value)
25719 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25721 onAddPane : function(pane)
25723 this.panes.push(pane);
25724 //Roo.log('addpane');
25726 // tabs are rendere left to right..
25727 if(!this.showtabs){
25731 var ctr = this.el.select('.nav-tabs', true).first();
25734 var existing = ctr.select('.nav-tab',true);
25735 var qty = existing.getCount();;
25738 var tab = ctr.createChild({
25740 cls : 'nav-tab' + (qty ? '' : ' active'),
25748 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25751 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25753 pane.el.addClass('active');
25758 onTabClick : function(ev,un,ob,pane)
25760 //Roo.log('tab - prev default');
25761 ev.preventDefault();
25764 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25765 pane.tab.addClass('active');
25766 //Roo.log(pane.title);
25767 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25768 // technically we should have a deactivate event.. but maybe add later.
25769 // and it should not de-activate the selected tab...
25770 this.fireEvent('activatepane', pane);
25771 pane.el.addClass('active');
25772 pane.fireEvent('activate');
25777 getActivePane : function()
25780 Roo.each(this.panes, function(p) {
25781 if(p.el.hasClass('active')){
25802 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25804 * @class Roo.bootstrap.TabPane
25805 * @extends Roo.bootstrap.Component
25806 * Bootstrap TabPane class
25807 * @cfg {Boolean} active (false | true) Default false
25808 * @cfg {String} title title of panel
25812 * Create a new TabPane
25813 * @param {Object} config The config object
25816 Roo.bootstrap.dash.TabPane = function(config){
25817 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25823 * When a pane is activated
25824 * @param {Roo.bootstrap.dash.TabPane} pane
25831 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25836 // the tabBox that this is attached to.
25839 getAutoCreate : function()
25847 cfg.cls += ' active';
25852 initEvents : function()
25854 //Roo.log('trigger add pane handler');
25855 this.parent().fireEvent('addpane', this)
25859 * Updates the tab title
25860 * @param {String} html to set the title to.
25862 setTitle: function(str)
25868 this.tab.select('a', true).first().dom.innerHTML = str;
25885 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25888 * @class Roo.bootstrap.menu.Menu
25889 * @extends Roo.bootstrap.Component
25890 * Bootstrap Menu class - container for Menu
25891 * @cfg {String} html Text of the menu
25892 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25893 * @cfg {String} icon Font awesome icon
25894 * @cfg {String} pos Menu align to (top | bottom) default bottom
25898 * Create a new Menu
25899 * @param {Object} config The config object
25903 Roo.bootstrap.menu.Menu = function(config){
25904 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
25908 * @event beforeshow
25909 * Fires before this menu is displayed
25910 * @param {Roo.bootstrap.menu.Menu} this
25914 * @event beforehide
25915 * Fires before this menu is hidden
25916 * @param {Roo.bootstrap.menu.Menu} this
25921 * Fires after this menu is displayed
25922 * @param {Roo.bootstrap.menu.Menu} this
25927 * Fires after this menu is hidden
25928 * @param {Roo.bootstrap.menu.Menu} this
25933 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
25934 * @param {Roo.bootstrap.menu.Menu} this
25935 * @param {Roo.EventObject} e
25942 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
25946 weight : 'default',
25951 getChildContainer : function() {
25952 if(this.isSubMenu){
25956 return this.el.select('ul.dropdown-menu', true).first();
25959 getAutoCreate : function()
25964 cls : 'roo-menu-text',
25972 cls : 'fa ' + this.icon
25983 cls : 'dropdown-button btn btn-' + this.weight,
25988 cls : 'dropdown-toggle btn btn-' + this.weight,
25998 cls : 'dropdown-menu'
26004 if(this.pos == 'top'){
26005 cfg.cls += ' dropup';
26008 if(this.isSubMenu){
26011 cls : 'dropdown-menu'
26018 onRender : function(ct, position)
26020 this.isSubMenu = ct.hasClass('dropdown-submenu');
26022 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26025 initEvents : function()
26027 if(this.isSubMenu){
26031 this.hidden = true;
26033 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26034 this.triggerEl.on('click', this.onTriggerPress, this);
26036 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26037 this.buttonEl.on('click', this.onClick, this);
26043 if(this.isSubMenu){
26047 return this.el.select('ul.dropdown-menu', true).first();
26050 onClick : function(e)
26052 this.fireEvent("click", this, e);
26055 onTriggerPress : function(e)
26057 if (this.isVisible()) {
26064 isVisible : function(){
26065 return !this.hidden;
26070 this.fireEvent("beforeshow", this);
26072 this.hidden = false;
26073 this.el.addClass('open');
26075 Roo.get(document).on("mouseup", this.onMouseUp, this);
26077 this.fireEvent("show", this);
26084 this.fireEvent("beforehide", this);
26086 this.hidden = true;
26087 this.el.removeClass('open');
26089 Roo.get(document).un("mouseup", this.onMouseUp);
26091 this.fireEvent("hide", this);
26094 onMouseUp : function()
26108 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26111 * @class Roo.bootstrap.menu.Item
26112 * @extends Roo.bootstrap.Component
26113 * Bootstrap MenuItem class
26114 * @cfg {Boolean} submenu (true | false) default false
26115 * @cfg {String} html text of the item
26116 * @cfg {String} href the link
26117 * @cfg {Boolean} disable (true | false) default false
26118 * @cfg {Boolean} preventDefault (true | false) default true
26119 * @cfg {String} icon Font awesome icon
26120 * @cfg {String} pos Submenu align to (left | right) default right
26124 * Create a new Item
26125 * @param {Object} config The config object
26129 Roo.bootstrap.menu.Item = function(config){
26130 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26134 * Fires when the mouse is hovering over this menu
26135 * @param {Roo.bootstrap.menu.Item} this
26136 * @param {Roo.EventObject} e
26141 * Fires when the mouse exits this menu
26142 * @param {Roo.bootstrap.menu.Item} this
26143 * @param {Roo.EventObject} e
26149 * The raw click event for the entire grid.
26150 * @param {Roo.EventObject} e
26156 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26161 preventDefault: true,
26166 getAutoCreate : function()
26171 cls : 'roo-menu-item-text',
26179 cls : 'fa ' + this.icon
26188 href : this.href || '#',
26195 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26199 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26201 if(this.pos == 'left'){
26202 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26209 initEvents : function()
26211 this.el.on('mouseover', this.onMouseOver, this);
26212 this.el.on('mouseout', this.onMouseOut, this);
26214 this.el.select('a', true).first().on('click', this.onClick, this);
26218 onClick : function(e)
26220 if(this.preventDefault){
26221 e.preventDefault();
26224 this.fireEvent("click", this, e);
26227 onMouseOver : function(e)
26229 if(this.submenu && this.pos == 'left'){
26230 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26233 this.fireEvent("mouseover", this, e);
26236 onMouseOut : function(e)
26238 this.fireEvent("mouseout", this, e);
26250 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26253 * @class Roo.bootstrap.menu.Separator
26254 * @extends Roo.bootstrap.Component
26255 * Bootstrap Separator class
26258 * Create a new Separator
26259 * @param {Object} config The config object
26263 Roo.bootstrap.menu.Separator = function(config){
26264 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26267 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26269 getAutoCreate : function(){
26290 * @class Roo.bootstrap.Tooltip
26291 * Bootstrap Tooltip class
26292 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26293 * to determine which dom element triggers the tooltip.
26295 * It needs to add support for additional attributes like tooltip-position
26298 * Create a new Toolti
26299 * @param {Object} config The config object
26302 Roo.bootstrap.Tooltip = function(config){
26303 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26305 this.alignment = Roo.bootstrap.Tooltip.alignment;
26307 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26308 this.alignment = config.alignment;
26313 Roo.apply(Roo.bootstrap.Tooltip, {
26315 * @function init initialize tooltip monitoring.
26319 currentTip : false,
26320 currentRegion : false,
26326 Roo.get(document).on('mouseover', this.enter ,this);
26327 Roo.get(document).on('mouseout', this.leave, this);
26330 this.currentTip = new Roo.bootstrap.Tooltip();
26333 enter : function(ev)
26335 var dom = ev.getTarget();
26337 //Roo.log(['enter',dom]);
26338 var el = Roo.fly(dom);
26339 if (this.currentEl) {
26341 //Roo.log(this.currentEl);
26342 //Roo.log(this.currentEl.contains(dom));
26343 if (this.currentEl == el) {
26346 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26352 if (this.currentTip.el) {
26353 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26357 if(!el || el.dom == document){
26363 // you can not look for children, as if el is the body.. then everythign is the child..
26364 if (!el.attr('tooltip')) { //
26365 if (!el.select("[tooltip]").elements.length) {
26368 // is the mouse over this child...?
26369 bindEl = el.select("[tooltip]").first();
26370 var xy = ev.getXY();
26371 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26372 //Roo.log("not in region.");
26375 //Roo.log("child element over..");
26378 this.currentEl = bindEl;
26379 this.currentTip.bind(bindEl);
26380 this.currentRegion = Roo.lib.Region.getRegion(dom);
26381 this.currentTip.enter();
26384 leave : function(ev)
26386 var dom = ev.getTarget();
26387 //Roo.log(['leave',dom]);
26388 if (!this.currentEl) {
26393 if (dom != this.currentEl.dom) {
26396 var xy = ev.getXY();
26397 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26400 // only activate leave if mouse cursor is outside... bounding box..
26405 if (this.currentTip) {
26406 this.currentTip.leave();
26408 //Roo.log('clear currentEl');
26409 this.currentEl = false;
26414 'left' : ['r-l', [-2,0], 'right'],
26415 'right' : ['l-r', [2,0], 'left'],
26416 'bottom' : ['t-b', [0,2], 'top'],
26417 'top' : [ 'b-t', [0,-2], 'bottom']
26423 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26428 delay : null, // can be { show : 300 , hide: 500}
26432 hoverState : null, //???
26434 placement : 'bottom',
26438 getAutoCreate : function(){
26445 cls : 'tooltip-arrow'
26448 cls : 'tooltip-inner'
26455 bind : function(el)
26461 enter : function () {
26463 if (this.timeout != null) {
26464 clearTimeout(this.timeout);
26467 this.hoverState = 'in';
26468 //Roo.log("enter - show");
26469 if (!this.delay || !this.delay.show) {
26474 this.timeout = setTimeout(function () {
26475 if (_t.hoverState == 'in') {
26478 }, this.delay.show);
26482 clearTimeout(this.timeout);
26484 this.hoverState = 'out';
26485 if (!this.delay || !this.delay.hide) {
26491 this.timeout = setTimeout(function () {
26492 //Roo.log("leave - timeout");
26494 if (_t.hoverState == 'out') {
26496 Roo.bootstrap.Tooltip.currentEl = false;
26501 show : function (msg)
26504 this.render(document.body);
26507 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26509 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26511 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26513 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26515 var placement = typeof this.placement == 'function' ?
26516 this.placement.call(this, this.el, on_el) :
26519 var autoToken = /\s?auto?\s?/i;
26520 var autoPlace = autoToken.test(placement);
26522 placement = placement.replace(autoToken, '') || 'top';
26526 //this.el.setXY([0,0]);
26528 //this.el.dom.style.display='block';
26530 //this.el.appendTo(on_el);
26532 var p = this.getPosition();
26533 var box = this.el.getBox();
26539 var align = this.alignment[placement];
26541 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26543 if(placement == 'top' || placement == 'bottom'){
26545 placement = 'right';
26548 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26549 placement = 'left';
26552 var scroll = Roo.select('body', true).first().getScroll();
26554 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26558 align = this.alignment[placement];
26561 this.el.alignTo(this.bindEl, align[0],align[1]);
26562 //var arrow = this.el.select('.arrow',true).first();
26563 //arrow.set(align[2],
26565 this.el.addClass(placement);
26567 this.el.addClass('in fade');
26569 this.hoverState = null;
26571 if (this.el.hasClass('fade')) {
26582 //this.el.setXY([0,0]);
26583 this.el.removeClass('in');
26599 * @class Roo.bootstrap.LocationPicker
26600 * @extends Roo.bootstrap.Component
26601 * Bootstrap LocationPicker class
26602 * @cfg {Number} latitude Position when init default 0
26603 * @cfg {Number} longitude Position when init default 0
26604 * @cfg {Number} zoom default 15
26605 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26606 * @cfg {Boolean} mapTypeControl default false
26607 * @cfg {Boolean} disableDoubleClickZoom default false
26608 * @cfg {Boolean} scrollwheel default true
26609 * @cfg {Boolean} streetViewControl default false
26610 * @cfg {Number} radius default 0
26611 * @cfg {String} locationName
26612 * @cfg {Boolean} draggable default true
26613 * @cfg {Boolean} enableAutocomplete default false
26614 * @cfg {Boolean} enableReverseGeocode default true
26615 * @cfg {String} markerTitle
26618 * Create a new LocationPicker
26619 * @param {Object} config The config object
26623 Roo.bootstrap.LocationPicker = function(config){
26625 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26630 * Fires when the picker initialized.
26631 * @param {Roo.bootstrap.LocationPicker} this
26632 * @param {Google Location} location
26636 * @event positionchanged
26637 * Fires when the picker position changed.
26638 * @param {Roo.bootstrap.LocationPicker} this
26639 * @param {Google Location} location
26641 positionchanged : true,
26644 * Fires when the map resize.
26645 * @param {Roo.bootstrap.LocationPicker} this
26650 * Fires when the map show.
26651 * @param {Roo.bootstrap.LocationPicker} this
26656 * Fires when the map hide.
26657 * @param {Roo.bootstrap.LocationPicker} this
26662 * Fires when click the map.
26663 * @param {Roo.bootstrap.LocationPicker} this
26664 * @param {Map event} e
26668 * @event mapRightClick
26669 * Fires when right click the map.
26670 * @param {Roo.bootstrap.LocationPicker} this
26671 * @param {Map event} e
26673 mapRightClick : true,
26675 * @event markerClick
26676 * Fires when click the marker.
26677 * @param {Roo.bootstrap.LocationPicker} this
26678 * @param {Map event} e
26680 markerClick : true,
26682 * @event markerRightClick
26683 * Fires when right click the marker.
26684 * @param {Roo.bootstrap.LocationPicker} this
26685 * @param {Map event} e
26687 markerRightClick : true,
26689 * @event OverlayViewDraw
26690 * Fires when OverlayView Draw
26691 * @param {Roo.bootstrap.LocationPicker} this
26693 OverlayViewDraw : true,
26695 * @event OverlayViewOnAdd
26696 * Fires when OverlayView Draw
26697 * @param {Roo.bootstrap.LocationPicker} this
26699 OverlayViewOnAdd : true,
26701 * @event OverlayViewOnRemove
26702 * Fires when OverlayView Draw
26703 * @param {Roo.bootstrap.LocationPicker} this
26705 OverlayViewOnRemove : true,
26707 * @event OverlayViewShow
26708 * Fires when OverlayView Draw
26709 * @param {Roo.bootstrap.LocationPicker} this
26710 * @param {Pixel} cpx
26712 OverlayViewShow : true,
26714 * @event OverlayViewHide
26715 * Fires when OverlayView Draw
26716 * @param {Roo.bootstrap.LocationPicker} this
26718 OverlayViewHide : true,
26720 * @event loadexception
26721 * Fires when load google lib failed.
26722 * @param {Roo.bootstrap.LocationPicker} this
26724 loadexception : true
26729 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26731 gMapContext: false,
26737 mapTypeControl: false,
26738 disableDoubleClickZoom: false,
26740 streetViewControl: false,
26744 enableAutocomplete: false,
26745 enableReverseGeocode: true,
26748 getAutoCreate: function()
26753 cls: 'roo-location-picker'
26759 initEvents: function(ct, position)
26761 if(!this.el.getWidth() || this.isApplied()){
26765 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26770 initial: function()
26772 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26773 this.fireEvent('loadexception', this);
26777 if(!this.mapTypeId){
26778 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26781 this.gMapContext = this.GMapContext();
26783 this.initOverlayView();
26785 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26789 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26790 _this.setPosition(_this.gMapContext.marker.position);
26793 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26794 _this.fireEvent('mapClick', this, event);
26798 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26799 _this.fireEvent('mapRightClick', this, event);
26803 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26804 _this.fireEvent('markerClick', this, event);
26808 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26809 _this.fireEvent('markerRightClick', this, event);
26813 this.setPosition(this.gMapContext.location);
26815 this.fireEvent('initial', this, this.gMapContext.location);
26818 initOverlayView: function()
26822 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26826 _this.fireEvent('OverlayViewDraw', _this);
26831 _this.fireEvent('OverlayViewOnAdd', _this);
26834 onRemove: function()
26836 _this.fireEvent('OverlayViewOnRemove', _this);
26839 show: function(cpx)
26841 _this.fireEvent('OverlayViewShow', _this, cpx);
26846 _this.fireEvent('OverlayViewHide', _this);
26852 fromLatLngToContainerPixel: function(event)
26854 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26857 isApplied: function()
26859 return this.getGmapContext() == false ? false : true;
26862 getGmapContext: function()
26864 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26867 GMapContext: function()
26869 var position = new google.maps.LatLng(this.latitude, this.longitude);
26871 var _map = new google.maps.Map(this.el.dom, {
26874 mapTypeId: this.mapTypeId,
26875 mapTypeControl: this.mapTypeControl,
26876 disableDoubleClickZoom: this.disableDoubleClickZoom,
26877 scrollwheel: this.scrollwheel,
26878 streetViewControl: this.streetViewControl,
26879 locationName: this.locationName,
26880 draggable: this.draggable,
26881 enableAutocomplete: this.enableAutocomplete,
26882 enableReverseGeocode: this.enableReverseGeocode
26885 var _marker = new google.maps.Marker({
26886 position: position,
26888 title: this.markerTitle,
26889 draggable: this.draggable
26896 location: position,
26897 radius: this.radius,
26898 locationName: this.locationName,
26899 addressComponents: {
26900 formatted_address: null,
26901 addressLine1: null,
26902 addressLine2: null,
26904 streetNumber: null,
26908 stateOrProvince: null
26911 domContainer: this.el.dom,
26912 geodecoder: new google.maps.Geocoder()
26916 drawCircle: function(center, radius, options)
26918 if (this.gMapContext.circle != null) {
26919 this.gMapContext.circle.setMap(null);
26923 options = Roo.apply({}, options, {
26924 strokeColor: "#0000FF",
26925 strokeOpacity: .35,
26927 fillColor: "#0000FF",
26931 options.map = this.gMapContext.map;
26932 options.radius = radius;
26933 options.center = center;
26934 this.gMapContext.circle = new google.maps.Circle(options);
26935 return this.gMapContext.circle;
26941 setPosition: function(location)
26943 this.gMapContext.location = location;
26944 this.gMapContext.marker.setPosition(location);
26945 this.gMapContext.map.panTo(location);
26946 this.drawCircle(location, this.gMapContext.radius, {});
26950 if (this.gMapContext.settings.enableReverseGeocode) {
26951 this.gMapContext.geodecoder.geocode({
26952 latLng: this.gMapContext.location
26953 }, function(results, status) {
26955 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
26956 _this.gMapContext.locationName = results[0].formatted_address;
26957 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
26959 _this.fireEvent('positionchanged', this, location);
26966 this.fireEvent('positionchanged', this, location);
26971 google.maps.event.trigger(this.gMapContext.map, "resize");
26973 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
26975 this.fireEvent('resize', this);
26978 setPositionByLatLng: function(latitude, longitude)
26980 this.setPosition(new google.maps.LatLng(latitude, longitude));
26983 getCurrentPosition: function()
26986 latitude: this.gMapContext.location.lat(),
26987 longitude: this.gMapContext.location.lng()
26991 getAddressName: function()
26993 return this.gMapContext.locationName;
26996 getAddressComponents: function()
26998 return this.gMapContext.addressComponents;
27001 address_component_from_google_geocode: function(address_components)
27005 for (var i = 0; i < address_components.length; i++) {
27006 var component = address_components[i];
27007 if (component.types.indexOf("postal_code") >= 0) {
27008 result.postalCode = component.short_name;
27009 } else if (component.types.indexOf("street_number") >= 0) {
27010 result.streetNumber = component.short_name;
27011 } else if (component.types.indexOf("route") >= 0) {
27012 result.streetName = component.short_name;
27013 } else if (component.types.indexOf("neighborhood") >= 0) {
27014 result.city = component.short_name;
27015 } else if (component.types.indexOf("locality") >= 0) {
27016 result.city = component.short_name;
27017 } else if (component.types.indexOf("sublocality") >= 0) {
27018 result.district = component.short_name;
27019 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27020 result.stateOrProvince = component.short_name;
27021 } else if (component.types.indexOf("country") >= 0) {
27022 result.country = component.short_name;
27026 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27027 result.addressLine2 = "";
27031 setZoomLevel: function(zoom)
27033 this.gMapContext.map.setZoom(zoom);
27046 this.fireEvent('show', this);
27057 this.fireEvent('hide', this);
27062 Roo.apply(Roo.bootstrap.LocationPicker, {
27064 OverlayView : function(map, options)
27066 options = options || {};
27080 * @class Roo.bootstrap.Alert
27081 * @extends Roo.bootstrap.Component
27082 * Bootstrap Alert class
27083 * @cfg {String} title The title of alert
27084 * @cfg {String} html The content of alert
27085 * @cfg {String} weight ( success | info | warning | danger )
27086 * @cfg {String} faicon font-awesomeicon
27089 * Create a new alert
27090 * @param {Object} config The config object
27094 Roo.bootstrap.Alert = function(config){
27095 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27099 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27106 getAutoCreate : function()
27115 cls : 'roo-alert-icon'
27120 cls : 'roo-alert-title',
27125 cls : 'roo-alert-text',
27132 cfg.cn[0].cls += ' fa ' + this.faicon;
27136 cfg.cls += ' alert-' + this.weight;
27142 initEvents: function()
27144 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27147 setTitle : function(str)
27149 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27152 setText : function(str)
27154 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27157 setWeight : function(weight)
27160 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27163 this.weight = weight;
27165 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27168 setIcon : function(icon)
27171 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27174 this.faicon = icon;
27176 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27197 * @class Roo.bootstrap.UploadCropbox
27198 * @extends Roo.bootstrap.Component
27199 * Bootstrap UploadCropbox class
27200 * @cfg {String} emptyText show when image has been loaded
27201 * @cfg {String} rotateNotify show when image too small to rotate
27202 * @cfg {Number} errorTimeout default 3000
27203 * @cfg {Number} minWidth default 300
27204 * @cfg {Number} minHeight default 300
27205 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27206 * @cfg {Boolean} isDocument (true|false) default false
27207 * @cfg {String} url action url
27208 * @cfg {String} paramName default 'imageUpload'
27209 * @cfg {String} method default POST
27210 * @cfg {Boolean} loadMask (true|false) default true
27211 * @cfg {Boolean} loadingText default 'Loading...'
27214 * Create a new UploadCropbox
27215 * @param {Object} config The config object
27218 Roo.bootstrap.UploadCropbox = function(config){
27219 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27223 * @event beforeselectfile
27224 * Fire before select file
27225 * @param {Roo.bootstrap.UploadCropbox} this
27227 "beforeselectfile" : true,
27230 * Fire after initEvent
27231 * @param {Roo.bootstrap.UploadCropbox} this
27236 * Fire after initEvent
27237 * @param {Roo.bootstrap.UploadCropbox} this
27238 * @param {String} data
27243 * Fire when preparing the file data
27244 * @param {Roo.bootstrap.UploadCropbox} this
27245 * @param {Object} file
27250 * Fire when get exception
27251 * @param {Roo.bootstrap.UploadCropbox} this
27252 * @param {XMLHttpRequest} xhr
27254 "exception" : true,
27256 * @event beforeloadcanvas
27257 * Fire before load the canvas
27258 * @param {Roo.bootstrap.UploadCropbox} this
27259 * @param {String} src
27261 "beforeloadcanvas" : true,
27264 * Fire when trash image
27265 * @param {Roo.bootstrap.UploadCropbox} this
27270 * Fire when download the image
27271 * @param {Roo.bootstrap.UploadCropbox} this
27275 * @event footerbuttonclick
27276 * Fire when footerbuttonclick
27277 * @param {Roo.bootstrap.UploadCropbox} this
27278 * @param {String} type
27280 "footerbuttonclick" : true,
27284 * @param {Roo.bootstrap.UploadCropbox} this
27289 * Fire when rotate the image
27290 * @param {Roo.bootstrap.UploadCropbox} this
27291 * @param {String} pos
27296 * Fire when inspect the file
27297 * @param {Roo.bootstrap.UploadCropbox} this
27298 * @param {Object} file
27303 * Fire when xhr upload the file
27304 * @param {Roo.bootstrap.UploadCropbox} this
27305 * @param {Object} data
27310 * Fire when arrange the file data
27311 * @param {Roo.bootstrap.UploadCropbox} this
27312 * @param {Object} formData
27317 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27320 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27322 emptyText : 'Click to upload image',
27323 rotateNotify : 'Image is too small to rotate',
27324 errorTimeout : 3000,
27338 cropType : 'image/jpeg',
27340 canvasLoaded : false,
27341 isDocument : false,
27343 paramName : 'imageUpload',
27345 loadingText : 'Loading...',
27348 getAutoCreate : function()
27352 cls : 'roo-upload-cropbox',
27356 cls : 'roo-upload-cropbox-selector',
27361 cls : 'roo-upload-cropbox-body',
27362 style : 'cursor:pointer',
27366 cls : 'roo-upload-cropbox-preview'
27370 cls : 'roo-upload-cropbox-thumb'
27374 cls : 'roo-upload-cropbox-empty-notify',
27375 html : this.emptyText
27379 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27380 html : this.rotateNotify
27386 cls : 'roo-upload-cropbox-footer',
27389 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27399 onRender : function(ct, position)
27401 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27403 if (this.buttons.length) {
27405 Roo.each(this.buttons, function(bb) {
27407 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27409 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27415 this.maskEl = this.el;
27419 initEvents : function()
27421 this.urlAPI = (window.createObjectURL && window) ||
27422 (window.URL && URL.revokeObjectURL && URL) ||
27423 (window.webkitURL && webkitURL);
27425 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27426 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27428 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27429 this.selectorEl.hide();
27431 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27432 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27434 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27435 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27436 this.thumbEl.hide();
27438 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27439 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27441 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27442 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27443 this.errorEl.hide();
27445 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27446 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27447 this.footerEl.hide();
27449 this.setThumbBoxSize();
27455 this.fireEvent('initial', this);
27462 window.addEventListener("resize", function() { _this.resize(); } );
27464 this.bodyEl.on('click', this.beforeSelectFile, this);
27467 this.bodyEl.on('touchstart', this.onTouchStart, this);
27468 this.bodyEl.on('touchmove', this.onTouchMove, this);
27469 this.bodyEl.on('touchend', this.onTouchEnd, this);
27473 this.bodyEl.on('mousedown', this.onMouseDown, this);
27474 this.bodyEl.on('mousemove', this.onMouseMove, this);
27475 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27476 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27477 Roo.get(document).on('mouseup', this.onMouseUp, this);
27480 this.selectorEl.on('change', this.onFileSelected, this);
27486 this.baseScale = 1;
27488 this.baseRotate = 1;
27489 this.dragable = false;
27490 this.pinching = false;
27493 this.cropData = false;
27494 this.notifyEl.dom.innerHTML = this.emptyText;
27496 this.selectorEl.dom.value = '';
27500 resize : function()
27502 if(this.fireEvent('resize', this) != false){
27503 this.setThumbBoxPosition();
27504 this.setCanvasPosition();
27508 onFooterButtonClick : function(e, el, o, type)
27511 case 'rotate-left' :
27512 this.onRotateLeft(e);
27514 case 'rotate-right' :
27515 this.onRotateRight(e);
27518 this.beforeSelectFile(e);
27533 this.fireEvent('footerbuttonclick', this, type);
27536 beforeSelectFile : function(e)
27538 e.preventDefault();
27540 if(this.fireEvent('beforeselectfile', this) != false){
27541 this.selectorEl.dom.click();
27545 onFileSelected : function(e)
27547 e.preventDefault();
27549 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27553 var file = this.selectorEl.dom.files[0];
27555 if(this.fireEvent('inspect', this, file) != false){
27556 this.prepare(file);
27561 trash : function(e)
27563 this.fireEvent('trash', this);
27566 download : function(e)
27568 this.fireEvent('download', this);
27571 loadCanvas : function(src)
27573 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27577 this.imageEl = document.createElement('img');
27581 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27583 this.imageEl.src = src;
27587 onLoadCanvas : function()
27589 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27590 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27592 this.bodyEl.un('click', this.beforeSelectFile, this);
27594 this.notifyEl.hide();
27595 this.thumbEl.show();
27596 this.footerEl.show();
27598 this.baseRotateLevel();
27600 if(this.isDocument){
27601 this.setThumbBoxSize();
27604 this.setThumbBoxPosition();
27606 this.baseScaleLevel();
27612 this.canvasLoaded = true;
27615 this.maskEl.unmask();
27620 setCanvasPosition : function()
27622 if(!this.canvasEl){
27626 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27627 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27629 this.previewEl.setLeft(pw);
27630 this.previewEl.setTop(ph);
27634 onMouseDown : function(e)
27638 this.dragable = true;
27639 this.pinching = false;
27641 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27642 this.dragable = false;
27646 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27647 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27651 onMouseMove : function(e)
27655 if(!this.canvasLoaded){
27659 if (!this.dragable){
27663 var minX = Math.ceil(this.thumbEl.getLeft(true));
27664 var minY = Math.ceil(this.thumbEl.getTop(true));
27666 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27667 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27669 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27670 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27672 x = x - this.mouseX;
27673 y = y - this.mouseY;
27675 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27676 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27678 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27679 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27681 this.previewEl.setLeft(bgX);
27682 this.previewEl.setTop(bgY);
27684 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27685 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27688 onMouseUp : function(e)
27692 this.dragable = false;
27695 onMouseWheel : function(e)
27699 this.startScale = this.scale;
27701 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27703 if(!this.zoomable()){
27704 this.scale = this.startScale;
27713 zoomable : function()
27715 var minScale = this.thumbEl.getWidth() / this.minWidth;
27717 if(this.minWidth < this.minHeight){
27718 minScale = this.thumbEl.getHeight() / this.minHeight;
27721 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27722 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27726 (this.rotate == 0 || this.rotate == 180) &&
27728 width > this.imageEl.OriginWidth ||
27729 height > this.imageEl.OriginHeight ||
27730 (width < this.minWidth && height < this.minHeight)
27738 (this.rotate == 90 || this.rotate == 270) &&
27740 width > this.imageEl.OriginWidth ||
27741 height > this.imageEl.OriginHeight ||
27742 (width < this.minHeight && height < this.minWidth)
27749 !this.isDocument &&
27750 (this.rotate == 0 || this.rotate == 180) &&
27752 width < this.minWidth ||
27753 width > this.imageEl.OriginWidth ||
27754 height < this.minHeight ||
27755 height > this.imageEl.OriginHeight
27762 !this.isDocument &&
27763 (this.rotate == 90 || this.rotate == 270) &&
27765 width < this.minHeight ||
27766 width > this.imageEl.OriginWidth ||
27767 height < this.minWidth ||
27768 height > this.imageEl.OriginHeight
27778 onRotateLeft : function(e)
27780 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27782 var minScale = this.thumbEl.getWidth() / this.minWidth;
27784 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27785 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27787 this.startScale = this.scale;
27789 while (this.getScaleLevel() < minScale){
27791 this.scale = this.scale + 1;
27793 if(!this.zoomable()){
27798 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27799 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27804 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27811 this.scale = this.startScale;
27813 this.onRotateFail();
27818 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27820 if(this.isDocument){
27821 this.setThumbBoxSize();
27822 this.setThumbBoxPosition();
27823 this.setCanvasPosition();
27828 this.fireEvent('rotate', this, 'left');
27832 onRotateRight : function(e)
27834 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27836 var minScale = this.thumbEl.getWidth() / this.minWidth;
27838 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27839 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27841 this.startScale = this.scale;
27843 while (this.getScaleLevel() < minScale){
27845 this.scale = this.scale + 1;
27847 if(!this.zoomable()){
27852 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27853 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27858 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27865 this.scale = this.startScale;
27867 this.onRotateFail();
27872 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27874 if(this.isDocument){
27875 this.setThumbBoxSize();
27876 this.setThumbBoxPosition();
27877 this.setCanvasPosition();
27882 this.fireEvent('rotate', this, 'right');
27885 onRotateFail : function()
27887 this.errorEl.show(true);
27891 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27896 this.previewEl.dom.innerHTML = '';
27898 var canvasEl = document.createElement("canvas");
27900 var contextEl = canvasEl.getContext("2d");
27902 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27903 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27904 var center = this.imageEl.OriginWidth / 2;
27906 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
27907 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27908 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27909 center = this.imageEl.OriginHeight / 2;
27912 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
27914 contextEl.translate(center, center);
27915 contextEl.rotate(this.rotate * Math.PI / 180);
27917 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
27919 this.canvasEl = document.createElement("canvas");
27921 this.contextEl = this.canvasEl.getContext("2d");
27923 switch (this.rotate) {
27926 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27927 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27929 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27934 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27935 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27937 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27938 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);
27942 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27947 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
27948 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
27950 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27951 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);
27955 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);
27960 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
27961 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
27963 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
27964 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
27968 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);
27975 this.previewEl.appendChild(this.canvasEl);
27977 this.setCanvasPosition();
27982 if(!this.canvasLoaded){
27986 var imageCanvas = document.createElement("canvas");
27988 var imageContext = imageCanvas.getContext("2d");
27990 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27991 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
27993 var center = imageCanvas.width / 2;
27995 imageContext.translate(center, center);
27997 imageContext.rotate(this.rotate * Math.PI / 180);
27999 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28001 var canvas = document.createElement("canvas");
28003 var context = canvas.getContext("2d");
28005 canvas.width = this.minWidth;
28006 canvas.height = this.minHeight;
28008 switch (this.rotate) {
28011 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28012 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28014 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28015 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28017 var targetWidth = this.minWidth - 2 * x;
28018 var targetHeight = this.minHeight - 2 * y;
28022 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28023 scale = targetWidth / width;
28026 if(x > 0 && y == 0){
28027 scale = targetHeight / height;
28030 if(x > 0 && y > 0){
28031 scale = targetWidth / width;
28033 if(width < height){
28034 scale = targetHeight / height;
28038 context.scale(scale, scale);
28040 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28041 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28043 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28044 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28046 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28051 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28052 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28054 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28055 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28057 var targetWidth = this.minWidth - 2 * x;
28058 var targetHeight = this.minHeight - 2 * y;
28062 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28063 scale = targetWidth / width;
28066 if(x > 0 && y == 0){
28067 scale = targetHeight / height;
28070 if(x > 0 && y > 0){
28071 scale = targetWidth / width;
28073 if(width < height){
28074 scale = targetHeight / height;
28078 context.scale(scale, scale);
28080 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28081 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28083 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28084 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28086 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28088 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28093 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28094 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28096 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28097 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28099 var targetWidth = this.minWidth - 2 * x;
28100 var targetHeight = this.minHeight - 2 * y;
28104 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28105 scale = targetWidth / width;
28108 if(x > 0 && y == 0){
28109 scale = targetHeight / height;
28112 if(x > 0 && y > 0){
28113 scale = targetWidth / width;
28115 if(width < height){
28116 scale = targetHeight / height;
28120 context.scale(scale, scale);
28122 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28123 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28125 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28126 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28128 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28129 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28131 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28136 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28137 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28139 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28140 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28142 var targetWidth = this.minWidth - 2 * x;
28143 var targetHeight = this.minHeight - 2 * y;
28147 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28148 scale = targetWidth / width;
28151 if(x > 0 && y == 0){
28152 scale = targetHeight / height;
28155 if(x > 0 && y > 0){
28156 scale = targetWidth / width;
28158 if(width < height){
28159 scale = targetHeight / height;
28163 context.scale(scale, scale);
28165 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28166 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28168 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28169 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28171 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28173 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28180 this.cropData = canvas.toDataURL(this.cropType);
28182 if(this.fireEvent('crop', this, this.cropData) !== false){
28183 this.process(this.file, this.cropData);
28190 setThumbBoxSize : function()
28194 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28195 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28196 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28198 this.minWidth = width;
28199 this.minHeight = height;
28201 if(this.rotate == 90 || this.rotate == 270){
28202 this.minWidth = height;
28203 this.minHeight = width;
28208 width = Math.ceil(this.minWidth * height / this.minHeight);
28210 if(this.minWidth > this.minHeight){
28212 height = Math.ceil(this.minHeight * width / this.minWidth);
28215 this.thumbEl.setStyle({
28216 width : width + 'px',
28217 height : height + 'px'
28224 setThumbBoxPosition : function()
28226 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28227 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28229 this.thumbEl.setLeft(x);
28230 this.thumbEl.setTop(y);
28234 baseRotateLevel : function()
28236 this.baseRotate = 1;
28239 typeof(this.exif) != 'undefined' &&
28240 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28241 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28243 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28246 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28250 baseScaleLevel : function()
28254 if(this.isDocument){
28256 if(this.baseRotate == 6 || this.baseRotate == 8){
28258 height = this.thumbEl.getHeight();
28259 this.baseScale = height / this.imageEl.OriginWidth;
28261 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28262 width = this.thumbEl.getWidth();
28263 this.baseScale = width / this.imageEl.OriginHeight;
28269 height = this.thumbEl.getHeight();
28270 this.baseScale = height / this.imageEl.OriginHeight;
28272 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28273 width = this.thumbEl.getWidth();
28274 this.baseScale = width / this.imageEl.OriginWidth;
28280 if(this.baseRotate == 6 || this.baseRotate == 8){
28282 width = this.thumbEl.getHeight();
28283 this.baseScale = width / this.imageEl.OriginHeight;
28285 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28286 height = this.thumbEl.getWidth();
28287 this.baseScale = height / this.imageEl.OriginHeight;
28290 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28291 height = this.thumbEl.getWidth();
28292 this.baseScale = height / this.imageEl.OriginHeight;
28294 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28295 width = this.thumbEl.getHeight();
28296 this.baseScale = width / this.imageEl.OriginWidth;
28303 width = this.thumbEl.getWidth();
28304 this.baseScale = width / this.imageEl.OriginWidth;
28306 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28307 height = this.thumbEl.getHeight();
28308 this.baseScale = height / this.imageEl.OriginHeight;
28311 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28313 height = this.thumbEl.getHeight();
28314 this.baseScale = height / this.imageEl.OriginHeight;
28316 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28317 width = this.thumbEl.getWidth();
28318 this.baseScale = width / this.imageEl.OriginWidth;
28326 getScaleLevel : function()
28328 return this.baseScale * Math.pow(1.1, this.scale);
28331 onTouchStart : function(e)
28333 if(!this.canvasLoaded){
28334 this.beforeSelectFile(e);
28338 var touches = e.browserEvent.touches;
28344 if(touches.length == 1){
28345 this.onMouseDown(e);
28349 if(touches.length != 2){
28355 for(var i = 0, finger; finger = touches[i]; i++){
28356 coords.push(finger.pageX, finger.pageY);
28359 var x = Math.pow(coords[0] - coords[2], 2);
28360 var y = Math.pow(coords[1] - coords[3], 2);
28362 this.startDistance = Math.sqrt(x + y);
28364 this.startScale = this.scale;
28366 this.pinching = true;
28367 this.dragable = false;
28371 onTouchMove : function(e)
28373 if(!this.pinching && !this.dragable){
28377 var touches = e.browserEvent.touches;
28384 this.onMouseMove(e);
28390 for(var i = 0, finger; finger = touches[i]; i++){
28391 coords.push(finger.pageX, finger.pageY);
28394 var x = Math.pow(coords[0] - coords[2], 2);
28395 var y = Math.pow(coords[1] - coords[3], 2);
28397 this.endDistance = Math.sqrt(x + y);
28399 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28401 if(!this.zoomable()){
28402 this.scale = this.startScale;
28410 onTouchEnd : function(e)
28412 this.pinching = false;
28413 this.dragable = false;
28417 process : function(file, crop)
28420 this.maskEl.mask(this.loadingText);
28423 this.xhr = new XMLHttpRequest();
28425 file.xhr = this.xhr;
28427 this.xhr.open(this.method, this.url, true);
28430 "Accept": "application/json",
28431 "Cache-Control": "no-cache",
28432 "X-Requested-With": "XMLHttpRequest"
28435 for (var headerName in headers) {
28436 var headerValue = headers[headerName];
28438 this.xhr.setRequestHeader(headerName, headerValue);
28444 this.xhr.onload = function()
28446 _this.xhrOnLoad(_this.xhr);
28449 this.xhr.onerror = function()
28451 _this.xhrOnError(_this.xhr);
28454 var formData = new FormData();
28456 formData.append('returnHTML', 'NO');
28459 formData.append('crop', crop);
28462 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28463 formData.append(this.paramName, file, file.name);
28466 if(typeof(file.filename) != 'undefined'){
28467 formData.append('filename', file.filename);
28470 if(typeof(file.mimetype) != 'undefined'){
28471 formData.append('mimetype', file.mimetype);
28474 if(this.fireEvent('arrange', this, formData) != false){
28475 this.xhr.send(formData);
28479 xhrOnLoad : function(xhr)
28482 this.maskEl.unmask();
28485 if (xhr.readyState !== 4) {
28486 this.fireEvent('exception', this, xhr);
28490 var response = Roo.decode(xhr.responseText);
28492 if(!response.success){
28493 this.fireEvent('exception', this, xhr);
28497 var response = Roo.decode(xhr.responseText);
28499 this.fireEvent('upload', this, response);
28503 xhrOnError : function()
28506 this.maskEl.unmask();
28509 Roo.log('xhr on error');
28511 var response = Roo.decode(xhr.responseText);
28517 prepare : function(file)
28520 this.maskEl.mask(this.loadingText);
28526 if(typeof(file) === 'string'){
28527 this.loadCanvas(file);
28531 if(!file || !this.urlAPI){
28536 this.cropType = file.type;
28540 if(this.fireEvent('prepare', this, this.file) != false){
28542 var reader = new FileReader();
28544 reader.onload = function (e) {
28545 if (e.target.error) {
28546 Roo.log(e.target.error);
28550 var buffer = e.target.result,
28551 dataView = new DataView(buffer),
28553 maxOffset = dataView.byteLength - 4,
28557 if (dataView.getUint16(0) === 0xffd8) {
28558 while (offset < maxOffset) {
28559 markerBytes = dataView.getUint16(offset);
28561 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28562 markerLength = dataView.getUint16(offset + 2) + 2;
28563 if (offset + markerLength > dataView.byteLength) {
28564 Roo.log('Invalid meta data: Invalid segment size.');
28568 if(markerBytes == 0xffe1){
28569 _this.parseExifData(
28576 offset += markerLength;
28586 var url = _this.urlAPI.createObjectURL(_this.file);
28588 _this.loadCanvas(url);
28593 reader.readAsArrayBuffer(this.file);
28599 parseExifData : function(dataView, offset, length)
28601 var tiffOffset = offset + 10,
28605 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28606 // No Exif data, might be XMP data instead
28610 // Check for the ASCII code for "Exif" (0x45786966):
28611 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28612 // No Exif data, might be XMP data instead
28615 if (tiffOffset + 8 > dataView.byteLength) {
28616 Roo.log('Invalid Exif data: Invalid segment size.');
28619 // Check for the two null bytes:
28620 if (dataView.getUint16(offset + 8) !== 0x0000) {
28621 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28624 // Check the byte alignment:
28625 switch (dataView.getUint16(tiffOffset)) {
28627 littleEndian = true;
28630 littleEndian = false;
28633 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28636 // Check for the TIFF tag marker (0x002A):
28637 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28638 Roo.log('Invalid Exif data: Missing TIFF marker.');
28641 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28642 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28644 this.parseExifTags(
28647 tiffOffset + dirOffset,
28652 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28657 if (dirOffset + 6 > dataView.byteLength) {
28658 Roo.log('Invalid Exif data: Invalid directory offset.');
28661 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28662 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28663 if (dirEndOffset + 4 > dataView.byteLength) {
28664 Roo.log('Invalid Exif data: Invalid directory size.');
28667 for (i = 0; i < tagsNumber; i += 1) {
28671 dirOffset + 2 + 12 * i, // tag offset
28675 // Return the offset to the next directory:
28676 return dataView.getUint32(dirEndOffset, littleEndian);
28679 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28681 var tag = dataView.getUint16(offset, littleEndian);
28683 this.exif[tag] = this.getExifValue(
28687 dataView.getUint16(offset + 2, littleEndian), // tag type
28688 dataView.getUint32(offset + 4, littleEndian), // tag length
28693 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28695 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28704 Roo.log('Invalid Exif data: Invalid tag type.');
28708 tagSize = tagType.size * length;
28709 // Determine if the value is contained in the dataOffset bytes,
28710 // or if the value at the dataOffset is a pointer to the actual data:
28711 dataOffset = tagSize > 4 ?
28712 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28713 if (dataOffset + tagSize > dataView.byteLength) {
28714 Roo.log('Invalid Exif data: Invalid data offset.');
28717 if (length === 1) {
28718 return tagType.getValue(dataView, dataOffset, littleEndian);
28721 for (i = 0; i < length; i += 1) {
28722 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28725 if (tagType.ascii) {
28727 // Concatenate the chars:
28728 for (i = 0; i < values.length; i += 1) {
28730 // Ignore the terminating NULL byte(s):
28731 if (c === '\u0000') {
28743 Roo.apply(Roo.bootstrap.UploadCropbox, {
28745 'Orientation': 0x0112
28749 1: 0, //'top-left',
28751 3: 180, //'bottom-right',
28752 // 4: 'bottom-left',
28754 6: 90, //'right-top',
28755 // 7: 'right-bottom',
28756 8: 270 //'left-bottom'
28760 // byte, 8-bit unsigned int:
28762 getValue: function (dataView, dataOffset) {
28763 return dataView.getUint8(dataOffset);
28767 // ascii, 8-bit byte:
28769 getValue: function (dataView, dataOffset) {
28770 return String.fromCharCode(dataView.getUint8(dataOffset));
28775 // short, 16 bit int:
28777 getValue: function (dataView, dataOffset, littleEndian) {
28778 return dataView.getUint16(dataOffset, littleEndian);
28782 // long, 32 bit int:
28784 getValue: function (dataView, dataOffset, littleEndian) {
28785 return dataView.getUint32(dataOffset, littleEndian);
28789 // rational = two long values, first is numerator, second is denominator:
28791 getValue: function (dataView, dataOffset, littleEndian) {
28792 return dataView.getUint32(dataOffset, littleEndian) /
28793 dataView.getUint32(dataOffset + 4, littleEndian);
28797 // slong, 32 bit signed int:
28799 getValue: function (dataView, dataOffset, littleEndian) {
28800 return dataView.getInt32(dataOffset, littleEndian);
28804 // srational, two slongs, first is numerator, second is denominator:
28806 getValue: function (dataView, dataOffset, littleEndian) {
28807 return dataView.getInt32(dataOffset, littleEndian) /
28808 dataView.getInt32(dataOffset + 4, littleEndian);
28818 cls : 'btn-group roo-upload-cropbox-rotate-left',
28819 action : 'rotate-left',
28823 cls : 'btn btn-default',
28824 html : '<i class="fa fa-undo"></i>'
28830 cls : 'btn-group roo-upload-cropbox-picture',
28831 action : 'picture',
28835 cls : 'btn btn-default',
28836 html : '<i class="fa fa-picture-o"></i>'
28842 cls : 'btn-group roo-upload-cropbox-rotate-right',
28843 action : 'rotate-right',
28847 cls : 'btn btn-default',
28848 html : '<i class="fa fa-repeat"></i>'
28856 cls : 'btn-group roo-upload-cropbox-rotate-left',
28857 action : 'rotate-left',
28861 cls : 'btn btn-default',
28862 html : '<i class="fa fa-undo"></i>'
28868 cls : 'btn-group roo-upload-cropbox-download',
28869 action : 'download',
28873 cls : 'btn btn-default',
28874 html : '<i class="fa fa-download"></i>'
28880 cls : 'btn-group roo-upload-cropbox-crop',
28885 cls : 'btn btn-default',
28886 html : '<i class="fa fa-crop"></i>'
28892 cls : 'btn-group roo-upload-cropbox-trash',
28897 cls : 'btn btn-default',
28898 html : '<i class="fa fa-trash"></i>'
28904 cls : 'btn-group roo-upload-cropbox-rotate-right',
28905 action : 'rotate-right',
28909 cls : 'btn btn-default',
28910 html : '<i class="fa fa-repeat"></i>'
28918 cls : 'btn-group roo-upload-cropbox-rotate-left',
28919 action : 'rotate-left',
28923 cls : 'btn btn-default',
28924 html : '<i class="fa fa-undo"></i>'
28930 cls : 'btn-group roo-upload-cropbox-rotate-right',
28931 action : 'rotate-right',
28935 cls : 'btn btn-default',
28936 html : '<i class="fa fa-repeat"></i>'
28949 * @class Roo.bootstrap.DocumentManager
28950 * @extends Roo.bootstrap.Component
28951 * Bootstrap DocumentManager class
28952 * @cfg {String} paramName default 'imageUpload'
28953 * @cfg {String} toolTipName default 'filename'
28954 * @cfg {String} method default POST
28955 * @cfg {String} url action url
28956 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
28957 * @cfg {Boolean} multiple multiple upload default true
28958 * @cfg {Number} thumbSize default 300
28959 * @cfg {String} fieldLabel
28960 * @cfg {Number} labelWidth default 4
28961 * @cfg {String} labelAlign (left|top) default left
28962 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
28963 * @cfg {Number} labellg set the width of label (1-12)
28964 * @cfg {Number} labelmd set the width of label (1-12)
28965 * @cfg {Number} labelsm set the width of label (1-12)
28966 * @cfg {Number} labelxs set the width of label (1-12)
28969 * Create a new DocumentManager
28970 * @param {Object} config The config object
28973 Roo.bootstrap.DocumentManager = function(config){
28974 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
28977 this.delegates = [];
28982 * Fire when initial the DocumentManager
28983 * @param {Roo.bootstrap.DocumentManager} this
28988 * inspect selected file
28989 * @param {Roo.bootstrap.DocumentManager} this
28990 * @param {File} file
28995 * Fire when xhr load exception
28996 * @param {Roo.bootstrap.DocumentManager} this
28997 * @param {XMLHttpRequest} xhr
28999 "exception" : true,
29001 * @event afterupload
29002 * Fire when xhr load exception
29003 * @param {Roo.bootstrap.DocumentManager} this
29004 * @param {XMLHttpRequest} xhr
29006 "afterupload" : true,
29009 * prepare the form data
29010 * @param {Roo.bootstrap.DocumentManager} this
29011 * @param {Object} formData
29016 * Fire when remove the file
29017 * @param {Roo.bootstrap.DocumentManager} this
29018 * @param {Object} file
29023 * Fire after refresh the file
29024 * @param {Roo.bootstrap.DocumentManager} this
29029 * Fire after click the image
29030 * @param {Roo.bootstrap.DocumentManager} this
29031 * @param {Object} file
29036 * Fire when upload a image and editable set to true
29037 * @param {Roo.bootstrap.DocumentManager} this
29038 * @param {Object} file
29042 * @event beforeselectfile
29043 * Fire before select file
29044 * @param {Roo.bootstrap.DocumentManager} this
29046 "beforeselectfile" : true,
29049 * Fire before process file
29050 * @param {Roo.bootstrap.DocumentManager} this
29051 * @param {Object} file
29055 * @event previewrendered
29056 * Fire when preview rendered
29057 * @param {Roo.bootstrap.DocumentManager} this
29058 * @param {Object} file
29060 "previewrendered" : true,
29063 "previewResize" : true
29068 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29077 paramName : 'imageUpload',
29078 toolTipName : 'filename',
29081 labelAlign : 'left',
29091 getAutoCreate : function()
29093 var managerWidget = {
29095 cls : 'roo-document-manager',
29099 cls : 'roo-document-manager-selector',
29104 cls : 'roo-document-manager-uploader',
29108 cls : 'roo-document-manager-upload-btn',
29109 html : '<i class="fa fa-plus"></i>'
29120 cls : 'column col-md-12',
29125 if(this.fieldLabel.length){
29130 cls : 'column col-md-12',
29131 html : this.fieldLabel
29135 cls : 'column col-md-12',
29140 if(this.labelAlign == 'left'){
29145 html : this.fieldLabel
29154 if(this.labelWidth > 12){
29155 content[0].style = "width: " + this.labelWidth + 'px';
29158 if(this.labelWidth < 13 && this.labelmd == 0){
29159 this.labelmd = this.labelWidth;
29162 if(this.labellg > 0){
29163 content[0].cls += ' col-lg-' + this.labellg;
29164 content[1].cls += ' col-lg-' + (12 - this.labellg);
29167 if(this.labelmd > 0){
29168 content[0].cls += ' col-md-' + this.labelmd;
29169 content[1].cls += ' col-md-' + (12 - this.labelmd);
29172 if(this.labelsm > 0){
29173 content[0].cls += ' col-sm-' + this.labelsm;
29174 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29177 if(this.labelxs > 0){
29178 content[0].cls += ' col-xs-' + this.labelxs;
29179 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29187 cls : 'row clearfix',
29195 initEvents : function()
29197 this.managerEl = this.el.select('.roo-document-manager', true).first();
29198 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29200 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29201 this.selectorEl.hide();
29204 this.selectorEl.attr('multiple', 'multiple');
29207 this.selectorEl.on('change', this.onFileSelected, this);
29209 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29210 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29212 this.uploader.on('click', this.onUploaderClick, this);
29214 this.renderProgressDialog();
29218 window.addEventListener("resize", function() { _this.refresh(); } );
29220 this.fireEvent('initial', this);
29223 renderProgressDialog : function()
29227 this.progressDialog = new Roo.bootstrap.Modal({
29228 cls : 'roo-document-manager-progress-dialog',
29229 allow_close : false,
29240 btnclick : function() {
29241 _this.uploadCancel();
29247 this.progressDialog.render(Roo.get(document.body));
29249 this.progress = new Roo.bootstrap.Progress({
29250 cls : 'roo-document-manager-progress',
29255 this.progress.render(this.progressDialog.getChildContainer());
29257 this.progressBar = new Roo.bootstrap.ProgressBar({
29258 cls : 'roo-document-manager-progress-bar',
29261 aria_valuemax : 12,
29265 this.progressBar.render(this.progress.getChildContainer());
29268 onUploaderClick : function(e)
29270 e.preventDefault();
29272 if(this.fireEvent('beforeselectfile', this) != false){
29273 this.selectorEl.dom.click();
29278 onFileSelected : function(e)
29280 e.preventDefault();
29282 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29286 Roo.each(this.selectorEl.dom.files, function(file){
29287 if(this.fireEvent('inspect', this, file) != false){
29288 this.files.push(file);
29298 this.selectorEl.dom.value = '';
29300 if(!this.files || !this.files.length){
29304 if(this.boxes > 0 && this.files.length > this.boxes){
29305 this.files = this.files.slice(0, this.boxes);
29308 this.uploader.show();
29310 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29311 this.uploader.hide();
29320 Roo.each(this.files, function(file){
29322 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29323 var f = this.renderPreview(file);
29328 if(file.type.indexOf('image') != -1){
29329 this.delegates.push(
29331 _this.process(file);
29332 }).createDelegate(this)
29340 _this.process(file);
29341 }).createDelegate(this)
29346 this.files = files;
29348 this.delegates = this.delegates.concat(docs);
29350 if(!this.delegates.length){
29355 this.progressBar.aria_valuemax = this.delegates.length;
29362 arrange : function()
29364 if(!this.delegates.length){
29365 this.progressDialog.hide();
29370 var delegate = this.delegates.shift();
29372 this.progressDialog.show();
29374 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29376 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29381 refresh : function()
29383 this.uploader.show();
29385 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29386 this.uploader.hide();
29389 Roo.isTouch ? this.closable(false) : this.closable(true);
29391 this.fireEvent('refresh', this);
29394 onRemove : function(e, el, o)
29396 e.preventDefault();
29398 this.fireEvent('remove', this, o);
29402 remove : function(o)
29406 Roo.each(this.files, function(file){
29407 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29416 this.files = files;
29423 Roo.each(this.files, function(file){
29428 file.target.remove();
29437 onClick : function(e, el, o)
29439 e.preventDefault();
29441 this.fireEvent('click', this, o);
29445 closable : function(closable)
29447 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29449 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29461 xhrOnLoad : function(xhr)
29463 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29467 if (xhr.readyState !== 4) {
29469 this.fireEvent('exception', this, xhr);
29473 var response = Roo.decode(xhr.responseText);
29475 if(!response.success){
29477 this.fireEvent('exception', this, xhr);
29481 var file = this.renderPreview(response.data);
29483 this.files.push(file);
29487 this.fireEvent('afterupload', this, xhr);
29491 xhrOnError : function(xhr)
29493 Roo.log('xhr on error');
29495 var response = Roo.decode(xhr.responseText);
29502 process : function(file)
29504 if(this.fireEvent('process', this, file) !== false){
29505 if(this.editable && file.type.indexOf('image') != -1){
29506 this.fireEvent('edit', this, file);
29510 this.uploadStart(file, false);
29517 uploadStart : function(file, crop)
29519 this.xhr = new XMLHttpRequest();
29521 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29526 file.xhr = this.xhr;
29528 this.managerEl.createChild({
29530 cls : 'roo-document-manager-loading',
29534 tooltip : file.name,
29535 cls : 'roo-document-manager-thumb',
29536 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29542 this.xhr.open(this.method, this.url, true);
29545 "Accept": "application/json",
29546 "Cache-Control": "no-cache",
29547 "X-Requested-With": "XMLHttpRequest"
29550 for (var headerName in headers) {
29551 var headerValue = headers[headerName];
29553 this.xhr.setRequestHeader(headerName, headerValue);
29559 this.xhr.onload = function()
29561 _this.xhrOnLoad(_this.xhr);
29564 this.xhr.onerror = function()
29566 _this.xhrOnError(_this.xhr);
29569 var formData = new FormData();
29571 formData.append('returnHTML', 'NO');
29574 formData.append('crop', crop);
29577 formData.append(this.paramName, file, file.name);
29584 if(this.fireEvent('prepare', this, formData, options) != false){
29586 if(options.manually){
29590 this.xhr.send(formData);
29594 this.uploadCancel();
29597 uploadCancel : function()
29603 this.delegates = [];
29605 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29612 renderPreview : function(file)
29614 if(typeof(file.target) != 'undefined' && file.target){
29618 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29620 var previewEl = this.managerEl.createChild({
29622 cls : 'roo-document-manager-preview',
29626 tooltip : file[this.toolTipName],
29627 cls : 'roo-document-manager-thumb',
29628 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29633 html : '<i class="fa fa-times-circle"></i>'
29638 var close = previewEl.select('button.close', true).first();
29640 close.on('click', this.onRemove, this, file);
29642 file.target = previewEl;
29644 var image = previewEl.select('img', true).first();
29648 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29650 image.on('click', this.onClick, this, file);
29652 this.fireEvent('previewrendered', this, file);
29658 onPreviewLoad : function(file, image)
29660 if(typeof(file.target) == 'undefined' || !file.target){
29664 var width = image.dom.naturalWidth || image.dom.width;
29665 var height = image.dom.naturalHeight || image.dom.height;
29667 if(!this.previewResize) {
29671 if(width > height){
29672 file.target.addClass('wide');
29676 file.target.addClass('tall');
29681 uploadFromSource : function(file, crop)
29683 this.xhr = new XMLHttpRequest();
29685 this.managerEl.createChild({
29687 cls : 'roo-document-manager-loading',
29691 tooltip : file.name,
29692 cls : 'roo-document-manager-thumb',
29693 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29699 this.xhr.open(this.method, this.url, true);
29702 "Accept": "application/json",
29703 "Cache-Control": "no-cache",
29704 "X-Requested-With": "XMLHttpRequest"
29707 for (var headerName in headers) {
29708 var headerValue = headers[headerName];
29710 this.xhr.setRequestHeader(headerName, headerValue);
29716 this.xhr.onload = function()
29718 _this.xhrOnLoad(_this.xhr);
29721 this.xhr.onerror = function()
29723 _this.xhrOnError(_this.xhr);
29726 var formData = new FormData();
29728 formData.append('returnHTML', 'NO');
29730 formData.append('crop', crop);
29732 if(typeof(file.filename) != 'undefined'){
29733 formData.append('filename', file.filename);
29736 if(typeof(file.mimetype) != 'undefined'){
29737 formData.append('mimetype', file.mimetype);
29742 if(this.fireEvent('prepare', this, formData) != false){
29743 this.xhr.send(formData);
29753 * @class Roo.bootstrap.DocumentViewer
29754 * @extends Roo.bootstrap.Component
29755 * Bootstrap DocumentViewer class
29756 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29757 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29760 * Create a new DocumentViewer
29761 * @param {Object} config The config object
29764 Roo.bootstrap.DocumentViewer = function(config){
29765 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29770 * Fire after initEvent
29771 * @param {Roo.bootstrap.DocumentViewer} this
29777 * @param {Roo.bootstrap.DocumentViewer} this
29782 * Fire after download button
29783 * @param {Roo.bootstrap.DocumentViewer} this
29788 * Fire after trash button
29789 * @param {Roo.bootstrap.DocumentViewer} this
29796 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29798 showDownload : true,
29802 getAutoCreate : function()
29806 cls : 'roo-document-viewer',
29810 cls : 'roo-document-viewer-body',
29814 cls : 'roo-document-viewer-thumb',
29818 cls : 'roo-document-viewer-image'
29826 cls : 'roo-document-viewer-footer',
29829 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29833 cls : 'btn-group roo-document-viewer-download',
29837 cls : 'btn btn-default',
29838 html : '<i class="fa fa-download"></i>'
29844 cls : 'btn-group roo-document-viewer-trash',
29848 cls : 'btn btn-default',
29849 html : '<i class="fa fa-trash"></i>'
29862 initEvents : function()
29864 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29865 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29867 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29868 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29870 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29871 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29873 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29874 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29876 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29877 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29879 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29880 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29882 this.bodyEl.on('click', this.onClick, this);
29883 this.downloadBtn.on('click', this.onDownload, this);
29884 this.trashBtn.on('click', this.onTrash, this);
29886 this.downloadBtn.hide();
29887 this.trashBtn.hide();
29889 if(this.showDownload){
29890 this.downloadBtn.show();
29893 if(this.showTrash){
29894 this.trashBtn.show();
29897 if(!this.showDownload && !this.showTrash) {
29898 this.footerEl.hide();
29903 initial : function()
29905 this.fireEvent('initial', this);
29909 onClick : function(e)
29911 e.preventDefault();
29913 this.fireEvent('click', this);
29916 onDownload : function(e)
29918 e.preventDefault();
29920 this.fireEvent('download', this);
29923 onTrash : function(e)
29925 e.preventDefault();
29927 this.fireEvent('trash', this);
29939 * @class Roo.bootstrap.NavProgressBar
29940 * @extends Roo.bootstrap.Component
29941 * Bootstrap NavProgressBar class
29944 * Create a new nav progress bar
29945 * @param {Object} config The config object
29948 Roo.bootstrap.NavProgressBar = function(config){
29949 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
29951 this.bullets = this.bullets || [];
29953 // Roo.bootstrap.NavProgressBar.register(this);
29957 * Fires when the active item changes
29958 * @param {Roo.bootstrap.NavProgressBar} this
29959 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
29960 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
29967 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
29972 getAutoCreate : function()
29974 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
29978 cls : 'roo-navigation-bar-group',
29982 cls : 'roo-navigation-top-bar'
29986 cls : 'roo-navigation-bullets-bar',
29990 cls : 'roo-navigation-bar'
29997 cls : 'roo-navigation-bottom-bar'
30007 initEvents: function()
30012 onRender : function(ct, position)
30014 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30016 if(this.bullets.length){
30017 Roo.each(this.bullets, function(b){
30026 addItem : function(cfg)
30028 var item = new Roo.bootstrap.NavProgressItem(cfg);
30030 item.parentId = this.id;
30031 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30034 var top = new Roo.bootstrap.Element({
30036 cls : 'roo-navigation-bar-text'
30039 var bottom = new Roo.bootstrap.Element({
30041 cls : 'roo-navigation-bar-text'
30044 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30045 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30047 var topText = new Roo.bootstrap.Element({
30049 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30052 var bottomText = new Roo.bootstrap.Element({
30054 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30057 topText.onRender(top.el, null);
30058 bottomText.onRender(bottom.el, null);
30061 item.bottomEl = bottom;
30064 this.barItems.push(item);
30069 getActive : function()
30071 var active = false;
30073 Roo.each(this.barItems, function(v){
30075 if (!v.isActive()) {
30087 setActiveItem : function(item)
30091 Roo.each(this.barItems, function(v){
30092 if (v.rid == item.rid) {
30096 if (v.isActive()) {
30097 v.setActive(false);
30102 item.setActive(true);
30104 this.fireEvent('changed', this, item, prev);
30107 getBarItem: function(rid)
30111 Roo.each(this.barItems, function(e) {
30112 if (e.rid != rid) {
30123 indexOfItem : function(item)
30127 Roo.each(this.barItems, function(v, i){
30129 if (v.rid != item.rid) {
30140 setActiveNext : function()
30142 var i = this.indexOfItem(this.getActive());
30144 if (i > this.barItems.length) {
30148 this.setActiveItem(this.barItems[i+1]);
30151 setActivePrev : function()
30153 var i = this.indexOfItem(this.getActive());
30159 this.setActiveItem(this.barItems[i-1]);
30162 format : function()
30164 if(!this.barItems.length){
30168 var width = 100 / this.barItems.length;
30170 Roo.each(this.barItems, function(i){
30171 i.el.setStyle('width', width + '%');
30172 i.topEl.el.setStyle('width', width + '%');
30173 i.bottomEl.el.setStyle('width', width + '%');
30182 * Nav Progress Item
30187 * @class Roo.bootstrap.NavProgressItem
30188 * @extends Roo.bootstrap.Component
30189 * Bootstrap NavProgressItem class
30190 * @cfg {String} rid the reference id
30191 * @cfg {Boolean} active (true|false) Is item active default false
30192 * @cfg {Boolean} disabled (true|false) Is item active default false
30193 * @cfg {String} html
30194 * @cfg {String} position (top|bottom) text position default bottom
30195 * @cfg {String} icon show icon instead of number
30198 * Create a new NavProgressItem
30199 * @param {Object} config The config object
30201 Roo.bootstrap.NavProgressItem = function(config){
30202 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30207 * The raw click event for the entire grid.
30208 * @param {Roo.bootstrap.NavProgressItem} this
30209 * @param {Roo.EventObject} e
30216 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30222 position : 'bottom',
30225 getAutoCreate : function()
30227 var iconCls = 'roo-navigation-bar-item-icon';
30229 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30233 cls: 'roo-navigation-bar-item',
30243 cfg.cls += ' active';
30246 cfg.cls += ' disabled';
30252 disable : function()
30254 this.setDisabled(true);
30257 enable : function()
30259 this.setDisabled(false);
30262 initEvents: function()
30264 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30266 this.iconEl.on('click', this.onClick, this);
30269 onClick : function(e)
30271 e.preventDefault();
30277 if(this.fireEvent('click', this, e) === false){
30281 this.parent().setActiveItem(this);
30284 isActive: function ()
30286 return this.active;
30289 setActive : function(state)
30291 if(this.active == state){
30295 this.active = state;
30298 this.el.addClass('active');
30302 this.el.removeClass('active');
30307 setDisabled : function(state)
30309 if(this.disabled == state){
30313 this.disabled = state;
30316 this.el.addClass('disabled');
30320 this.el.removeClass('disabled');
30323 tooltipEl : function()
30325 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30338 * @class Roo.bootstrap.FieldLabel
30339 * @extends Roo.bootstrap.Component
30340 * Bootstrap FieldLabel class
30341 * @cfg {String} html contents of the element
30342 * @cfg {String} tag tag of the element default label
30343 * @cfg {String} cls class of the element
30344 * @cfg {String} target label target
30345 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30346 * @cfg {String} invalidClass default "text-warning"
30347 * @cfg {String} validClass default "text-success"
30348 * @cfg {String} iconTooltip default "This field is required"
30349 * @cfg {String} indicatorpos (left|right) default left
30352 * Create a new FieldLabel
30353 * @param {Object} config The config object
30356 Roo.bootstrap.FieldLabel = function(config){
30357 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30362 * Fires after the field has been marked as invalid.
30363 * @param {Roo.form.FieldLabel} this
30364 * @param {String} msg The validation message
30369 * Fires after the field has been validated with no errors.
30370 * @param {Roo.form.FieldLabel} this
30376 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30383 invalidClass : 'has-warning',
30384 validClass : 'has-success',
30385 iconTooltip : 'This field is required',
30386 indicatorpos : 'left',
30388 getAutoCreate : function(){
30391 if (!this.allowBlank) {
30397 cls : 'roo-bootstrap-field-label ' + this.cls,
30402 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30403 tooltip : this.iconTooltip
30412 if(this.indicatorpos == 'right'){
30415 cls : 'roo-bootstrap-field-label ' + this.cls,
30424 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30425 tooltip : this.iconTooltip
30434 initEvents: function()
30436 Roo.bootstrap.Element.superclass.initEvents.call(this);
30438 this.indicator = this.indicatorEl();
30440 if(this.indicator){
30441 this.indicator.removeClass('visible');
30442 this.indicator.addClass('invisible');
30445 Roo.bootstrap.FieldLabel.register(this);
30448 indicatorEl : function()
30450 var indicator = this.el.select('i.roo-required-indicator',true).first();
30461 * Mark this field as valid
30463 markValid : function()
30465 if(this.indicator){
30466 this.indicator.removeClass('visible');
30467 this.indicator.addClass('invisible');
30470 this.el.removeClass(this.invalidClass);
30472 this.el.addClass(this.validClass);
30474 this.fireEvent('valid', this);
30478 * Mark this field as invalid
30479 * @param {String} msg The validation message
30481 markInvalid : function(msg)
30483 if(this.indicator){
30484 this.indicator.removeClass('invisible');
30485 this.indicator.addClass('visible');
30488 this.el.removeClass(this.validClass);
30490 this.el.addClass(this.invalidClass);
30492 this.fireEvent('invalid', this, msg);
30498 Roo.apply(Roo.bootstrap.FieldLabel, {
30503 * register a FieldLabel Group
30504 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30506 register : function(label)
30508 if(this.groups.hasOwnProperty(label.target)){
30512 this.groups[label.target] = label;
30516 * fetch a FieldLabel Group based on the target
30517 * @param {string} target
30518 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30520 get: function(target) {
30521 if (typeof(this.groups[target]) == 'undefined') {
30525 return this.groups[target] ;
30534 * page DateSplitField.
30540 * @class Roo.bootstrap.DateSplitField
30541 * @extends Roo.bootstrap.Component
30542 * Bootstrap DateSplitField class
30543 * @cfg {string} fieldLabel - the label associated
30544 * @cfg {Number} labelWidth set the width of label (0-12)
30545 * @cfg {String} labelAlign (top|left)
30546 * @cfg {Boolean} dayAllowBlank (true|false) default false
30547 * @cfg {Boolean} monthAllowBlank (true|false) default false
30548 * @cfg {Boolean} yearAllowBlank (true|false) default false
30549 * @cfg {string} dayPlaceholder
30550 * @cfg {string} monthPlaceholder
30551 * @cfg {string} yearPlaceholder
30552 * @cfg {string} dayFormat default 'd'
30553 * @cfg {string} monthFormat default 'm'
30554 * @cfg {string} yearFormat default 'Y'
30555 * @cfg {Number} labellg set the width of label (1-12)
30556 * @cfg {Number} labelmd set the width of label (1-12)
30557 * @cfg {Number} labelsm set the width of label (1-12)
30558 * @cfg {Number} labelxs set the width of label (1-12)
30562 * Create a new DateSplitField
30563 * @param {Object} config The config object
30566 Roo.bootstrap.DateSplitField = function(config){
30567 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30573 * getting the data of years
30574 * @param {Roo.bootstrap.DateSplitField} this
30575 * @param {Object} years
30580 * getting the data of days
30581 * @param {Roo.bootstrap.DateSplitField} this
30582 * @param {Object} days
30587 * Fires after the field has been marked as invalid.
30588 * @param {Roo.form.Field} this
30589 * @param {String} msg The validation message
30594 * Fires after the field has been validated with no errors.
30595 * @param {Roo.form.Field} this
30601 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30604 labelAlign : 'top',
30606 dayAllowBlank : false,
30607 monthAllowBlank : false,
30608 yearAllowBlank : false,
30609 dayPlaceholder : '',
30610 monthPlaceholder : '',
30611 yearPlaceholder : '',
30615 isFormField : true,
30621 getAutoCreate : function()
30625 cls : 'row roo-date-split-field-group',
30630 cls : 'form-hidden-field roo-date-split-field-group-value',
30636 var labelCls = 'col-md-12';
30637 var contentCls = 'col-md-4';
30639 if(this.fieldLabel){
30643 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30647 html : this.fieldLabel
30652 if(this.labelAlign == 'left'){
30654 if(this.labelWidth > 12){
30655 label.style = "width: " + this.labelWidth + 'px';
30658 if(this.labelWidth < 13 && this.labelmd == 0){
30659 this.labelmd = this.labelWidth;
30662 if(this.labellg > 0){
30663 labelCls = ' col-lg-' + this.labellg;
30664 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30667 if(this.labelmd > 0){
30668 labelCls = ' col-md-' + this.labelmd;
30669 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30672 if(this.labelsm > 0){
30673 labelCls = ' col-sm-' + this.labelsm;
30674 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30677 if(this.labelxs > 0){
30678 labelCls = ' col-xs-' + this.labelxs;
30679 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30683 label.cls += ' ' + labelCls;
30685 cfg.cn.push(label);
30688 Roo.each(['day', 'month', 'year'], function(t){
30691 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30698 inputEl: function ()
30700 return this.el.select('.roo-date-split-field-group-value', true).first();
30703 onRender : function(ct, position)
30707 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30709 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30711 this.dayField = new Roo.bootstrap.ComboBox({
30712 allowBlank : this.dayAllowBlank,
30713 alwaysQuery : true,
30714 displayField : 'value',
30717 forceSelection : true,
30719 placeholder : this.dayPlaceholder,
30720 selectOnFocus : true,
30721 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30722 triggerAction : 'all',
30724 valueField : 'value',
30725 store : new Roo.data.SimpleStore({
30726 data : (function() {
30728 _this.fireEvent('days', _this, days);
30731 fields : [ 'value' ]
30734 select : function (_self, record, index)
30736 _this.setValue(_this.getValue());
30741 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30743 this.monthField = new Roo.bootstrap.MonthField({
30744 after : '<i class=\"fa fa-calendar\"></i>',
30745 allowBlank : this.monthAllowBlank,
30746 placeholder : this.monthPlaceholder,
30749 render : function (_self)
30751 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30752 e.preventDefault();
30756 select : function (_self, oldvalue, newvalue)
30758 _this.setValue(_this.getValue());
30763 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30765 this.yearField = new Roo.bootstrap.ComboBox({
30766 allowBlank : this.yearAllowBlank,
30767 alwaysQuery : true,
30768 displayField : 'value',
30771 forceSelection : true,
30773 placeholder : this.yearPlaceholder,
30774 selectOnFocus : true,
30775 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30776 triggerAction : 'all',
30778 valueField : 'value',
30779 store : new Roo.data.SimpleStore({
30780 data : (function() {
30782 _this.fireEvent('years', _this, years);
30785 fields : [ 'value' ]
30788 select : function (_self, record, index)
30790 _this.setValue(_this.getValue());
30795 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30798 setValue : function(v, format)
30800 this.inputEl.dom.value = v;
30802 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30804 var d = Date.parseDate(v, f);
30811 this.setDay(d.format(this.dayFormat));
30812 this.setMonth(d.format(this.monthFormat));
30813 this.setYear(d.format(this.yearFormat));
30820 setDay : function(v)
30822 this.dayField.setValue(v);
30823 this.inputEl.dom.value = this.getValue();
30828 setMonth : function(v)
30830 this.monthField.setValue(v, true);
30831 this.inputEl.dom.value = this.getValue();
30836 setYear : function(v)
30838 this.yearField.setValue(v);
30839 this.inputEl.dom.value = this.getValue();
30844 getDay : function()
30846 return this.dayField.getValue();
30849 getMonth : function()
30851 return this.monthField.getValue();
30854 getYear : function()
30856 return this.yearField.getValue();
30859 getValue : function()
30861 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30863 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30873 this.inputEl.dom.value = '';
30878 validate : function()
30880 var d = this.dayField.validate();
30881 var m = this.monthField.validate();
30882 var y = this.yearField.validate();
30887 (!this.dayAllowBlank && !d) ||
30888 (!this.monthAllowBlank && !m) ||
30889 (!this.yearAllowBlank && !y)
30894 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
30903 this.markInvalid();
30908 markValid : function()
30911 var label = this.el.select('label', true).first();
30912 var icon = this.el.select('i.fa-star', true).first();
30918 this.fireEvent('valid', this);
30922 * Mark this field as invalid
30923 * @param {String} msg The validation message
30925 markInvalid : function(msg)
30928 var label = this.el.select('label', true).first();
30929 var icon = this.el.select('i.fa-star', true).first();
30931 if(label && !icon){
30932 this.el.select('.roo-date-split-field-label', true).createChild({
30934 cls : 'text-danger fa fa-lg fa-star',
30935 tooltip : 'This field is required',
30936 style : 'margin-right:5px;'
30940 this.fireEvent('invalid', this, msg);
30943 clearInvalid : function()
30945 var label = this.el.select('label', true).first();
30946 var icon = this.el.select('i.fa-star', true).first();
30952 this.fireEvent('valid', this);
30955 getName: function()
30965 * http://masonry.desandro.com
30967 * The idea is to render all the bricks based on vertical width...
30969 * The original code extends 'outlayer' - we might need to use that....
30975 * @class Roo.bootstrap.LayoutMasonry
30976 * @extends Roo.bootstrap.Component
30977 * Bootstrap Layout Masonry class
30980 * Create a new Element
30981 * @param {Object} config The config object
30984 Roo.bootstrap.LayoutMasonry = function(config){
30986 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
30990 Roo.bootstrap.LayoutMasonry.register(this);
30996 * Fire after layout the items
30997 * @param {Roo.bootstrap.LayoutMasonry} this
30998 * @param {Roo.EventObject} e
31005 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31008 * @cfg {Boolean} isLayoutInstant = no animation?
31010 isLayoutInstant : false, // needed?
31013 * @cfg {Number} boxWidth width of the columns
31018 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31023 * @cfg {Number} padWidth padding below box..
31028 * @cfg {Number} gutter gutter width..
31033 * @cfg {Number} maxCols maximum number of columns
31039 * @cfg {Boolean} isAutoInitial defalut true
31041 isAutoInitial : true,
31046 * @cfg {Boolean} isHorizontal defalut false
31048 isHorizontal : false,
31050 currentSize : null,
31056 bricks: null, //CompositeElement
31060 _isLayoutInited : false,
31062 // isAlternative : false, // only use for vertical layout...
31065 * @cfg {Number} alternativePadWidth padding below box..
31067 alternativePadWidth : 50,
31069 selectedBrick : [],
31071 getAutoCreate : function(){
31073 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31077 cls: 'blog-masonary-wrapper ' + this.cls,
31079 cls : 'mas-boxes masonary'
31086 getChildContainer: function( )
31088 if (this.boxesEl) {
31089 return this.boxesEl;
31092 this.boxesEl = this.el.select('.mas-boxes').first();
31094 return this.boxesEl;
31098 initEvents : function()
31102 if(this.isAutoInitial){
31103 Roo.log('hook children rendered');
31104 this.on('childrenrendered', function() {
31105 Roo.log('children rendered');
31111 initial : function()
31113 this.selectedBrick = [];
31115 this.currentSize = this.el.getBox(true);
31117 Roo.EventManager.onWindowResize(this.resize, this);
31119 if(!this.isAutoInitial){
31127 //this.layout.defer(500,this);
31131 resize : function()
31133 var cs = this.el.getBox(true);
31136 this.currentSize.width == cs.width &&
31137 this.currentSize.x == cs.x &&
31138 this.currentSize.height == cs.height &&
31139 this.currentSize.y == cs.y
31141 Roo.log("no change in with or X or Y");
31145 this.currentSize = cs;
31151 layout : function()
31153 this._resetLayout();
31155 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31157 this.layoutItems( isInstant );
31159 this._isLayoutInited = true;
31161 this.fireEvent('layout', this);
31165 _resetLayout : function()
31167 if(this.isHorizontal){
31168 this.horizontalMeasureColumns();
31172 this.verticalMeasureColumns();
31176 verticalMeasureColumns : function()
31178 this.getContainerWidth();
31180 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31181 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31185 var boxWidth = this.boxWidth + this.padWidth;
31187 if(this.containerWidth < this.boxWidth){
31188 boxWidth = this.containerWidth
31191 var containerWidth = this.containerWidth;
31193 var cols = Math.floor(containerWidth / boxWidth);
31195 this.cols = Math.max( cols, 1 );
31197 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31199 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31201 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31203 this.colWidth = boxWidth + avail - this.padWidth;
31205 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31206 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31209 horizontalMeasureColumns : function()
31211 this.getContainerWidth();
31213 var boxWidth = this.boxWidth;
31215 if(this.containerWidth < boxWidth){
31216 boxWidth = this.containerWidth;
31219 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31221 this.el.setHeight(boxWidth);
31225 getContainerWidth : function()
31227 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31230 layoutItems : function( isInstant )
31232 Roo.log(this.bricks);
31234 var items = Roo.apply([], this.bricks);
31236 if(this.isHorizontal){
31237 this._horizontalLayoutItems( items , isInstant );
31241 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31242 // this._verticalAlternativeLayoutItems( items , isInstant );
31246 this._verticalLayoutItems( items , isInstant );
31250 _verticalLayoutItems : function ( items , isInstant)
31252 if ( !items || !items.length ) {
31257 ['xs', 'xs', 'xs', 'tall'],
31258 ['xs', 'xs', 'tall'],
31259 ['xs', 'xs', 'sm'],
31260 ['xs', 'xs', 'xs'],
31266 ['sm', 'xs', 'xs'],
31270 ['tall', 'xs', 'xs', 'xs'],
31271 ['tall', 'xs', 'xs'],
31283 Roo.each(items, function(item, k){
31285 switch (item.size) {
31286 // these layouts take up a full box,
31297 boxes.push([item]);
31320 var filterPattern = function(box, length)
31328 var pattern = box.slice(0, length);
31332 Roo.each(pattern, function(i){
31333 format.push(i.size);
31336 Roo.each(standard, function(s){
31338 if(String(s) != String(format)){
31347 if(!match && length == 1){
31352 filterPattern(box, length - 1);
31356 queue.push(pattern);
31358 box = box.slice(length, box.length);
31360 filterPattern(box, 4);
31366 Roo.each(boxes, function(box, k){
31372 if(box.length == 1){
31377 filterPattern(box, 4);
31381 this._processVerticalLayoutQueue( queue, isInstant );
31385 // _verticalAlternativeLayoutItems : function( items , isInstant )
31387 // if ( !items || !items.length ) {
31391 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31395 _horizontalLayoutItems : function ( items , isInstant)
31397 if ( !items || !items.length || items.length < 3) {
31403 var eItems = items.slice(0, 3);
31405 items = items.slice(3, items.length);
31408 ['xs', 'xs', 'xs', 'wide'],
31409 ['xs', 'xs', 'wide'],
31410 ['xs', 'xs', 'sm'],
31411 ['xs', 'xs', 'xs'],
31417 ['sm', 'xs', 'xs'],
31421 ['wide', 'xs', 'xs', 'xs'],
31422 ['wide', 'xs', 'xs'],
31435 Roo.each(items, function(item, k){
31437 switch (item.size) {
31448 boxes.push([item]);
31472 var filterPattern = function(box, length)
31480 var pattern = box.slice(0, length);
31484 Roo.each(pattern, function(i){
31485 format.push(i.size);
31488 Roo.each(standard, function(s){
31490 if(String(s) != String(format)){
31499 if(!match && length == 1){
31504 filterPattern(box, length - 1);
31508 queue.push(pattern);
31510 box = box.slice(length, box.length);
31512 filterPattern(box, 4);
31518 Roo.each(boxes, function(box, k){
31524 if(box.length == 1){
31529 filterPattern(box, 4);
31536 var pos = this.el.getBox(true);
31540 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31542 var hit_end = false;
31544 Roo.each(queue, function(box){
31548 Roo.each(box, function(b){
31550 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31560 Roo.each(box, function(b){
31562 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31565 mx = Math.max(mx, b.x);
31569 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31573 Roo.each(box, function(b){
31575 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31589 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31592 /** Sets position of item in DOM
31593 * @param {Element} item
31594 * @param {Number} x - horizontal position
31595 * @param {Number} y - vertical position
31596 * @param {Boolean} isInstant - disables transitions
31598 _processVerticalLayoutQueue : function( queue, isInstant )
31600 var pos = this.el.getBox(true);
31605 for (var i = 0; i < this.cols; i++){
31609 Roo.each(queue, function(box, k){
31611 var col = k % this.cols;
31613 Roo.each(box, function(b,kk){
31615 b.el.position('absolute');
31617 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31618 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31620 if(b.size == 'md-left' || b.size == 'md-right'){
31621 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31622 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31625 b.el.setWidth(width);
31626 b.el.setHeight(height);
31628 b.el.select('iframe',true).setSize(width,height);
31632 for (var i = 0; i < this.cols; i++){
31634 if(maxY[i] < maxY[col]){
31639 col = Math.min(col, i);
31643 x = pos.x + col * (this.colWidth + this.padWidth);
31647 var positions = [];
31649 switch (box.length){
31651 positions = this.getVerticalOneBoxColPositions(x, y, box);
31654 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31657 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31660 positions = this.getVerticalFourBoxColPositions(x, y, box);
31666 Roo.each(box, function(b,kk){
31668 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31670 var sz = b.el.getSize();
31672 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31680 for (var i = 0; i < this.cols; i++){
31681 mY = Math.max(mY, maxY[i]);
31684 this.el.setHeight(mY - pos.y);
31688 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31690 // var pos = this.el.getBox(true);
31693 // var maxX = pos.right;
31695 // var maxHeight = 0;
31697 // Roo.each(items, function(item, k){
31701 // item.el.position('absolute');
31703 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31705 // item.el.setWidth(width);
31707 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31709 // item.el.setHeight(height);
31712 // item.el.setXY([x, y], isInstant ? false : true);
31714 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31717 // y = y + height + this.alternativePadWidth;
31719 // maxHeight = maxHeight + height + this.alternativePadWidth;
31723 // this.el.setHeight(maxHeight);
31727 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31729 var pos = this.el.getBox(true);
31734 var maxX = pos.right;
31736 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31738 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31740 Roo.each(queue, function(box, k){
31742 Roo.each(box, function(b, kk){
31744 b.el.position('absolute');
31746 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31747 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31749 if(b.size == 'md-left' || b.size == 'md-right'){
31750 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31751 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31754 b.el.setWidth(width);
31755 b.el.setHeight(height);
31763 var positions = [];
31765 switch (box.length){
31767 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31770 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31773 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31776 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31782 Roo.each(box, function(b,kk){
31784 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31786 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31794 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31796 Roo.each(eItems, function(b,k){
31798 b.size = (k == 0) ? 'sm' : 'xs';
31799 b.x = (k == 0) ? 2 : 1;
31800 b.y = (k == 0) ? 2 : 1;
31802 b.el.position('absolute');
31804 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31806 b.el.setWidth(width);
31808 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31810 b.el.setHeight(height);
31814 var positions = [];
31817 x : maxX - this.unitWidth * 2 - this.gutter,
31822 x : maxX - this.unitWidth,
31823 y : minY + (this.unitWidth + this.gutter) * 2
31827 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31831 Roo.each(eItems, function(b,k){
31833 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31839 getVerticalOneBoxColPositions : function(x, y, box)
31843 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31845 if(box[0].size == 'md-left'){
31849 if(box[0].size == 'md-right'){
31854 x : x + (this.unitWidth + this.gutter) * rand,
31861 getVerticalTwoBoxColPositions : function(x, y, box)
31865 if(box[0].size == 'xs'){
31869 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31873 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31887 x : x + (this.unitWidth + this.gutter) * 2,
31888 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
31895 getVerticalThreeBoxColPositions : function(x, y, box)
31899 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
31907 x : x + (this.unitWidth + this.gutter) * 1,
31912 x : x + (this.unitWidth + this.gutter) * 2,
31920 if(box[0].size == 'xs' && box[1].size == 'xs'){
31929 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
31933 x : x + (this.unitWidth + this.gutter) * 1,
31947 x : x + (this.unitWidth + this.gutter) * 2,
31952 x : x + (this.unitWidth + this.gutter) * 2,
31953 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
31960 getVerticalFourBoxColPositions : function(x, y, box)
31964 if(box[0].size == 'xs'){
31973 y : y + (this.unitHeight + this.gutter) * 1
31978 y : y + (this.unitHeight + this.gutter) * 2
31982 x : x + (this.unitWidth + this.gutter) * 1,
31996 x : x + (this.unitWidth + this.gutter) * 2,
32001 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32002 y : y + (this.unitHeight + this.gutter) * 1
32006 x : x + (this.unitWidth + this.gutter) * 2,
32007 y : y + (this.unitWidth + this.gutter) * 2
32014 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32018 if(box[0].size == 'md-left'){
32020 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32027 if(box[0].size == 'md-right'){
32029 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32030 y : minY + (this.unitWidth + this.gutter) * 1
32036 var rand = Math.floor(Math.random() * (4 - box[0].y));
32039 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32040 y : minY + (this.unitWidth + this.gutter) * rand
32047 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32051 if(box[0].size == 'xs'){
32054 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32059 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32060 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32068 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32073 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32074 y : minY + (this.unitWidth + this.gutter) * 2
32081 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32085 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32088 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32093 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32094 y : minY + (this.unitWidth + this.gutter) * 1
32098 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32099 y : minY + (this.unitWidth + this.gutter) * 2
32106 if(box[0].size == 'xs' && box[1].size == 'xs'){
32109 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32114 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32119 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32120 y : minY + (this.unitWidth + this.gutter) * 1
32128 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32133 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32134 y : minY + (this.unitWidth + this.gutter) * 2
32138 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32139 y : minY + (this.unitWidth + this.gutter) * 2
32146 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32150 if(box[0].size == 'xs'){
32153 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32158 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32163 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),
32168 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32169 y : minY + (this.unitWidth + this.gutter) * 1
32177 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32182 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32183 y : minY + (this.unitWidth + this.gutter) * 2
32187 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32188 y : minY + (this.unitWidth + this.gutter) * 2
32192 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),
32193 y : minY + (this.unitWidth + this.gutter) * 2
32201 * remove a Masonry Brick
32202 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32204 removeBrick : function(brick_id)
32210 for (var i = 0; i<this.bricks.length; i++) {
32211 if (this.bricks[i].id == brick_id) {
32212 this.bricks.splice(i,1);
32213 this.el.dom.removeChild(Roo.get(brick_id).dom);
32220 * adds a Masonry Brick
32221 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32223 addBrick : function(cfg)
32225 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32226 //this.register(cn);
32227 cn.parentId = this.id;
32228 cn.render(this.el);
32233 * register a Masonry Brick
32234 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32237 register : function(brick)
32239 this.bricks.push(brick);
32240 brick.masonryId = this.id;
32244 * clear all the Masonry Brick
32246 clearAll : function()
32249 //this.getChildContainer().dom.innerHTML = "";
32250 this.el.dom.innerHTML = '';
32253 getSelected : function()
32255 if (!this.selectedBrick) {
32259 return this.selectedBrick;
32263 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32267 * register a Masonry Layout
32268 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32271 register : function(layout)
32273 this.groups[layout.id] = layout;
32276 * fetch a Masonry Layout based on the masonry layout ID
32277 * @param {string} the masonry layout to add
32278 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32281 get: function(layout_id) {
32282 if (typeof(this.groups[layout_id]) == 'undefined') {
32285 return this.groups[layout_id] ;
32297 * http://masonry.desandro.com
32299 * The idea is to render all the bricks based on vertical width...
32301 * The original code extends 'outlayer' - we might need to use that....
32307 * @class Roo.bootstrap.LayoutMasonryAuto
32308 * @extends Roo.bootstrap.Component
32309 * Bootstrap Layout Masonry class
32312 * Create a new Element
32313 * @param {Object} config The config object
32316 Roo.bootstrap.LayoutMasonryAuto = function(config){
32317 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32320 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32323 * @cfg {Boolean} isFitWidth - resize the width..
32325 isFitWidth : false, // options..
32327 * @cfg {Boolean} isOriginLeft = left align?
32329 isOriginLeft : true,
32331 * @cfg {Boolean} isOriginTop = top align?
32333 isOriginTop : false,
32335 * @cfg {Boolean} isLayoutInstant = no animation?
32337 isLayoutInstant : false, // needed?
32339 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32341 isResizingContainer : true,
32343 * @cfg {Number} columnWidth width of the columns
32349 * @cfg {Number} maxCols maximum number of columns
32354 * @cfg {Number} padHeight padding below box..
32360 * @cfg {Boolean} isAutoInitial defalut true
32363 isAutoInitial : true,
32369 initialColumnWidth : 0,
32370 currentSize : null,
32372 colYs : null, // array.
32379 bricks: null, //CompositeElement
32380 cols : 0, // array?
32381 // element : null, // wrapped now this.el
32382 _isLayoutInited : null,
32385 getAutoCreate : function(){
32389 cls: 'blog-masonary-wrapper ' + this.cls,
32391 cls : 'mas-boxes masonary'
32398 getChildContainer: function( )
32400 if (this.boxesEl) {
32401 return this.boxesEl;
32404 this.boxesEl = this.el.select('.mas-boxes').first();
32406 return this.boxesEl;
32410 initEvents : function()
32414 if(this.isAutoInitial){
32415 Roo.log('hook children rendered');
32416 this.on('childrenrendered', function() {
32417 Roo.log('children rendered');
32424 initial : function()
32426 this.reloadItems();
32428 this.currentSize = this.el.getBox(true);
32430 /// was window resize... - let's see if this works..
32431 Roo.EventManager.onWindowResize(this.resize, this);
32433 if(!this.isAutoInitial){
32438 this.layout.defer(500,this);
32441 reloadItems: function()
32443 this.bricks = this.el.select('.masonry-brick', true);
32445 this.bricks.each(function(b) {
32446 //Roo.log(b.getSize());
32447 if (!b.attr('originalwidth')) {
32448 b.attr('originalwidth', b.getSize().width);
32453 Roo.log(this.bricks.elements.length);
32456 resize : function()
32459 var cs = this.el.getBox(true);
32461 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32462 Roo.log("no change in with or X");
32465 this.currentSize = cs;
32469 layout : function()
32472 this._resetLayout();
32473 //this._manageStamps();
32475 // don't animate first layout
32476 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32477 this.layoutItems( isInstant );
32479 // flag for initalized
32480 this._isLayoutInited = true;
32483 layoutItems : function( isInstant )
32485 //var items = this._getItemsForLayout( this.items );
32486 // original code supports filtering layout items.. we just ignore it..
32488 this._layoutItems( this.bricks , isInstant );
32490 this._postLayout();
32492 _layoutItems : function ( items , isInstant)
32494 //this.fireEvent( 'layout', this, items );
32497 if ( !items || !items.elements.length ) {
32498 // no items, emit event with empty array
32503 items.each(function(item) {
32504 Roo.log("layout item");
32506 // get x/y object from method
32507 var position = this._getItemLayoutPosition( item );
32509 position.item = item;
32510 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32511 queue.push( position );
32514 this._processLayoutQueue( queue );
32516 /** Sets position of item in DOM
32517 * @param {Element} item
32518 * @param {Number} x - horizontal position
32519 * @param {Number} y - vertical position
32520 * @param {Boolean} isInstant - disables transitions
32522 _processLayoutQueue : function( queue )
32524 for ( var i=0, len = queue.length; i < len; i++ ) {
32525 var obj = queue[i];
32526 obj.item.position('absolute');
32527 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32533 * Any logic you want to do after each layout,
32534 * i.e. size the container
32536 _postLayout : function()
32538 this.resizeContainer();
32541 resizeContainer : function()
32543 if ( !this.isResizingContainer ) {
32546 var size = this._getContainerSize();
32548 this.el.setSize(size.width,size.height);
32549 this.boxesEl.setSize(size.width,size.height);
32555 _resetLayout : function()
32557 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32558 this.colWidth = this.el.getWidth();
32559 //this.gutter = this.el.getWidth();
32561 this.measureColumns();
32567 this.colYs.push( 0 );
32573 measureColumns : function()
32575 this.getContainerWidth();
32576 // if columnWidth is 0, default to outerWidth of first item
32577 if ( !this.columnWidth ) {
32578 var firstItem = this.bricks.first();
32579 Roo.log(firstItem);
32580 this.columnWidth = this.containerWidth;
32581 if (firstItem && firstItem.attr('originalwidth') ) {
32582 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32584 // columnWidth fall back to item of first element
32585 Roo.log("set column width?");
32586 this.initialColumnWidth = this.columnWidth ;
32588 // if first elem has no width, default to size of container
32593 if (this.initialColumnWidth) {
32594 this.columnWidth = this.initialColumnWidth;
32599 // column width is fixed at the top - however if container width get's smaller we should
32602 // this bit calcs how man columns..
32604 var columnWidth = this.columnWidth += this.gutter;
32606 // calculate columns
32607 var containerWidth = this.containerWidth + this.gutter;
32609 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32610 // fix rounding errors, typically with gutters
32611 var excess = columnWidth - containerWidth % columnWidth;
32614 // if overshoot is less than a pixel, round up, otherwise floor it
32615 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32616 cols = Math[ mathMethod ]( cols );
32617 this.cols = Math.max( cols, 1 );
32618 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32620 // padding positioning..
32621 var totalColWidth = this.cols * this.columnWidth;
32622 var padavail = this.containerWidth - totalColWidth;
32623 // so for 2 columns - we need 3 'pads'
32625 var padNeeded = (1+this.cols) * this.padWidth;
32627 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32629 this.columnWidth += padExtra
32630 //this.padWidth = Math.floor(padavail / ( this.cols));
32632 // adjust colum width so that padding is fixed??
32634 // we have 3 columns ... total = width * 3
32635 // we have X left over... that should be used by
32637 //if (this.expandC) {
32645 getContainerWidth : function()
32647 /* // container is parent if fit width
32648 var container = this.isFitWidth ? this.element.parentNode : this.element;
32649 // check that this.size and size are there
32650 // IE8 triggers resize on body size change, so they might not be
32652 var size = getSize( container ); //FIXME
32653 this.containerWidth = size && size.innerWidth; //FIXME
32656 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32660 _getItemLayoutPosition : function( item ) // what is item?
32662 // we resize the item to our columnWidth..
32664 item.setWidth(this.columnWidth);
32665 item.autoBoxAdjust = false;
32667 var sz = item.getSize();
32669 // how many columns does this brick span
32670 var remainder = this.containerWidth % this.columnWidth;
32672 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32673 // round if off by 1 pixel, otherwise use ceil
32674 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32675 colSpan = Math.min( colSpan, this.cols );
32677 // normally this should be '1' as we dont' currently allow multi width columns..
32679 var colGroup = this._getColGroup( colSpan );
32680 // get the minimum Y value from the columns
32681 var minimumY = Math.min.apply( Math, colGroup );
32682 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32684 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32686 // position the brick
32688 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32689 y: this.currentSize.y + minimumY + this.padHeight
32693 // apply setHeight to necessary columns
32694 var setHeight = minimumY + sz.height + this.padHeight;
32695 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32697 var setSpan = this.cols + 1 - colGroup.length;
32698 for ( var i = 0; i < setSpan; i++ ) {
32699 this.colYs[ shortColIndex + i ] = setHeight ;
32706 * @param {Number} colSpan - number of columns the element spans
32707 * @returns {Array} colGroup
32709 _getColGroup : function( colSpan )
32711 if ( colSpan < 2 ) {
32712 // if brick spans only one column, use all the column Ys
32717 // how many different places could this brick fit horizontally
32718 var groupCount = this.cols + 1 - colSpan;
32719 // for each group potential horizontal position
32720 for ( var i = 0; i < groupCount; i++ ) {
32721 // make an array of colY values for that one group
32722 var groupColYs = this.colYs.slice( i, i + colSpan );
32723 // and get the max value of the array
32724 colGroup[i] = Math.max.apply( Math, groupColYs );
32729 _manageStamp : function( stamp )
32731 var stampSize = stamp.getSize();
32732 var offset = stamp.getBox();
32733 // get the columns that this stamp affects
32734 var firstX = this.isOriginLeft ? offset.x : offset.right;
32735 var lastX = firstX + stampSize.width;
32736 var firstCol = Math.floor( firstX / this.columnWidth );
32737 firstCol = Math.max( 0, firstCol );
32739 var lastCol = Math.floor( lastX / this.columnWidth );
32740 // lastCol should not go over if multiple of columnWidth #425
32741 lastCol -= lastX % this.columnWidth ? 0 : 1;
32742 lastCol = Math.min( this.cols - 1, lastCol );
32744 // set colYs to bottom of the stamp
32745 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32748 for ( var i = firstCol; i <= lastCol; i++ ) {
32749 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32754 _getContainerSize : function()
32756 this.maxY = Math.max.apply( Math, this.colYs );
32761 if ( this.isFitWidth ) {
32762 size.width = this._getContainerFitWidth();
32768 _getContainerFitWidth : function()
32770 var unusedCols = 0;
32771 // count unused columns
32774 if ( this.colYs[i] !== 0 ) {
32779 // fit container to columns that have been used
32780 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32783 needsResizeLayout : function()
32785 var previousWidth = this.containerWidth;
32786 this.getContainerWidth();
32787 return previousWidth !== this.containerWidth;
32802 * @class Roo.bootstrap.MasonryBrick
32803 * @extends Roo.bootstrap.Component
32804 * Bootstrap MasonryBrick class
32807 * Create a new MasonryBrick
32808 * @param {Object} config The config object
32811 Roo.bootstrap.MasonryBrick = function(config){
32813 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32815 Roo.bootstrap.MasonryBrick.register(this);
32821 * When a MasonryBrick is clcik
32822 * @param {Roo.bootstrap.MasonryBrick} this
32823 * @param {Roo.EventObject} e
32829 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32832 * @cfg {String} title
32836 * @cfg {String} html
32840 * @cfg {String} bgimage
32844 * @cfg {String} videourl
32848 * @cfg {String} cls
32852 * @cfg {String} href
32856 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32861 * @cfg {String} placetitle (center|bottom)
32866 * @cfg {Boolean} isFitContainer defalut true
32868 isFitContainer : true,
32871 * @cfg {Boolean} preventDefault defalut false
32873 preventDefault : false,
32876 * @cfg {Boolean} inverse defalut false
32878 maskInverse : false,
32880 getAutoCreate : function()
32882 if(!this.isFitContainer){
32883 return this.getSplitAutoCreate();
32886 var cls = 'masonry-brick masonry-brick-full';
32888 if(this.href.length){
32889 cls += ' masonry-brick-link';
32892 if(this.bgimage.length){
32893 cls += ' masonry-brick-image';
32896 if(this.maskInverse){
32897 cls += ' mask-inverse';
32900 if(!this.html.length && !this.maskInverse && !this.videourl.length){
32901 cls += ' enable-mask';
32905 cls += ' masonry-' + this.size + '-brick';
32908 if(this.placetitle.length){
32910 switch (this.placetitle) {
32912 cls += ' masonry-center-title';
32915 cls += ' masonry-bottom-title';
32922 if(!this.html.length && !this.bgimage.length){
32923 cls += ' masonry-center-title';
32926 if(!this.html.length && this.bgimage.length){
32927 cls += ' masonry-bottom-title';
32932 cls += ' ' + this.cls;
32936 tag: (this.href.length) ? 'a' : 'div',
32941 cls: 'masonry-brick-mask'
32945 cls: 'masonry-brick-paragraph',
32951 if(this.href.length){
32952 cfg.href = this.href;
32955 var cn = cfg.cn[1].cn;
32957 if(this.title.length){
32960 cls: 'masonry-brick-title',
32965 if(this.html.length){
32968 cls: 'masonry-brick-text',
32973 if (!this.title.length && !this.html.length) {
32974 cfg.cn[1].cls += ' hide';
32977 if(this.bgimage.length){
32980 cls: 'masonry-brick-image-view',
32985 if(this.videourl.length){
32986 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
32987 // youtube support only?
32990 cls: 'masonry-brick-image-view',
32993 allowfullscreen : true
33001 getSplitAutoCreate : function()
33003 var cls = 'masonry-brick masonry-brick-split';
33005 if(this.href.length){
33006 cls += ' masonry-brick-link';
33009 if(this.bgimage.length){
33010 cls += ' masonry-brick-image';
33014 cls += ' masonry-' + this.size + '-brick';
33017 switch (this.placetitle) {
33019 cls += ' masonry-center-title';
33022 cls += ' masonry-bottom-title';
33025 if(!this.bgimage.length){
33026 cls += ' masonry-center-title';
33029 if(this.bgimage.length){
33030 cls += ' masonry-bottom-title';
33036 cls += ' ' + this.cls;
33040 tag: (this.href.length) ? 'a' : 'div',
33045 cls: 'masonry-brick-split-head',
33049 cls: 'masonry-brick-paragraph',
33056 cls: 'masonry-brick-split-body',
33062 if(this.href.length){
33063 cfg.href = this.href;
33066 if(this.title.length){
33067 cfg.cn[0].cn[0].cn.push({
33069 cls: 'masonry-brick-title',
33074 if(this.html.length){
33075 cfg.cn[1].cn.push({
33077 cls: 'masonry-brick-text',
33082 if(this.bgimage.length){
33083 cfg.cn[0].cn.push({
33085 cls: 'masonry-brick-image-view',
33090 if(this.videourl.length){
33091 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33092 // youtube support only?
33093 cfg.cn[0].cn.cn.push({
33095 cls: 'masonry-brick-image-view',
33098 allowfullscreen : true
33105 initEvents: function()
33107 switch (this.size) {
33140 this.el.on('touchstart', this.onTouchStart, this);
33141 this.el.on('touchmove', this.onTouchMove, this);
33142 this.el.on('touchend', this.onTouchEnd, this);
33143 this.el.on('contextmenu', this.onContextMenu, this);
33145 this.el.on('mouseenter' ,this.enter, this);
33146 this.el.on('mouseleave', this.leave, this);
33147 this.el.on('click', this.onClick, this);
33150 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33151 this.parent().bricks.push(this);
33156 onClick: function(e, el)
33158 var time = this.endTimer - this.startTimer;
33159 // Roo.log(e.preventDefault());
33162 e.preventDefault();
33167 if(!this.preventDefault){
33171 e.preventDefault();
33173 if (this.activeClass != '') {
33174 this.selectBrick();
33177 this.fireEvent('click', this, e);
33180 enter: function(e, el)
33182 e.preventDefault();
33184 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33188 if(this.bgimage.length && this.html.length){
33189 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33193 leave: function(e, el)
33195 e.preventDefault();
33197 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33201 if(this.bgimage.length && this.html.length){
33202 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33206 onTouchStart: function(e, el)
33208 // e.preventDefault();
33210 this.touchmoved = false;
33212 if(!this.isFitContainer){
33216 if(!this.bgimage.length || !this.html.length){
33220 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33222 this.timer = new Date().getTime();
33226 onTouchMove: function(e, el)
33228 this.touchmoved = true;
33231 onContextMenu : function(e,el)
33233 e.preventDefault();
33234 e.stopPropagation();
33238 onTouchEnd: function(e, el)
33240 // e.preventDefault();
33242 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33249 if(!this.bgimage.length || !this.html.length){
33251 if(this.href.length){
33252 window.location.href = this.href;
33258 if(!this.isFitContainer){
33262 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33264 window.location.href = this.href;
33267 //selection on single brick only
33268 selectBrick : function() {
33270 if (!this.parentId) {
33274 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33275 var index = m.selectedBrick.indexOf(this.id);
33278 m.selectedBrick.splice(index,1);
33279 this.el.removeClass(this.activeClass);
33283 for(var i = 0; i < m.selectedBrick.length; i++) {
33284 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33285 b.el.removeClass(b.activeClass);
33288 m.selectedBrick = [];
33290 m.selectedBrick.push(this.id);
33291 this.el.addClass(this.activeClass);
33295 isSelected : function(){
33296 return this.el.hasClass(this.activeClass);
33301 Roo.apply(Roo.bootstrap.MasonryBrick, {
33304 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33306 * register a Masonry Brick
33307 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33310 register : function(brick)
33312 //this.groups[brick.id] = brick;
33313 this.groups.add(brick.id, brick);
33316 * fetch a masonry brick based on the masonry brick ID
33317 * @param {string} the masonry brick to add
33318 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33321 get: function(brick_id)
33323 // if (typeof(this.groups[brick_id]) == 'undefined') {
33326 // return this.groups[brick_id] ;
33328 if(this.groups.key(brick_id)) {
33329 return this.groups.key(brick_id);
33347 * @class Roo.bootstrap.Brick
33348 * @extends Roo.bootstrap.Component
33349 * Bootstrap Brick class
33352 * Create a new Brick
33353 * @param {Object} config The config object
33356 Roo.bootstrap.Brick = function(config){
33357 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33363 * When a Brick is click
33364 * @param {Roo.bootstrap.Brick} this
33365 * @param {Roo.EventObject} e
33371 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33374 * @cfg {String} title
33378 * @cfg {String} html
33382 * @cfg {String} bgimage
33386 * @cfg {String} cls
33390 * @cfg {String} href
33394 * @cfg {String} video
33398 * @cfg {Boolean} square
33402 getAutoCreate : function()
33404 var cls = 'roo-brick';
33406 if(this.href.length){
33407 cls += ' roo-brick-link';
33410 if(this.bgimage.length){
33411 cls += ' roo-brick-image';
33414 if(!this.html.length && !this.bgimage.length){
33415 cls += ' roo-brick-center-title';
33418 if(!this.html.length && this.bgimage.length){
33419 cls += ' roo-brick-bottom-title';
33423 cls += ' ' + this.cls;
33427 tag: (this.href.length) ? 'a' : 'div',
33432 cls: 'roo-brick-paragraph',
33438 if(this.href.length){
33439 cfg.href = this.href;
33442 var cn = cfg.cn[0].cn;
33444 if(this.title.length){
33447 cls: 'roo-brick-title',
33452 if(this.html.length){
33455 cls: 'roo-brick-text',
33462 if(this.bgimage.length){
33465 cls: 'roo-brick-image-view',
33473 initEvents: function()
33475 if(this.title.length || this.html.length){
33476 this.el.on('mouseenter' ,this.enter, this);
33477 this.el.on('mouseleave', this.leave, this);
33480 Roo.EventManager.onWindowResize(this.resize, this);
33482 if(this.bgimage.length){
33483 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33484 this.imageEl.on('load', this.onImageLoad, this);
33491 onImageLoad : function()
33496 resize : function()
33498 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33500 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33502 if(this.bgimage.length){
33503 var image = this.el.select('.roo-brick-image-view', true).first();
33505 image.setWidth(paragraph.getWidth());
33508 image.setHeight(paragraph.getWidth());
33511 this.el.setHeight(image.getHeight());
33512 paragraph.setHeight(image.getHeight());
33518 enter: function(e, el)
33520 e.preventDefault();
33522 if(this.bgimage.length){
33523 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33524 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33528 leave: function(e, el)
33530 e.preventDefault();
33532 if(this.bgimage.length){
33533 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33534 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33549 * @class Roo.bootstrap.NumberField
33550 * @extends Roo.bootstrap.Input
33551 * Bootstrap NumberField class
33557 * Create a new NumberField
33558 * @param {Object} config The config object
33561 Roo.bootstrap.NumberField = function(config){
33562 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33565 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33568 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33570 allowDecimals : true,
33572 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33574 decimalSeparator : ".",
33576 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33578 decimalPrecision : 2,
33580 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33582 allowNegative : true,
33585 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33589 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33591 minValue : Number.NEGATIVE_INFINITY,
33593 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33595 maxValue : Number.MAX_VALUE,
33597 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33599 minText : "The minimum value for this field is {0}",
33601 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33603 maxText : "The maximum value for this field is {0}",
33605 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33606 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33608 nanText : "{0} is not a valid number",
33610 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33612 thousandsDelimiter : false,
33614 * @cfg {String} valueAlign alignment of value
33616 valueAlign : "left",
33618 getAutoCreate : function()
33620 var hiddenInput = {
33624 cls: 'hidden-number-input'
33628 hiddenInput.name = this.name;
33633 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33635 this.name = hiddenInput.name;
33637 if(cfg.cn.length > 0) {
33638 cfg.cn.push(hiddenInput);
33645 initEvents : function()
33647 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33649 var allowed = "0123456789";
33651 if(this.allowDecimals){
33652 allowed += this.decimalSeparator;
33655 if(this.allowNegative){
33659 if(this.thousandsDelimiter) {
33663 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33665 var keyPress = function(e){
33667 var k = e.getKey();
33669 var c = e.getCharCode();
33672 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33673 allowed.indexOf(String.fromCharCode(c)) === -1
33679 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33683 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33688 this.el.on("keypress", keyPress, this);
33691 validateValue : function(value)
33694 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33698 var num = this.parseValue(value);
33701 this.markInvalid(String.format(this.nanText, value));
33705 if(num < this.minValue){
33706 this.markInvalid(String.format(this.minText, this.minValue));
33710 if(num > this.maxValue){
33711 this.markInvalid(String.format(this.maxText, this.maxValue));
33718 getValue : function()
33720 var v = this.hiddenEl().getValue();
33722 return this.fixPrecision(this.parseValue(v));
33725 parseValue : function(value)
33727 if(this.thousandsDelimiter) {
33729 r = new RegExp(",", "g");
33730 value = value.replace(r, "");
33733 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33734 return isNaN(value) ? '' : value;
33737 fixPrecision : function(value)
33739 if(this.thousandsDelimiter) {
33741 r = new RegExp(",", "g");
33742 value = value.replace(r, "");
33745 var nan = isNaN(value);
33747 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33748 return nan ? '' : value;
33750 return parseFloat(value).toFixed(this.decimalPrecision);
33753 setValue : function(v)
33755 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33761 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33763 this.inputEl().dom.value = (v == '') ? '' :
33764 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33766 if(!this.allowZero && v === '0') {
33767 this.hiddenEl().dom.value = '';
33768 this.inputEl().dom.value = '';
33775 decimalPrecisionFcn : function(v)
33777 return Math.floor(v);
33780 beforeBlur : function()
33782 var v = this.parseValue(this.getRawValue());
33784 if(v || v === 0 || v === ''){
33789 hiddenEl : function()
33791 return this.el.select('input.hidden-number-input',true).first();
33803 * @class Roo.bootstrap.DocumentSlider
33804 * @extends Roo.bootstrap.Component
33805 * Bootstrap DocumentSlider class
33808 * Create a new DocumentViewer
33809 * @param {Object} config The config object
33812 Roo.bootstrap.DocumentSlider = function(config){
33813 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33820 * Fire after initEvent
33821 * @param {Roo.bootstrap.DocumentSlider} this
33826 * Fire after update
33827 * @param {Roo.bootstrap.DocumentSlider} this
33833 * @param {Roo.bootstrap.DocumentSlider} this
33839 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33845 getAutoCreate : function()
33849 cls : 'roo-document-slider',
33853 cls : 'roo-document-slider-header',
33857 cls : 'roo-document-slider-header-title'
33863 cls : 'roo-document-slider-body',
33867 cls : 'roo-document-slider-prev',
33871 cls : 'fa fa-chevron-left'
33877 cls : 'roo-document-slider-thumb',
33881 cls : 'roo-document-slider-image'
33887 cls : 'roo-document-slider-next',
33891 cls : 'fa fa-chevron-right'
33903 initEvents : function()
33905 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
33906 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
33908 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
33909 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
33911 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
33912 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
33914 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
33915 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
33917 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
33918 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
33920 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
33921 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33923 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
33924 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
33926 this.thumbEl.on('click', this.onClick, this);
33928 this.prevIndicator.on('click', this.prev, this);
33930 this.nextIndicator.on('click', this.next, this);
33934 initial : function()
33936 if(this.files.length){
33937 this.indicator = 1;
33941 this.fireEvent('initial', this);
33944 update : function()
33946 this.imageEl.attr('src', this.files[this.indicator - 1]);
33948 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
33950 this.prevIndicator.show();
33952 if(this.indicator == 1){
33953 this.prevIndicator.hide();
33956 this.nextIndicator.show();
33958 if(this.indicator == this.files.length){
33959 this.nextIndicator.hide();
33962 this.thumbEl.scrollTo('top');
33964 this.fireEvent('update', this);
33967 onClick : function(e)
33969 e.preventDefault();
33971 this.fireEvent('click', this);
33976 e.preventDefault();
33978 this.indicator = Math.max(1, this.indicator - 1);
33985 e.preventDefault();
33987 this.indicator = Math.min(this.files.length, this.indicator + 1);
34001 * @class Roo.bootstrap.RadioSet
34002 * @extends Roo.bootstrap.Input
34003 * Bootstrap RadioSet class
34004 * @cfg {String} indicatorpos (left|right) default left
34005 * @cfg {Boolean} inline (true|false) inline the element (default true)
34006 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34008 * Create a new RadioSet
34009 * @param {Object} config The config object
34012 Roo.bootstrap.RadioSet = function(config){
34014 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34018 Roo.bootstrap.RadioSet.register(this);
34023 * Fires when the element is checked or unchecked.
34024 * @param {Roo.bootstrap.RadioSet} this This radio
34025 * @param {Roo.bootstrap.Radio} item The checked item
34030 * Fires when the element is click.
34031 * @param {Roo.bootstrap.RadioSet} this This radio set
34032 * @param {Roo.bootstrap.Radio} item The checked item
34033 * @param {Roo.EventObject} e The event object
34040 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34048 indicatorpos : 'left',
34050 getAutoCreate : function()
34054 cls : 'roo-radio-set-label',
34058 html : this.fieldLabel
34062 if (Roo.bootstrap.version == 3) {
34065 if(this.indicatorpos == 'left'){
34068 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34069 tooltip : 'This field is required'
34074 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34075 tooltip : 'This field is required'
34081 cls : 'roo-radio-set-items'
34084 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34086 if (align === 'left' && this.fieldLabel.length) {
34089 cls : "roo-radio-set-right",
34095 if(this.labelWidth > 12){
34096 label.style = "width: " + this.labelWidth + 'px';
34099 if(this.labelWidth < 13 && this.labelmd == 0){
34100 this.labelmd = this.labelWidth;
34103 if(this.labellg > 0){
34104 label.cls += ' col-lg-' + this.labellg;
34105 items.cls += ' col-lg-' + (12 - this.labellg);
34108 if(this.labelmd > 0){
34109 label.cls += ' col-md-' + this.labelmd;
34110 items.cls += ' col-md-' + (12 - this.labelmd);
34113 if(this.labelsm > 0){
34114 label.cls += ' col-sm-' + this.labelsm;
34115 items.cls += ' col-sm-' + (12 - this.labelsm);
34118 if(this.labelxs > 0){
34119 label.cls += ' col-xs-' + this.labelxs;
34120 items.cls += ' col-xs-' + (12 - this.labelxs);
34126 cls : 'roo-radio-set',
34130 cls : 'roo-radio-set-input',
34133 value : this.value ? this.value : ''
34140 if(this.weight.length){
34141 cfg.cls += ' roo-radio-' + this.weight;
34145 cfg.cls += ' roo-radio-set-inline';
34149 ['xs','sm','md','lg'].map(function(size){
34150 if (settings[size]) {
34151 cfg.cls += ' col-' + size + '-' + settings[size];
34159 initEvents : function()
34161 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34162 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34164 if(!this.fieldLabel.length){
34165 this.labelEl.hide();
34168 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34169 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34171 this.indicator = this.indicatorEl();
34173 if(this.indicator){
34174 this.indicator.addClass('invisible');
34177 this.originalValue = this.getValue();
34181 inputEl: function ()
34183 return this.el.select('.roo-radio-set-input', true).first();
34186 getChildContainer : function()
34188 return this.itemsEl;
34191 register : function(item)
34193 this.radioes.push(item);
34197 validate : function()
34199 if(this.getVisibilityEl().hasClass('hidden')){
34205 Roo.each(this.radioes, function(i){
34214 if(this.allowBlank) {
34218 if(this.disabled || valid){
34223 this.markInvalid();
34228 markValid : function()
34230 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34231 this.indicatorEl().removeClass('visible');
34232 this.indicatorEl().addClass('invisible');
34235 this.el.removeClass([this.invalidClass, this.validClass]);
34236 this.el.addClass(this.validClass);
34237 if (Roo.bootstrap.version == 3) {
34238 this.el.removeClass(['is-invalid','is-valid']);
34239 this.el.addClass(['is-valid']);
34241 this.fireEvent('valid', this);
34244 markInvalid : function(msg)
34246 if(this.allowBlank || this.disabled){
34250 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34251 this.indicatorEl().removeClass('invisible');
34252 this.indicatorEl().addClass('visible');
34254 if (Roo.bootstrap.version == 3) {
34255 this.el.removeClass([this.invalidClass, this.validClass]);
34256 this.el.addClass(this.invalidClass);
34258 this.el.removeClass(['is-invalid','is-valid']);
34259 this.el.addClass(['is-invalid']);
34261 this.fireEvent('invalid', this, msg);
34265 setValue : function(v, suppressEvent)
34267 if(this.value === v){
34274 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34277 Roo.each(this.radioes, function(i){
34279 i.el.removeClass('checked');
34282 Roo.each(this.radioes, function(i){
34284 if(i.value === v || i.value.toString() === v.toString()){
34286 i.el.addClass('checked');
34288 if(suppressEvent !== true){
34289 this.fireEvent('check', this, i);
34300 clearInvalid : function(){
34302 if(!this.el || this.preventMark){
34306 this.el.removeClass([this.invalidClass]);
34308 this.fireEvent('valid', this);
34313 Roo.apply(Roo.bootstrap.RadioSet, {
34317 register : function(set)
34319 this.groups[set.name] = set;
34322 get: function(name)
34324 if (typeof(this.groups[name]) == 'undefined') {
34328 return this.groups[name] ;
34334 * Ext JS Library 1.1.1
34335 * Copyright(c) 2006-2007, Ext JS, LLC.
34337 * Originally Released Under LGPL - original licence link has changed is not relivant.
34340 * <script type="text/javascript">
34345 * @class Roo.bootstrap.SplitBar
34346 * @extends Roo.util.Observable
34347 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34351 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34352 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34353 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34354 split.minSize = 100;
34355 split.maxSize = 600;
34356 split.animate = true;
34357 split.on('moved', splitterMoved);
34360 * Create a new SplitBar
34361 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34362 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34363 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34364 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34365 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34366 position of the SplitBar).
34368 Roo.bootstrap.SplitBar = function(cfg){
34373 // dragElement : elm
34374 // resizingElement: el,
34376 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34377 // placement : Roo.bootstrap.SplitBar.LEFT ,
34378 // existingProxy ???
34381 this.el = Roo.get(cfg.dragElement, true);
34382 this.el.dom.unselectable = "on";
34384 this.resizingEl = Roo.get(cfg.resizingElement, true);
34388 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34389 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34392 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34395 * The minimum size of the resizing element. (Defaults to 0)
34401 * The maximum size of the resizing element. (Defaults to 2000)
34404 this.maxSize = 2000;
34407 * Whether to animate the transition to the new size
34410 this.animate = false;
34413 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34416 this.useShim = false;
34421 if(!cfg.existingProxy){
34423 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34425 this.proxy = Roo.get(cfg.existingProxy).dom;
34428 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34431 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34434 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34437 this.dragSpecs = {};
34440 * @private The adapter to use to positon and resize elements
34442 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34443 this.adapter.init(this);
34445 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34447 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34448 this.el.addClass("roo-splitbar-h");
34451 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34452 this.el.addClass("roo-splitbar-v");
34458 * Fires when the splitter is moved (alias for {@link #event-moved})
34459 * @param {Roo.bootstrap.SplitBar} this
34460 * @param {Number} newSize the new width or height
34465 * Fires when the splitter is moved
34466 * @param {Roo.bootstrap.SplitBar} this
34467 * @param {Number} newSize the new width or height
34471 * @event beforeresize
34472 * Fires before the splitter is dragged
34473 * @param {Roo.bootstrap.SplitBar} this
34475 "beforeresize" : true,
34477 "beforeapply" : true
34480 Roo.util.Observable.call(this);
34483 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34484 onStartProxyDrag : function(x, y){
34485 this.fireEvent("beforeresize", this);
34487 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34489 o.enableDisplayMode("block");
34490 // all splitbars share the same overlay
34491 Roo.bootstrap.SplitBar.prototype.overlay = o;
34493 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34494 this.overlay.show();
34495 Roo.get(this.proxy).setDisplayed("block");
34496 var size = this.adapter.getElementSize(this);
34497 this.activeMinSize = this.getMinimumSize();;
34498 this.activeMaxSize = this.getMaximumSize();;
34499 var c1 = size - this.activeMinSize;
34500 var c2 = Math.max(this.activeMaxSize - size, 0);
34501 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34502 this.dd.resetConstraints();
34503 this.dd.setXConstraint(
34504 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34505 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34507 this.dd.setYConstraint(0, 0);
34509 this.dd.resetConstraints();
34510 this.dd.setXConstraint(0, 0);
34511 this.dd.setYConstraint(
34512 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34513 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34516 this.dragSpecs.startSize = size;
34517 this.dragSpecs.startPoint = [x, y];
34518 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34522 * @private Called after the drag operation by the DDProxy
34524 onEndProxyDrag : function(e){
34525 Roo.get(this.proxy).setDisplayed(false);
34526 var endPoint = Roo.lib.Event.getXY(e);
34528 this.overlay.hide();
34531 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34532 newSize = this.dragSpecs.startSize +
34533 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34534 endPoint[0] - this.dragSpecs.startPoint[0] :
34535 this.dragSpecs.startPoint[0] - endPoint[0]
34538 newSize = this.dragSpecs.startSize +
34539 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34540 endPoint[1] - this.dragSpecs.startPoint[1] :
34541 this.dragSpecs.startPoint[1] - endPoint[1]
34544 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34545 if(newSize != this.dragSpecs.startSize){
34546 if(this.fireEvent('beforeapply', this, newSize) !== false){
34547 this.adapter.setElementSize(this, newSize);
34548 this.fireEvent("moved", this, newSize);
34549 this.fireEvent("resize", this, newSize);
34555 * Get the adapter this SplitBar uses
34556 * @return The adapter object
34558 getAdapter : function(){
34559 return this.adapter;
34563 * Set the adapter this SplitBar uses
34564 * @param {Object} adapter A SplitBar adapter object
34566 setAdapter : function(adapter){
34567 this.adapter = adapter;
34568 this.adapter.init(this);
34572 * Gets the minimum size for the resizing element
34573 * @return {Number} The minimum size
34575 getMinimumSize : function(){
34576 return this.minSize;
34580 * Sets the minimum size for the resizing element
34581 * @param {Number} minSize The minimum size
34583 setMinimumSize : function(minSize){
34584 this.minSize = minSize;
34588 * Gets the maximum size for the resizing element
34589 * @return {Number} The maximum size
34591 getMaximumSize : function(){
34592 return this.maxSize;
34596 * Sets the maximum size for the resizing element
34597 * @param {Number} maxSize The maximum size
34599 setMaximumSize : function(maxSize){
34600 this.maxSize = maxSize;
34604 * Sets the initialize size for the resizing element
34605 * @param {Number} size The initial size
34607 setCurrentSize : function(size){
34608 var oldAnimate = this.animate;
34609 this.animate = false;
34610 this.adapter.setElementSize(this, size);
34611 this.animate = oldAnimate;
34615 * Destroy this splitbar.
34616 * @param {Boolean} removeEl True to remove the element
34618 destroy : function(removeEl){
34620 this.shim.remove();
34623 this.proxy.parentNode.removeChild(this.proxy);
34631 * @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.
34633 Roo.bootstrap.SplitBar.createProxy = function(dir){
34634 var proxy = new Roo.Element(document.createElement("div"));
34635 proxy.unselectable();
34636 var cls = 'roo-splitbar-proxy';
34637 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34638 document.body.appendChild(proxy.dom);
34643 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34644 * Default Adapter. It assumes the splitter and resizing element are not positioned
34645 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34647 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34650 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34651 // do nothing for now
34652 init : function(s){
34656 * Called before drag operations to get the current size of the resizing element.
34657 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34659 getElementSize : function(s){
34660 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34661 return s.resizingEl.getWidth();
34663 return s.resizingEl.getHeight();
34668 * Called after drag operations to set the size of the resizing element.
34669 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34670 * @param {Number} newSize The new size to set
34671 * @param {Function} onComplete A function to be invoked when resizing is complete
34673 setElementSize : function(s, newSize, onComplete){
34674 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34676 s.resizingEl.setWidth(newSize);
34678 onComplete(s, newSize);
34681 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34686 s.resizingEl.setHeight(newSize);
34688 onComplete(s, newSize);
34691 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34698 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34699 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34700 * Adapter that moves the splitter element to align with the resized sizing element.
34701 * Used with an absolute positioned SplitBar.
34702 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34703 * document.body, make sure you assign an id to the body element.
34705 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34706 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34707 this.container = Roo.get(container);
34710 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34711 init : function(s){
34712 this.basic.init(s);
34715 getElementSize : function(s){
34716 return this.basic.getElementSize(s);
34719 setElementSize : function(s, newSize, onComplete){
34720 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34723 moveSplitter : function(s){
34724 var yes = Roo.bootstrap.SplitBar;
34725 switch(s.placement){
34727 s.el.setX(s.resizingEl.getRight());
34730 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34733 s.el.setY(s.resizingEl.getBottom());
34736 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34743 * Orientation constant - Create a vertical SplitBar
34747 Roo.bootstrap.SplitBar.VERTICAL = 1;
34750 * Orientation constant - Create a horizontal SplitBar
34754 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34757 * Placement constant - The resizing element is to the left of the splitter element
34761 Roo.bootstrap.SplitBar.LEFT = 1;
34764 * Placement constant - The resizing element is to the right of the splitter element
34768 Roo.bootstrap.SplitBar.RIGHT = 2;
34771 * Placement constant - The resizing element is positioned above the splitter element
34775 Roo.bootstrap.SplitBar.TOP = 3;
34778 * Placement constant - The resizing element is positioned under splitter element
34782 Roo.bootstrap.SplitBar.BOTTOM = 4;
34783 Roo.namespace("Roo.bootstrap.layout");/*
34785 * Ext JS Library 1.1.1
34786 * Copyright(c) 2006-2007, Ext JS, LLC.
34788 * Originally Released Under LGPL - original licence link has changed is not relivant.
34791 * <script type="text/javascript">
34795 * @class Roo.bootstrap.layout.Manager
34796 * @extends Roo.bootstrap.Component
34797 * Base class for layout managers.
34799 Roo.bootstrap.layout.Manager = function(config)
34801 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34807 /** false to disable window resize monitoring @type Boolean */
34808 this.monitorWindowResize = true;
34813 * Fires when a layout is performed.
34814 * @param {Roo.LayoutManager} this
34818 * @event regionresized
34819 * Fires when the user resizes a region.
34820 * @param {Roo.LayoutRegion} region The resized region
34821 * @param {Number} newSize The new size (width for east/west, height for north/south)
34823 "regionresized" : true,
34825 * @event regioncollapsed
34826 * Fires when a region is collapsed.
34827 * @param {Roo.LayoutRegion} region The collapsed region
34829 "regioncollapsed" : true,
34831 * @event regionexpanded
34832 * Fires when a region is expanded.
34833 * @param {Roo.LayoutRegion} region The expanded region
34835 "regionexpanded" : true
34837 this.updating = false;
34840 this.el = Roo.get(config.el);
34846 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34851 monitorWindowResize : true,
34857 onRender : function(ct, position)
34860 this.el = Roo.get(ct);
34863 //this.fireEvent('render',this);
34867 initEvents: function()
34871 // ie scrollbar fix
34872 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34873 document.body.scroll = "no";
34874 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34875 this.el.position('relative');
34877 this.id = this.el.id;
34878 this.el.addClass("roo-layout-container");
34879 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34880 if(this.el.dom != document.body ) {
34881 this.el.on('resize', this.layout,this);
34882 this.el.on('show', this.layout,this);
34888 * Returns true if this layout is currently being updated
34889 * @return {Boolean}
34891 isUpdating : function(){
34892 return this.updating;
34896 * Suspend the LayoutManager from doing auto-layouts while
34897 * making multiple add or remove calls
34899 beginUpdate : function(){
34900 this.updating = true;
34904 * Restore auto-layouts and optionally disable the manager from performing a layout
34905 * @param {Boolean} noLayout true to disable a layout update
34907 endUpdate : function(noLayout){
34908 this.updating = false;
34914 layout: function(){
34918 onRegionResized : function(region, newSize){
34919 this.fireEvent("regionresized", region, newSize);
34923 onRegionCollapsed : function(region){
34924 this.fireEvent("regioncollapsed", region);
34927 onRegionExpanded : function(region){
34928 this.fireEvent("regionexpanded", region);
34932 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
34933 * performs box-model adjustments.
34934 * @return {Object} The size as an object {width: (the width), height: (the height)}
34936 getViewSize : function()
34939 if(this.el.dom != document.body){
34940 size = this.el.getSize();
34942 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
34944 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
34945 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
34950 * Returns the Element this layout is bound to.
34951 * @return {Roo.Element}
34953 getEl : function(){
34958 * Returns the specified region.
34959 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
34960 * @return {Roo.LayoutRegion}
34962 getRegion : function(target){
34963 return this.regions[target.toLowerCase()];
34966 onWindowResize : function(){
34967 if(this.monitorWindowResize){
34974 * Ext JS Library 1.1.1
34975 * Copyright(c) 2006-2007, Ext JS, LLC.
34977 * Originally Released Under LGPL - original licence link has changed is not relivant.
34980 * <script type="text/javascript">
34983 * @class Roo.bootstrap.layout.Border
34984 * @extends Roo.bootstrap.layout.Manager
34985 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
34986 * please see: examples/bootstrap/nested.html<br><br>
34988 <b>The container the layout is rendered into can be either the body element or any other element.
34989 If it is not the body element, the container needs to either be an absolute positioned element,
34990 or you will need to add "position:relative" to the css of the container. You will also need to specify
34991 the container size if it is not the body element.</b>
34994 * Create a new Border
34995 * @param {Object} config Configuration options
34997 Roo.bootstrap.layout.Border = function(config){
34998 config = config || {};
34999 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35003 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35004 if(config[region]){
35005 config[region].region = region;
35006 this.addRegion(config[region]);
35012 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35014 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35016 * Creates and adds a new region if it doesn't already exist.
35017 * @param {String} target The target region key (north, south, east, west or center).
35018 * @param {Object} config The regions config object
35019 * @return {BorderLayoutRegion} The new region
35021 addRegion : function(config)
35023 if(!this.regions[config.region]){
35024 var r = this.factory(config);
35025 this.bindRegion(r);
35027 return this.regions[config.region];
35031 bindRegion : function(r){
35032 this.regions[r.config.region] = r;
35034 r.on("visibilitychange", this.layout, this);
35035 r.on("paneladded", this.layout, this);
35036 r.on("panelremoved", this.layout, this);
35037 r.on("invalidated", this.layout, this);
35038 r.on("resized", this.onRegionResized, this);
35039 r.on("collapsed", this.onRegionCollapsed, this);
35040 r.on("expanded", this.onRegionExpanded, this);
35044 * Performs a layout update.
35046 layout : function()
35048 if(this.updating) {
35052 // render all the rebions if they have not been done alreayd?
35053 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35054 if(this.regions[region] && !this.regions[region].bodyEl){
35055 this.regions[region].onRender(this.el)
35059 var size = this.getViewSize();
35060 var w = size.width;
35061 var h = size.height;
35066 //var x = 0, y = 0;
35068 var rs = this.regions;
35069 var north = rs["north"];
35070 var south = rs["south"];
35071 var west = rs["west"];
35072 var east = rs["east"];
35073 var center = rs["center"];
35074 //if(this.hideOnLayout){ // not supported anymore
35075 //c.el.setStyle("display", "none");
35077 if(north && north.isVisible()){
35078 var b = north.getBox();
35079 var m = north.getMargins();
35080 b.width = w - (m.left+m.right);
35083 centerY = b.height + b.y + m.bottom;
35084 centerH -= centerY;
35085 north.updateBox(this.safeBox(b));
35087 if(south && south.isVisible()){
35088 var b = south.getBox();
35089 var m = south.getMargins();
35090 b.width = w - (m.left+m.right);
35092 var totalHeight = (b.height + m.top + m.bottom);
35093 b.y = h - totalHeight + m.top;
35094 centerH -= totalHeight;
35095 south.updateBox(this.safeBox(b));
35097 if(west && west.isVisible()){
35098 var b = west.getBox();
35099 var m = west.getMargins();
35100 b.height = centerH - (m.top+m.bottom);
35102 b.y = centerY + m.top;
35103 var totalWidth = (b.width + m.left + m.right);
35104 centerX += totalWidth;
35105 centerW -= totalWidth;
35106 west.updateBox(this.safeBox(b));
35108 if(east && east.isVisible()){
35109 var b = east.getBox();
35110 var m = east.getMargins();
35111 b.height = centerH - (m.top+m.bottom);
35112 var totalWidth = (b.width + m.left + m.right);
35113 b.x = w - totalWidth + m.left;
35114 b.y = centerY + m.top;
35115 centerW -= totalWidth;
35116 east.updateBox(this.safeBox(b));
35119 var m = center.getMargins();
35121 x: centerX + m.left,
35122 y: centerY + m.top,
35123 width: centerW - (m.left+m.right),
35124 height: centerH - (m.top+m.bottom)
35126 //if(this.hideOnLayout){
35127 //center.el.setStyle("display", "block");
35129 center.updateBox(this.safeBox(centerBox));
35132 this.fireEvent("layout", this);
35136 safeBox : function(box){
35137 box.width = Math.max(0, box.width);
35138 box.height = Math.max(0, box.height);
35143 * Adds a ContentPanel (or subclass) to this layout.
35144 * @param {String} target The target region key (north, south, east, west or center).
35145 * @param {Roo.ContentPanel} panel The panel to add
35146 * @return {Roo.ContentPanel} The added panel
35148 add : function(target, panel){
35150 target = target.toLowerCase();
35151 return this.regions[target].add(panel);
35155 * Remove a ContentPanel (or subclass) to this layout.
35156 * @param {String} target The target region key (north, south, east, west or center).
35157 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35158 * @return {Roo.ContentPanel} The removed panel
35160 remove : function(target, panel){
35161 target = target.toLowerCase();
35162 return this.regions[target].remove(panel);
35166 * Searches all regions for a panel with the specified id
35167 * @param {String} panelId
35168 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35170 findPanel : function(panelId){
35171 var rs = this.regions;
35172 for(var target in rs){
35173 if(typeof rs[target] != "function"){
35174 var p = rs[target].getPanel(panelId);
35184 * Searches all regions for a panel with the specified id and activates (shows) it.
35185 * @param {String/ContentPanel} panelId The panels id or the panel itself
35186 * @return {Roo.ContentPanel} The shown panel or null
35188 showPanel : function(panelId) {
35189 var rs = this.regions;
35190 for(var target in rs){
35191 var r = rs[target];
35192 if(typeof r != "function"){
35193 if(r.hasPanel(panelId)){
35194 return r.showPanel(panelId);
35202 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35203 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35206 restoreState : function(provider){
35208 provider = Roo.state.Manager;
35210 var sm = new Roo.LayoutStateManager();
35211 sm.init(this, provider);
35217 * Adds a xtype elements to the layout.
35221 xtype : 'ContentPanel',
35228 xtype : 'NestedLayoutPanel',
35234 items : [ ... list of content panels or nested layout panels.. ]
35238 * @param {Object} cfg Xtype definition of item to add.
35240 addxtype : function(cfg)
35242 // basically accepts a pannel...
35243 // can accept a layout region..!?!?
35244 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35247 // theory? children can only be panels??
35249 //if (!cfg.xtype.match(/Panel$/)) {
35254 if (typeof(cfg.region) == 'undefined') {
35255 Roo.log("Failed to add Panel, region was not set");
35259 var region = cfg.region;
35265 xitems = cfg.items;
35272 case 'Content': // ContentPanel (el, cfg)
35273 case 'Scroll': // ContentPanel (el, cfg)
35275 cfg.autoCreate = true;
35276 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35278 // var el = this.el.createChild();
35279 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35282 this.add(region, ret);
35286 case 'TreePanel': // our new panel!
35287 cfg.el = this.el.createChild();
35288 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35289 this.add(region, ret);
35294 // create a new Layout (which is a Border Layout...
35296 var clayout = cfg.layout;
35297 clayout.el = this.el.createChild();
35298 clayout.items = clayout.items || [];
35302 // replace this exitems with the clayout ones..
35303 xitems = clayout.items;
35305 // force background off if it's in center...
35306 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35307 cfg.background = false;
35309 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35312 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35313 //console.log('adding nested layout panel ' + cfg.toSource());
35314 this.add(region, ret);
35315 nb = {}; /// find first...
35320 // needs grid and region
35322 //var el = this.getRegion(region).el.createChild();
35324 *var el = this.el.createChild();
35325 // create the grid first...
35326 cfg.grid.container = el;
35327 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35330 if (region == 'center' && this.active ) {
35331 cfg.background = false;
35334 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35336 this.add(region, ret);
35338 if (cfg.background) {
35339 // render grid on panel activation (if panel background)
35340 ret.on('activate', function(gp) {
35341 if (!gp.grid.rendered) {
35342 // gp.grid.render(el);
35346 // cfg.grid.render(el);
35352 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35353 // it was the old xcomponent building that caused this before.
35354 // espeically if border is the top element in the tree.
35364 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35366 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35367 this.add(region, ret);
35371 throw "Can not add '" + cfg.xtype + "' to Border";
35377 this.beginUpdate();
35381 Roo.each(xitems, function(i) {
35382 region = nb && i.region ? i.region : false;
35384 var add = ret.addxtype(i);
35387 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35388 if (!i.background) {
35389 abn[region] = nb[region] ;
35396 // make the last non-background panel active..
35397 //if (nb) { Roo.log(abn); }
35400 for(var r in abn) {
35401 region = this.getRegion(r);
35403 // tried using nb[r], but it does not work..
35405 region.showPanel(abn[r]);
35416 factory : function(cfg)
35419 var validRegions = Roo.bootstrap.layout.Border.regions;
35421 var target = cfg.region;
35424 var r = Roo.bootstrap.layout;
35428 return new r.North(cfg);
35430 return new r.South(cfg);
35432 return new r.East(cfg);
35434 return new r.West(cfg);
35436 return new r.Center(cfg);
35438 throw 'Layout region "'+target+'" not supported.';
35445 * Ext JS Library 1.1.1
35446 * Copyright(c) 2006-2007, Ext JS, LLC.
35448 * Originally Released Under LGPL - original licence link has changed is not relivant.
35451 * <script type="text/javascript">
35455 * @class Roo.bootstrap.layout.Basic
35456 * @extends Roo.util.Observable
35457 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35458 * and does not have a titlebar, tabs or any other features. All it does is size and position
35459 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35460 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35461 * @cfg {string} region the region that it inhabits..
35462 * @cfg {bool} skipConfig skip config?
35466 Roo.bootstrap.layout.Basic = function(config){
35468 this.mgr = config.mgr;
35470 this.position = config.region;
35472 var skipConfig = config.skipConfig;
35476 * @scope Roo.BasicLayoutRegion
35480 * @event beforeremove
35481 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35482 * @param {Roo.LayoutRegion} this
35483 * @param {Roo.ContentPanel} panel The panel
35484 * @param {Object} e The cancel event object
35486 "beforeremove" : true,
35488 * @event invalidated
35489 * Fires when the layout for this region is changed.
35490 * @param {Roo.LayoutRegion} this
35492 "invalidated" : true,
35494 * @event visibilitychange
35495 * Fires when this region is shown or hidden
35496 * @param {Roo.LayoutRegion} this
35497 * @param {Boolean} visibility true or false
35499 "visibilitychange" : true,
35501 * @event paneladded
35502 * Fires when a panel is added.
35503 * @param {Roo.LayoutRegion} this
35504 * @param {Roo.ContentPanel} panel The panel
35506 "paneladded" : true,
35508 * @event panelremoved
35509 * Fires when a panel is removed.
35510 * @param {Roo.LayoutRegion} this
35511 * @param {Roo.ContentPanel} panel The panel
35513 "panelremoved" : true,
35515 * @event beforecollapse
35516 * Fires when this region before collapse.
35517 * @param {Roo.LayoutRegion} this
35519 "beforecollapse" : true,
35522 * Fires when this region is collapsed.
35523 * @param {Roo.LayoutRegion} this
35525 "collapsed" : true,
35528 * Fires when this region is expanded.
35529 * @param {Roo.LayoutRegion} this
35534 * Fires when this region is slid into view.
35535 * @param {Roo.LayoutRegion} this
35537 "slideshow" : true,
35540 * Fires when this region slides out of view.
35541 * @param {Roo.LayoutRegion} this
35543 "slidehide" : true,
35545 * @event panelactivated
35546 * Fires when a panel is activated.
35547 * @param {Roo.LayoutRegion} this
35548 * @param {Roo.ContentPanel} panel The activated panel
35550 "panelactivated" : true,
35553 * Fires when the user resizes this region.
35554 * @param {Roo.LayoutRegion} this
35555 * @param {Number} newSize The new size (width for east/west, height for north/south)
35559 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35560 this.panels = new Roo.util.MixedCollection();
35561 this.panels.getKey = this.getPanelId.createDelegate(this);
35563 this.activePanel = null;
35564 // ensure listeners are added...
35566 if (config.listeners || config.events) {
35567 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35568 listeners : config.listeners || {},
35569 events : config.events || {}
35573 if(skipConfig !== true){
35574 this.applyConfig(config);
35578 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35580 getPanelId : function(p){
35584 applyConfig : function(config){
35585 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35586 this.config = config;
35591 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35592 * the width, for horizontal (north, south) the height.
35593 * @param {Number} newSize The new width or height
35595 resizeTo : function(newSize){
35596 var el = this.el ? this.el :
35597 (this.activePanel ? this.activePanel.getEl() : null);
35599 switch(this.position){
35602 el.setWidth(newSize);
35603 this.fireEvent("resized", this, newSize);
35607 el.setHeight(newSize);
35608 this.fireEvent("resized", this, newSize);
35614 getBox : function(){
35615 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35618 getMargins : function(){
35619 return this.margins;
35622 updateBox : function(box){
35624 var el = this.activePanel.getEl();
35625 el.dom.style.left = box.x + "px";
35626 el.dom.style.top = box.y + "px";
35627 this.activePanel.setSize(box.width, box.height);
35631 * Returns the container element for this region.
35632 * @return {Roo.Element}
35634 getEl : function(){
35635 return this.activePanel;
35639 * Returns true if this region is currently visible.
35640 * @return {Boolean}
35642 isVisible : function(){
35643 return this.activePanel ? true : false;
35646 setActivePanel : function(panel){
35647 panel = this.getPanel(panel);
35648 if(this.activePanel && this.activePanel != panel){
35649 this.activePanel.setActiveState(false);
35650 this.activePanel.getEl().setLeftTop(-10000,-10000);
35652 this.activePanel = panel;
35653 panel.setActiveState(true);
35655 panel.setSize(this.box.width, this.box.height);
35657 this.fireEvent("panelactivated", this, panel);
35658 this.fireEvent("invalidated");
35662 * Show the specified panel.
35663 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35664 * @return {Roo.ContentPanel} The shown panel or null
35666 showPanel : function(panel){
35667 panel = this.getPanel(panel);
35669 this.setActivePanel(panel);
35675 * Get the active panel for this region.
35676 * @return {Roo.ContentPanel} The active panel or null
35678 getActivePanel : function(){
35679 return this.activePanel;
35683 * Add the passed ContentPanel(s)
35684 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35685 * @return {Roo.ContentPanel} The panel added (if only one was added)
35687 add : function(panel){
35688 if(arguments.length > 1){
35689 for(var i = 0, len = arguments.length; i < len; i++) {
35690 this.add(arguments[i]);
35694 if(this.hasPanel(panel)){
35695 this.showPanel(panel);
35698 var el = panel.getEl();
35699 if(el.dom.parentNode != this.mgr.el.dom){
35700 this.mgr.el.dom.appendChild(el.dom);
35702 if(panel.setRegion){
35703 panel.setRegion(this);
35705 this.panels.add(panel);
35706 el.setStyle("position", "absolute");
35707 if(!panel.background){
35708 this.setActivePanel(panel);
35709 if(this.config.initialSize && this.panels.getCount()==1){
35710 this.resizeTo(this.config.initialSize);
35713 this.fireEvent("paneladded", this, panel);
35718 * Returns true if the panel is in this region.
35719 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35720 * @return {Boolean}
35722 hasPanel : function(panel){
35723 if(typeof panel == "object"){ // must be panel obj
35724 panel = panel.getId();
35726 return this.getPanel(panel) ? true : false;
35730 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35731 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35732 * @param {Boolean} preservePanel Overrides the config preservePanel option
35733 * @return {Roo.ContentPanel} The panel that was removed
35735 remove : function(panel, preservePanel){
35736 panel = this.getPanel(panel);
35741 this.fireEvent("beforeremove", this, panel, e);
35742 if(e.cancel === true){
35745 var panelId = panel.getId();
35746 this.panels.removeKey(panelId);
35751 * Returns the panel specified or null if it's not in this region.
35752 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35753 * @return {Roo.ContentPanel}
35755 getPanel : function(id){
35756 if(typeof id == "object"){ // must be panel obj
35759 return this.panels.get(id);
35763 * Returns this regions position (north/south/east/west/center).
35766 getPosition: function(){
35767 return this.position;
35771 * Ext JS Library 1.1.1
35772 * Copyright(c) 2006-2007, Ext JS, LLC.
35774 * Originally Released Under LGPL - original licence link has changed is not relivant.
35777 * <script type="text/javascript">
35781 * @class Roo.bootstrap.layout.Region
35782 * @extends Roo.bootstrap.layout.Basic
35783 * This class represents a region in a layout manager.
35785 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35786 * @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})
35787 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35788 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35789 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35790 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35791 * @cfg {String} title The title for the region (overrides panel titles)
35792 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35793 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35794 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35795 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35796 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35797 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35798 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35799 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35800 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35801 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35803 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35804 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35805 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35806 * @cfg {Number} width For East/West panels
35807 * @cfg {Number} height For North/South panels
35808 * @cfg {Boolean} split To show the splitter
35809 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35811 * @cfg {string} cls Extra CSS classes to add to region
35813 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35814 * @cfg {string} region the region that it inhabits..
35817 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35818 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35820 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35821 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35822 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35824 Roo.bootstrap.layout.Region = function(config)
35826 this.applyConfig(config);
35828 var mgr = config.mgr;
35829 var pos = config.region;
35830 config.skipConfig = true;
35831 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35834 this.onRender(mgr.el);
35837 this.visible = true;
35838 this.collapsed = false;
35839 this.unrendered_panels = [];
35842 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35844 position: '', // set by wrapper (eg. north/south etc..)
35845 unrendered_panels : null, // unrendered panels.
35846 createBody : function(){
35847 /** This region's body element
35848 * @type Roo.Element */
35849 this.bodyEl = this.el.createChild({
35851 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35855 onRender: function(ctr, pos)
35857 var dh = Roo.DomHelper;
35858 /** This region's container element
35859 * @type Roo.Element */
35860 this.el = dh.append(ctr.dom, {
35862 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35864 /** This region's title element
35865 * @type Roo.Element */
35867 this.titleEl = dh.append(this.el.dom,
35870 unselectable: "on",
35871 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35873 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35874 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
35877 this.titleEl.enableDisplayMode();
35878 /** This region's title text element
35879 * @type HTMLElement */
35880 this.titleTextEl = this.titleEl.dom.firstChild;
35881 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
35883 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
35884 this.closeBtn.enableDisplayMode();
35885 this.closeBtn.on("click", this.closeClicked, this);
35886 this.closeBtn.hide();
35888 this.createBody(this.config);
35889 if(this.config.hideWhenEmpty){
35891 this.on("paneladded", this.validateVisibility, this);
35892 this.on("panelremoved", this.validateVisibility, this);
35894 if(this.autoScroll){
35895 this.bodyEl.setStyle("overflow", "auto");
35897 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
35899 //if(c.titlebar !== false){
35900 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
35901 this.titleEl.hide();
35903 this.titleEl.show();
35904 if(this.config.title){
35905 this.titleTextEl.innerHTML = this.config.title;
35909 if(this.config.collapsed){
35910 this.collapse(true);
35912 if(this.config.hidden){
35916 if (this.unrendered_panels && this.unrendered_panels.length) {
35917 for (var i =0;i< this.unrendered_panels.length; i++) {
35918 this.add(this.unrendered_panels[i]);
35920 this.unrendered_panels = null;
35926 applyConfig : function(c)
35929 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
35930 var dh = Roo.DomHelper;
35931 if(c.titlebar !== false){
35932 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
35933 this.collapseBtn.on("click", this.collapse, this);
35934 this.collapseBtn.enableDisplayMode();
35936 if(c.showPin === true || this.showPin){
35937 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
35938 this.stickBtn.enableDisplayMode();
35939 this.stickBtn.on("click", this.expand, this);
35940 this.stickBtn.hide();
35945 /** This region's collapsed element
35946 * @type Roo.Element */
35949 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
35950 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
35953 if(c.floatable !== false){
35954 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
35955 this.collapsedEl.on("click", this.collapseClick, this);
35958 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
35959 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
35960 id: "message", unselectable: "on", style:{"float":"left"}});
35961 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
35963 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
35964 this.expandBtn.on("click", this.expand, this);
35968 if(this.collapseBtn){
35969 this.collapseBtn.setVisible(c.collapsible == true);
35972 this.cmargins = c.cmargins || this.cmargins ||
35973 (this.position == "west" || this.position == "east" ?
35974 {top: 0, left: 2, right:2, bottom: 0} :
35975 {top: 2, left: 0, right:0, bottom: 2});
35977 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35980 this.bottomTabs = c.tabPosition != "top";
35982 this.autoScroll = c.autoScroll || false;
35987 this.duration = c.duration || .30;
35988 this.slideDuration = c.slideDuration || .45;
35993 * Returns true if this region is currently visible.
35994 * @return {Boolean}
35996 isVisible : function(){
35997 return this.visible;
36001 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36002 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36004 //setCollapsedTitle : function(title){
36005 // title = title || " ";
36006 // if(this.collapsedTitleTextEl){
36007 // this.collapsedTitleTextEl.innerHTML = title;
36011 getBox : function(){
36013 // if(!this.collapsed){
36014 b = this.el.getBox(false, true);
36016 // b = this.collapsedEl.getBox(false, true);
36021 getMargins : function(){
36022 return this.margins;
36023 //return this.collapsed ? this.cmargins : this.margins;
36026 highlight : function(){
36027 this.el.addClass("x-layout-panel-dragover");
36030 unhighlight : function(){
36031 this.el.removeClass("x-layout-panel-dragover");
36034 updateBox : function(box)
36036 if (!this.bodyEl) {
36037 return; // not rendered yet..
36041 if(!this.collapsed){
36042 this.el.dom.style.left = box.x + "px";
36043 this.el.dom.style.top = box.y + "px";
36044 this.updateBody(box.width, box.height);
36046 this.collapsedEl.dom.style.left = box.x + "px";
36047 this.collapsedEl.dom.style.top = box.y + "px";
36048 this.collapsedEl.setSize(box.width, box.height);
36051 this.tabs.autoSizeTabs();
36055 updateBody : function(w, h)
36058 this.el.setWidth(w);
36059 w -= this.el.getBorderWidth("rl");
36060 if(this.config.adjustments){
36061 w += this.config.adjustments[0];
36064 if(h !== null && h > 0){
36065 this.el.setHeight(h);
36066 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36067 h -= this.el.getBorderWidth("tb");
36068 if(this.config.adjustments){
36069 h += this.config.adjustments[1];
36071 this.bodyEl.setHeight(h);
36073 h = this.tabs.syncHeight(h);
36076 if(this.panelSize){
36077 w = w !== null ? w : this.panelSize.width;
36078 h = h !== null ? h : this.panelSize.height;
36080 if(this.activePanel){
36081 var el = this.activePanel.getEl();
36082 w = w !== null ? w : el.getWidth();
36083 h = h !== null ? h : el.getHeight();
36084 this.panelSize = {width: w, height: h};
36085 this.activePanel.setSize(w, h);
36087 if(Roo.isIE && this.tabs){
36088 this.tabs.el.repaint();
36093 * Returns the container element for this region.
36094 * @return {Roo.Element}
36096 getEl : function(){
36101 * Hides this region.
36104 //if(!this.collapsed){
36105 this.el.dom.style.left = "-2000px";
36108 // this.collapsedEl.dom.style.left = "-2000px";
36109 // this.collapsedEl.hide();
36111 this.visible = false;
36112 this.fireEvent("visibilitychange", this, false);
36116 * Shows this region if it was previously hidden.
36119 //if(!this.collapsed){
36122 // this.collapsedEl.show();
36124 this.visible = true;
36125 this.fireEvent("visibilitychange", this, true);
36128 closeClicked : function(){
36129 if(this.activePanel){
36130 this.remove(this.activePanel);
36134 collapseClick : function(e){
36136 e.stopPropagation();
36139 e.stopPropagation();
36145 * Collapses this region.
36146 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36149 collapse : function(skipAnim, skipCheck = false){
36150 if(this.collapsed) {
36154 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36156 this.collapsed = true;
36158 this.split.el.hide();
36160 if(this.config.animate && skipAnim !== true){
36161 this.fireEvent("invalidated", this);
36162 this.animateCollapse();
36164 this.el.setLocation(-20000,-20000);
36166 this.collapsedEl.show();
36167 this.fireEvent("collapsed", this);
36168 this.fireEvent("invalidated", this);
36174 animateCollapse : function(){
36179 * Expands this region if it was previously collapsed.
36180 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36181 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36184 expand : function(e, skipAnim){
36186 e.stopPropagation();
36188 if(!this.collapsed || this.el.hasActiveFx()) {
36192 this.afterSlideIn();
36195 this.collapsed = false;
36196 if(this.config.animate && skipAnim !== true){
36197 this.animateExpand();
36201 this.split.el.show();
36203 this.collapsedEl.setLocation(-2000,-2000);
36204 this.collapsedEl.hide();
36205 this.fireEvent("invalidated", this);
36206 this.fireEvent("expanded", this);
36210 animateExpand : function(){
36214 initTabs : function()
36216 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36218 var ts = new Roo.bootstrap.panel.Tabs({
36219 el: this.bodyEl.dom,
36220 tabPosition: this.bottomTabs ? 'bottom' : 'top',
36221 disableTooltips: this.config.disableTabTips,
36222 toolbar : this.config.toolbar
36225 if(this.config.hideTabs){
36226 ts.stripWrap.setDisplayed(false);
36229 ts.resizeTabs = this.config.resizeTabs === true;
36230 ts.minTabWidth = this.config.minTabWidth || 40;
36231 ts.maxTabWidth = this.config.maxTabWidth || 250;
36232 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36233 ts.monitorResize = false;
36234 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36235 ts.bodyEl.addClass('roo-layout-tabs-body');
36236 this.panels.each(this.initPanelAsTab, this);
36239 initPanelAsTab : function(panel){
36240 var ti = this.tabs.addTab(
36244 this.config.closeOnTab && panel.isClosable(),
36247 if(panel.tabTip !== undefined){
36248 ti.setTooltip(panel.tabTip);
36250 ti.on("activate", function(){
36251 this.setActivePanel(panel);
36254 if(this.config.closeOnTab){
36255 ti.on("beforeclose", function(t, e){
36257 this.remove(panel);
36261 panel.tabItem = ti;
36266 updatePanelTitle : function(panel, title)
36268 if(this.activePanel == panel){
36269 this.updateTitle(title);
36272 var ti = this.tabs.getTab(panel.getEl().id);
36274 if(panel.tabTip !== undefined){
36275 ti.setTooltip(panel.tabTip);
36280 updateTitle : function(title){
36281 if(this.titleTextEl && !this.config.title){
36282 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36286 setActivePanel : function(panel)
36288 panel = this.getPanel(panel);
36289 if(this.activePanel && this.activePanel != panel){
36290 if(this.activePanel.setActiveState(false) === false){
36294 this.activePanel = panel;
36295 panel.setActiveState(true);
36296 if(this.panelSize){
36297 panel.setSize(this.panelSize.width, this.panelSize.height);
36300 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36302 this.updateTitle(panel.getTitle());
36304 this.fireEvent("invalidated", this);
36306 this.fireEvent("panelactivated", this, panel);
36310 * Shows the specified panel.
36311 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36312 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36314 showPanel : function(panel)
36316 panel = this.getPanel(panel);
36319 var tab = this.tabs.getTab(panel.getEl().id);
36320 if(tab.isHidden()){
36321 this.tabs.unhideTab(tab.id);
36325 this.setActivePanel(panel);
36332 * Get the active panel for this region.
36333 * @return {Roo.ContentPanel} The active panel or null
36335 getActivePanel : function(){
36336 return this.activePanel;
36339 validateVisibility : function(){
36340 if(this.panels.getCount() < 1){
36341 this.updateTitle(" ");
36342 this.closeBtn.hide();
36345 if(!this.isVisible()){
36352 * Adds the passed ContentPanel(s) to this region.
36353 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36354 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36356 add : function(panel)
36358 if(arguments.length > 1){
36359 for(var i = 0, len = arguments.length; i < len; i++) {
36360 this.add(arguments[i]);
36365 // if we have not been rendered yet, then we can not really do much of this..
36366 if (!this.bodyEl) {
36367 this.unrendered_panels.push(panel);
36374 if(this.hasPanel(panel)){
36375 this.showPanel(panel);
36378 panel.setRegion(this);
36379 this.panels.add(panel);
36380 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36381 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36382 // and hide them... ???
36383 this.bodyEl.dom.appendChild(panel.getEl().dom);
36384 if(panel.background !== true){
36385 this.setActivePanel(panel);
36387 this.fireEvent("paneladded", this, panel);
36394 this.initPanelAsTab(panel);
36398 if(panel.background !== true){
36399 this.tabs.activate(panel.getEl().id);
36401 this.fireEvent("paneladded", this, panel);
36406 * Hides the tab for the specified panel.
36407 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36409 hidePanel : function(panel){
36410 if(this.tabs && (panel = this.getPanel(panel))){
36411 this.tabs.hideTab(panel.getEl().id);
36416 * Unhides the tab for a previously hidden panel.
36417 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36419 unhidePanel : function(panel){
36420 if(this.tabs && (panel = this.getPanel(panel))){
36421 this.tabs.unhideTab(panel.getEl().id);
36425 clearPanels : function(){
36426 while(this.panels.getCount() > 0){
36427 this.remove(this.panels.first());
36432 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36433 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36434 * @param {Boolean} preservePanel Overrides the config preservePanel option
36435 * @return {Roo.ContentPanel} The panel that was removed
36437 remove : function(panel, preservePanel)
36439 panel = this.getPanel(panel);
36444 this.fireEvent("beforeremove", this, panel, e);
36445 if(e.cancel === true){
36448 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36449 var panelId = panel.getId();
36450 this.panels.removeKey(panelId);
36452 document.body.appendChild(panel.getEl().dom);
36455 this.tabs.removeTab(panel.getEl().id);
36456 }else if (!preservePanel){
36457 this.bodyEl.dom.removeChild(panel.getEl().dom);
36459 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36460 var p = this.panels.first();
36461 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36462 tempEl.appendChild(p.getEl().dom);
36463 this.bodyEl.update("");
36464 this.bodyEl.dom.appendChild(p.getEl().dom);
36466 this.updateTitle(p.getTitle());
36468 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36469 this.setActivePanel(p);
36471 panel.setRegion(null);
36472 if(this.activePanel == panel){
36473 this.activePanel = null;
36475 if(this.config.autoDestroy !== false && preservePanel !== true){
36476 try{panel.destroy();}catch(e){}
36478 this.fireEvent("panelremoved", this, panel);
36483 * Returns the TabPanel component used by this region
36484 * @return {Roo.TabPanel}
36486 getTabs : function(){
36490 createTool : function(parentEl, className){
36491 var btn = Roo.DomHelper.append(parentEl, {
36493 cls: "x-layout-tools-button",
36496 cls: "roo-layout-tools-button-inner " + className,
36500 btn.addClassOnOver("roo-layout-tools-button-over");
36505 * Ext JS Library 1.1.1
36506 * Copyright(c) 2006-2007, Ext JS, LLC.
36508 * Originally Released Under LGPL - original licence link has changed is not relivant.
36511 * <script type="text/javascript">
36517 * @class Roo.SplitLayoutRegion
36518 * @extends Roo.LayoutRegion
36519 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36521 Roo.bootstrap.layout.Split = function(config){
36522 this.cursor = config.cursor;
36523 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36526 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36528 splitTip : "Drag to resize.",
36529 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36530 useSplitTips : false,
36532 applyConfig : function(config){
36533 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36536 onRender : function(ctr,pos) {
36538 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36539 if(!this.config.split){
36544 var splitEl = Roo.DomHelper.append(ctr.dom, {
36546 id: this.el.id + "-split",
36547 cls: "roo-layout-split roo-layout-split-"+this.position,
36550 /** The SplitBar for this region
36551 * @type Roo.SplitBar */
36552 // does not exist yet...
36553 Roo.log([this.position, this.orientation]);
36555 this.split = new Roo.bootstrap.SplitBar({
36556 dragElement : splitEl,
36557 resizingElement: this.el,
36558 orientation : this.orientation
36561 this.split.on("moved", this.onSplitMove, this);
36562 this.split.useShim = this.config.useShim === true;
36563 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36564 if(this.useSplitTips){
36565 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36567 //if(config.collapsible){
36568 // this.split.el.on("dblclick", this.collapse, this);
36571 if(typeof this.config.minSize != "undefined"){
36572 this.split.minSize = this.config.minSize;
36574 if(typeof this.config.maxSize != "undefined"){
36575 this.split.maxSize = this.config.maxSize;
36577 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36578 this.hideSplitter();
36583 getHMaxSize : function(){
36584 var cmax = this.config.maxSize || 10000;
36585 var center = this.mgr.getRegion("center");
36586 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36589 getVMaxSize : function(){
36590 var cmax = this.config.maxSize || 10000;
36591 var center = this.mgr.getRegion("center");
36592 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36595 onSplitMove : function(split, newSize){
36596 this.fireEvent("resized", this, newSize);
36600 * Returns the {@link Roo.SplitBar} for this region.
36601 * @return {Roo.SplitBar}
36603 getSplitBar : function(){
36608 this.hideSplitter();
36609 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36612 hideSplitter : function(){
36614 this.split.el.setLocation(-2000,-2000);
36615 this.split.el.hide();
36621 this.split.el.show();
36623 Roo.bootstrap.layout.Split.superclass.show.call(this);
36626 beforeSlide: function(){
36627 if(Roo.isGecko){// firefox overflow auto bug workaround
36628 this.bodyEl.clip();
36630 this.tabs.bodyEl.clip();
36632 if(this.activePanel){
36633 this.activePanel.getEl().clip();
36635 if(this.activePanel.beforeSlide){
36636 this.activePanel.beforeSlide();
36642 afterSlide : function(){
36643 if(Roo.isGecko){// firefox overflow auto bug workaround
36644 this.bodyEl.unclip();
36646 this.tabs.bodyEl.unclip();
36648 if(this.activePanel){
36649 this.activePanel.getEl().unclip();
36650 if(this.activePanel.afterSlide){
36651 this.activePanel.afterSlide();
36657 initAutoHide : function(){
36658 if(this.autoHide !== false){
36659 if(!this.autoHideHd){
36660 var st = new Roo.util.DelayedTask(this.slideIn, this);
36661 this.autoHideHd = {
36662 "mouseout": function(e){
36663 if(!e.within(this.el, true)){
36667 "mouseover" : function(e){
36673 this.el.on(this.autoHideHd);
36677 clearAutoHide : function(){
36678 if(this.autoHide !== false){
36679 this.el.un("mouseout", this.autoHideHd.mouseout);
36680 this.el.un("mouseover", this.autoHideHd.mouseover);
36684 clearMonitor : function(){
36685 Roo.get(document).un("click", this.slideInIf, this);
36688 // these names are backwards but not changed for compat
36689 slideOut : function(){
36690 if(this.isSlid || this.el.hasActiveFx()){
36693 this.isSlid = true;
36694 if(this.collapseBtn){
36695 this.collapseBtn.hide();
36697 this.closeBtnState = this.closeBtn.getStyle('display');
36698 this.closeBtn.hide();
36700 this.stickBtn.show();
36703 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36704 this.beforeSlide();
36705 this.el.setStyle("z-index", 10001);
36706 this.el.slideIn(this.getSlideAnchor(), {
36707 callback: function(){
36709 this.initAutoHide();
36710 Roo.get(document).on("click", this.slideInIf, this);
36711 this.fireEvent("slideshow", this);
36718 afterSlideIn : function(){
36719 this.clearAutoHide();
36720 this.isSlid = false;
36721 this.clearMonitor();
36722 this.el.setStyle("z-index", "");
36723 if(this.collapseBtn){
36724 this.collapseBtn.show();
36726 this.closeBtn.setStyle('display', this.closeBtnState);
36728 this.stickBtn.hide();
36730 this.fireEvent("slidehide", this);
36733 slideIn : function(cb){
36734 if(!this.isSlid || this.el.hasActiveFx()){
36738 this.isSlid = false;
36739 this.beforeSlide();
36740 this.el.slideOut(this.getSlideAnchor(), {
36741 callback: function(){
36742 this.el.setLeftTop(-10000, -10000);
36744 this.afterSlideIn();
36752 slideInIf : function(e){
36753 if(!e.within(this.el)){
36758 animateCollapse : function(){
36759 this.beforeSlide();
36760 this.el.setStyle("z-index", 20000);
36761 var anchor = this.getSlideAnchor();
36762 this.el.slideOut(anchor, {
36763 callback : function(){
36764 this.el.setStyle("z-index", "");
36765 this.collapsedEl.slideIn(anchor, {duration:.3});
36767 this.el.setLocation(-10000,-10000);
36769 this.fireEvent("collapsed", this);
36776 animateExpand : function(){
36777 this.beforeSlide();
36778 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36779 this.el.setStyle("z-index", 20000);
36780 this.collapsedEl.hide({
36783 this.el.slideIn(this.getSlideAnchor(), {
36784 callback : function(){
36785 this.el.setStyle("z-index", "");
36788 this.split.el.show();
36790 this.fireEvent("invalidated", this);
36791 this.fireEvent("expanded", this);
36819 getAnchor : function(){
36820 return this.anchors[this.position];
36823 getCollapseAnchor : function(){
36824 return this.canchors[this.position];
36827 getSlideAnchor : function(){
36828 return this.sanchors[this.position];
36831 getAlignAdj : function(){
36832 var cm = this.cmargins;
36833 switch(this.position){
36849 getExpandAdj : function(){
36850 var c = this.collapsedEl, cm = this.cmargins;
36851 switch(this.position){
36853 return [-(cm.right+c.getWidth()+cm.left), 0];
36856 return [cm.right+c.getWidth()+cm.left, 0];
36859 return [0, -(cm.top+cm.bottom+c.getHeight())];
36862 return [0, cm.top+cm.bottom+c.getHeight()];
36868 * Ext JS Library 1.1.1
36869 * Copyright(c) 2006-2007, Ext JS, LLC.
36871 * Originally Released Under LGPL - original licence link has changed is not relivant.
36874 * <script type="text/javascript">
36877 * These classes are private internal classes
36879 Roo.bootstrap.layout.Center = function(config){
36880 config.region = "center";
36881 Roo.bootstrap.layout.Region.call(this, config);
36882 this.visible = true;
36883 this.minWidth = config.minWidth || 20;
36884 this.minHeight = config.minHeight || 20;
36887 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
36889 // center panel can't be hidden
36893 // center panel can't be hidden
36896 getMinWidth: function(){
36897 return this.minWidth;
36900 getMinHeight: function(){
36901 return this.minHeight;
36914 Roo.bootstrap.layout.North = function(config)
36916 config.region = 'north';
36917 config.cursor = 'n-resize';
36919 Roo.bootstrap.layout.Split.call(this, config);
36923 this.split.placement = Roo.bootstrap.SplitBar.TOP;
36924 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36925 this.split.el.addClass("roo-layout-split-v");
36927 var size = config.initialSize || config.height;
36928 if(typeof size != "undefined"){
36929 this.el.setHeight(size);
36932 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
36934 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36938 getBox : function(){
36939 if(this.collapsed){
36940 return this.collapsedEl.getBox();
36942 var box = this.el.getBox();
36944 box.height += this.split.el.getHeight();
36949 updateBox : function(box){
36950 if(this.split && !this.collapsed){
36951 box.height -= this.split.el.getHeight();
36952 this.split.el.setLeft(box.x);
36953 this.split.el.setTop(box.y+box.height);
36954 this.split.el.setWidth(box.width);
36956 if(this.collapsed){
36957 this.updateBody(box.width, null);
36959 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
36967 Roo.bootstrap.layout.South = function(config){
36968 config.region = 'south';
36969 config.cursor = 's-resize';
36970 Roo.bootstrap.layout.Split.call(this, config);
36972 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
36973 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
36974 this.split.el.addClass("roo-layout-split-v");
36976 var size = config.initialSize || config.height;
36977 if(typeof size != "undefined"){
36978 this.el.setHeight(size);
36982 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
36983 orientation: Roo.bootstrap.SplitBar.VERTICAL,
36984 getBox : function(){
36985 if(this.collapsed){
36986 return this.collapsedEl.getBox();
36988 var box = this.el.getBox();
36990 var sh = this.split.el.getHeight();
36997 updateBox : function(box){
36998 if(this.split && !this.collapsed){
36999 var sh = this.split.el.getHeight();
37002 this.split.el.setLeft(box.x);
37003 this.split.el.setTop(box.y-sh);
37004 this.split.el.setWidth(box.width);
37006 if(this.collapsed){
37007 this.updateBody(box.width, null);
37009 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37013 Roo.bootstrap.layout.East = function(config){
37014 config.region = "east";
37015 config.cursor = "e-resize";
37016 Roo.bootstrap.layout.Split.call(this, config);
37018 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37019 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37020 this.split.el.addClass("roo-layout-split-h");
37022 var size = config.initialSize || config.width;
37023 if(typeof size != "undefined"){
37024 this.el.setWidth(size);
37027 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37028 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37029 getBox : function(){
37030 if(this.collapsed){
37031 return this.collapsedEl.getBox();
37033 var box = this.el.getBox();
37035 var sw = this.split.el.getWidth();
37042 updateBox : function(box){
37043 if(this.split && !this.collapsed){
37044 var sw = this.split.el.getWidth();
37046 this.split.el.setLeft(box.x);
37047 this.split.el.setTop(box.y);
37048 this.split.el.setHeight(box.height);
37051 if(this.collapsed){
37052 this.updateBody(null, box.height);
37054 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37058 Roo.bootstrap.layout.West = function(config){
37059 config.region = "west";
37060 config.cursor = "w-resize";
37062 Roo.bootstrap.layout.Split.call(this, config);
37064 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37065 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37066 this.split.el.addClass("roo-layout-split-h");
37070 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37071 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37073 onRender: function(ctr, pos)
37075 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37076 var size = this.config.initialSize || this.config.width;
37077 if(typeof size != "undefined"){
37078 this.el.setWidth(size);
37082 getBox : function(){
37083 if(this.collapsed){
37084 return this.collapsedEl.getBox();
37086 var box = this.el.getBox();
37088 box.width += this.split.el.getWidth();
37093 updateBox : function(box){
37094 if(this.split && !this.collapsed){
37095 var sw = this.split.el.getWidth();
37097 this.split.el.setLeft(box.x+box.width);
37098 this.split.el.setTop(box.y);
37099 this.split.el.setHeight(box.height);
37101 if(this.collapsed){
37102 this.updateBody(null, box.height);
37104 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37107 Roo.namespace("Roo.bootstrap.panel");/*
37109 * Ext JS Library 1.1.1
37110 * Copyright(c) 2006-2007, Ext JS, LLC.
37112 * Originally Released Under LGPL - original licence link has changed is not relivant.
37115 * <script type="text/javascript">
37118 * @class Roo.ContentPanel
37119 * @extends Roo.util.Observable
37120 * A basic ContentPanel element.
37121 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37122 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37123 * @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
37124 * @cfg {Boolean} closable True if the panel can be closed/removed
37125 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37126 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37127 * @cfg {Toolbar} toolbar A toolbar for this panel
37128 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37129 * @cfg {String} title The title for this panel
37130 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37131 * @cfg {String} url Calls {@link #setUrl} with this value
37132 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37133 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37134 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37135 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37136 * @cfg {Boolean} badges render the badges
37139 * Create a new ContentPanel.
37140 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37141 * @param {String/Object} config A string to set only the title or a config object
37142 * @param {String} content (optional) Set the HTML content for this panel
37143 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37145 Roo.bootstrap.panel.Content = function( config){
37147 this.tpl = config.tpl || false;
37149 var el = config.el;
37150 var content = config.content;
37152 if(config.autoCreate){ // xtype is available if this is called from factory
37155 this.el = Roo.get(el);
37156 if(!this.el && config && config.autoCreate){
37157 if(typeof config.autoCreate == "object"){
37158 if(!config.autoCreate.id){
37159 config.autoCreate.id = config.id||el;
37161 this.el = Roo.DomHelper.append(document.body,
37162 config.autoCreate, true);
37164 var elcfg = { tag: "div",
37165 cls: "roo-layout-inactive-content",
37169 elcfg.html = config.html;
37173 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37176 this.closable = false;
37177 this.loaded = false;
37178 this.active = false;
37181 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37183 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37185 this.wrapEl = this.el; //this.el.wrap();
37187 if (config.toolbar.items) {
37188 ti = config.toolbar.items ;
37189 delete config.toolbar.items ;
37193 this.toolbar.render(this.wrapEl, 'before');
37194 for(var i =0;i < ti.length;i++) {
37195 // Roo.log(['add child', items[i]]);
37196 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37198 this.toolbar.items = nitems;
37199 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37200 delete config.toolbar;
37204 // xtype created footer. - not sure if will work as we normally have to render first..
37205 if (this.footer && !this.footer.el && this.footer.xtype) {
37206 if (!this.wrapEl) {
37207 this.wrapEl = this.el.wrap();
37210 this.footer.container = this.wrapEl.createChild();
37212 this.footer = Roo.factory(this.footer, Roo);
37217 if(typeof config == "string"){
37218 this.title = config;
37220 Roo.apply(this, config);
37224 this.resizeEl = Roo.get(this.resizeEl, true);
37226 this.resizeEl = this.el;
37228 // handle view.xtype
37236 * Fires when this panel is activated.
37237 * @param {Roo.ContentPanel} this
37241 * @event deactivate
37242 * Fires when this panel is activated.
37243 * @param {Roo.ContentPanel} this
37245 "deactivate" : true,
37249 * Fires when this panel is resized if fitToFrame is true.
37250 * @param {Roo.ContentPanel} this
37251 * @param {Number} width The width after any component adjustments
37252 * @param {Number} height The height after any component adjustments
37258 * Fires when this tab is created
37259 * @param {Roo.ContentPanel} this
37270 if(this.autoScroll){
37271 this.resizeEl.setStyle("overflow", "auto");
37273 // fix randome scrolling
37274 //this.el.on('scroll', function() {
37275 // Roo.log('fix random scolling');
37276 // this.scrollTo('top',0);
37279 content = content || this.content;
37281 this.setContent(content);
37283 if(config && config.url){
37284 this.setUrl(this.url, this.params, this.loadOnce);
37289 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37291 if (this.view && typeof(this.view.xtype) != 'undefined') {
37292 this.view.el = this.el.appendChild(document.createElement("div"));
37293 this.view = Roo.factory(this.view);
37294 this.view.render && this.view.render(false, '');
37298 this.fireEvent('render', this);
37301 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37305 setRegion : function(region){
37306 this.region = region;
37307 this.setActiveClass(region && !this.background);
37311 setActiveClass: function(state)
37314 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37315 this.el.setStyle('position','relative');
37317 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37318 this.el.setStyle('position', 'absolute');
37323 * Returns the toolbar for this Panel if one was configured.
37324 * @return {Roo.Toolbar}
37326 getToolbar : function(){
37327 return this.toolbar;
37330 setActiveState : function(active)
37332 this.active = active;
37333 this.setActiveClass(active);
37335 if(this.fireEvent("deactivate", this) === false){
37340 this.fireEvent("activate", this);
37344 * Updates this panel's element
37345 * @param {String} content The new content
37346 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37348 setContent : function(content, loadScripts){
37349 this.el.update(content, loadScripts);
37352 ignoreResize : function(w, h){
37353 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37356 this.lastSize = {width: w, height: h};
37361 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37362 * @return {Roo.UpdateManager} The UpdateManager
37364 getUpdateManager : function(){
37365 return this.el.getUpdateManager();
37368 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37369 * @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:
37372 url: "your-url.php",
37373 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37374 callback: yourFunction,
37375 scope: yourObject, //(optional scope)
37378 text: "Loading...",
37383 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37384 * 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.
37385 * @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}
37386 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37387 * @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.
37388 * @return {Roo.ContentPanel} this
37391 var um = this.el.getUpdateManager();
37392 um.update.apply(um, arguments);
37398 * 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.
37399 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37400 * @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)
37401 * @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)
37402 * @return {Roo.UpdateManager} The UpdateManager
37404 setUrl : function(url, params, loadOnce){
37405 if(this.refreshDelegate){
37406 this.removeListener("activate", this.refreshDelegate);
37408 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37409 this.on("activate", this.refreshDelegate);
37410 return this.el.getUpdateManager();
37413 _handleRefresh : function(url, params, loadOnce){
37414 if(!loadOnce || !this.loaded){
37415 var updater = this.el.getUpdateManager();
37416 updater.update(url, params, this._setLoaded.createDelegate(this));
37420 _setLoaded : function(){
37421 this.loaded = true;
37425 * Returns this panel's id
37428 getId : function(){
37433 * Returns this panel's element - used by regiosn to add.
37434 * @return {Roo.Element}
37436 getEl : function(){
37437 return this.wrapEl || this.el;
37442 adjustForComponents : function(width, height)
37444 //Roo.log('adjustForComponents ');
37445 if(this.resizeEl != this.el){
37446 width -= this.el.getFrameWidth('lr');
37447 height -= this.el.getFrameWidth('tb');
37450 var te = this.toolbar.getEl();
37451 te.setWidth(width);
37452 height -= te.getHeight();
37455 var te = this.footer.getEl();
37456 te.setWidth(width);
37457 height -= te.getHeight();
37461 if(this.adjustments){
37462 width += this.adjustments[0];
37463 height += this.adjustments[1];
37465 return {"width": width, "height": height};
37468 setSize : function(width, height){
37469 if(this.fitToFrame && !this.ignoreResize(width, height)){
37470 if(this.fitContainer && this.resizeEl != this.el){
37471 this.el.setSize(width, height);
37473 var size = this.adjustForComponents(width, height);
37474 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37475 this.fireEvent('resize', this, size.width, size.height);
37480 * Returns this panel's title
37483 getTitle : function(){
37485 if (typeof(this.title) != 'object') {
37490 for (var k in this.title) {
37491 if (!this.title.hasOwnProperty(k)) {
37495 if (k.indexOf('-') >= 0) {
37496 var s = k.split('-');
37497 for (var i = 0; i<s.length; i++) {
37498 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37501 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37508 * Set this panel's title
37509 * @param {String} title
37511 setTitle : function(title){
37512 this.title = title;
37514 this.region.updatePanelTitle(this, title);
37519 * Returns true is this panel was configured to be closable
37520 * @return {Boolean}
37522 isClosable : function(){
37523 return this.closable;
37526 beforeSlide : function(){
37528 this.resizeEl.clip();
37531 afterSlide : function(){
37533 this.resizeEl.unclip();
37537 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37538 * Will fail silently if the {@link #setUrl} method has not been called.
37539 * This does not activate the panel, just updates its content.
37541 refresh : function(){
37542 if(this.refreshDelegate){
37543 this.loaded = false;
37544 this.refreshDelegate();
37549 * Destroys this panel
37551 destroy : function(){
37552 this.el.removeAllListeners();
37553 var tempEl = document.createElement("span");
37554 tempEl.appendChild(this.el.dom);
37555 tempEl.innerHTML = "";
37561 * form - if the content panel contains a form - this is a reference to it.
37562 * @type {Roo.form.Form}
37566 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37567 * This contains a reference to it.
37573 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37583 * @param {Object} cfg Xtype definition of item to add.
37587 getChildContainer: function () {
37588 return this.getEl();
37593 var ret = new Roo.factory(cfg);
37598 if (cfg.xtype.match(/^Form$/)) {
37601 //if (this.footer) {
37602 // el = this.footer.container.insertSibling(false, 'before');
37604 el = this.el.createChild();
37607 this.form = new Roo.form.Form(cfg);
37610 if ( this.form.allItems.length) {
37611 this.form.render(el.dom);
37615 // should only have one of theses..
37616 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37617 // views.. should not be just added - used named prop 'view''
37619 cfg.el = this.el.appendChild(document.createElement("div"));
37622 var ret = new Roo.factory(cfg);
37624 ret.render && ret.render(false, ''); // render blank..
37634 * @class Roo.bootstrap.panel.Grid
37635 * @extends Roo.bootstrap.panel.Content
37637 * Create a new GridPanel.
37638 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37639 * @param {Object} config A the config object
37645 Roo.bootstrap.panel.Grid = function(config)
37649 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37650 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37652 config.el = this.wrapper;
37653 //this.el = this.wrapper;
37655 if (config.container) {
37656 // ctor'ed from a Border/panel.grid
37659 this.wrapper.setStyle("overflow", "hidden");
37660 this.wrapper.addClass('roo-grid-container');
37665 if(config.toolbar){
37666 var tool_el = this.wrapper.createChild();
37667 this.toolbar = Roo.factory(config.toolbar);
37669 if (config.toolbar.items) {
37670 ti = config.toolbar.items ;
37671 delete config.toolbar.items ;
37675 this.toolbar.render(tool_el);
37676 for(var i =0;i < ti.length;i++) {
37677 // Roo.log(['add child', items[i]]);
37678 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37680 this.toolbar.items = nitems;
37682 delete config.toolbar;
37685 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37686 config.grid.scrollBody = true;;
37687 config.grid.monitorWindowResize = false; // turn off autosizing
37688 config.grid.autoHeight = false;
37689 config.grid.autoWidth = false;
37691 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37693 if (config.background) {
37694 // render grid on panel activation (if panel background)
37695 this.on('activate', function(gp) {
37696 if (!gp.grid.rendered) {
37697 gp.grid.render(this.wrapper);
37698 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37703 this.grid.render(this.wrapper);
37704 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37707 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37708 // ??? needed ??? config.el = this.wrapper;
37713 // xtype created footer. - not sure if will work as we normally have to render first..
37714 if (this.footer && !this.footer.el && this.footer.xtype) {
37716 var ctr = this.grid.getView().getFooterPanel(true);
37717 this.footer.dataSource = this.grid.dataSource;
37718 this.footer = Roo.factory(this.footer, Roo);
37719 this.footer.render(ctr);
37729 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37730 getId : function(){
37731 return this.grid.id;
37735 * Returns the grid for this panel
37736 * @return {Roo.bootstrap.Table}
37738 getGrid : function(){
37742 setSize : function(width, height){
37743 if(!this.ignoreResize(width, height)){
37744 var grid = this.grid;
37745 var size = this.adjustForComponents(width, height);
37746 var gridel = grid.getGridEl();
37747 gridel.setSize(size.width, size.height);
37749 var thd = grid.getGridEl().select('thead',true).first();
37750 var tbd = grid.getGridEl().select('tbody', true).first();
37752 tbd.setSize(width, height - thd.getHeight());
37761 beforeSlide : function(){
37762 this.grid.getView().scroller.clip();
37765 afterSlide : function(){
37766 this.grid.getView().scroller.unclip();
37769 destroy : function(){
37770 this.grid.destroy();
37772 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37777 * @class Roo.bootstrap.panel.Nest
37778 * @extends Roo.bootstrap.panel.Content
37780 * Create a new Panel, that can contain a layout.Border.
37783 * @param {Roo.BorderLayout} layout The layout for this panel
37784 * @param {String/Object} config A string to set only the title or a config object
37786 Roo.bootstrap.panel.Nest = function(config)
37788 // construct with only one argument..
37789 /* FIXME - implement nicer consturctors
37790 if (layout.layout) {
37792 layout = config.layout;
37793 delete config.layout;
37795 if (layout.xtype && !layout.getEl) {
37796 // then layout needs constructing..
37797 layout = Roo.factory(layout, Roo);
37801 config.el = config.layout.getEl();
37803 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37805 config.layout.monitorWindowResize = false; // turn off autosizing
37806 this.layout = config.layout;
37807 this.layout.getEl().addClass("roo-layout-nested-layout");
37814 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37816 setSize : function(width, height){
37817 if(!this.ignoreResize(width, height)){
37818 var size = this.adjustForComponents(width, height);
37819 var el = this.layout.getEl();
37820 if (size.height < 1) {
37821 el.setWidth(size.width);
37823 el.setSize(size.width, size.height);
37825 var touch = el.dom.offsetWidth;
37826 this.layout.layout();
37827 // ie requires a double layout on the first pass
37828 if(Roo.isIE && !this.initialized){
37829 this.initialized = true;
37830 this.layout.layout();
37835 // activate all subpanels if not currently active..
37837 setActiveState : function(active){
37838 this.active = active;
37839 this.setActiveClass(active);
37842 this.fireEvent("deactivate", this);
37846 this.fireEvent("activate", this);
37847 // not sure if this should happen before or after..
37848 if (!this.layout) {
37849 return; // should not happen..
37852 for (var r in this.layout.regions) {
37853 reg = this.layout.getRegion(r);
37854 if (reg.getActivePanel()) {
37855 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37856 reg.setActivePanel(reg.getActivePanel());
37859 if (!reg.panels.length) {
37862 reg.showPanel(reg.getPanel(0));
37871 * Returns the nested BorderLayout for this panel
37872 * @return {Roo.BorderLayout}
37874 getLayout : function(){
37875 return this.layout;
37879 * Adds a xtype elements to the layout of the nested panel
37883 xtype : 'ContentPanel',
37890 xtype : 'NestedLayoutPanel',
37896 items : [ ... list of content panels or nested layout panels.. ]
37900 * @param {Object} cfg Xtype definition of item to add.
37902 addxtype : function(cfg) {
37903 return this.layout.addxtype(cfg);
37908 * Ext JS Library 1.1.1
37909 * Copyright(c) 2006-2007, Ext JS, LLC.
37911 * Originally Released Under LGPL - original licence link has changed is not relivant.
37914 * <script type="text/javascript">
37917 * @class Roo.TabPanel
37918 * @extends Roo.util.Observable
37919 * A lightweight tab container.
37923 // basic tabs 1, built from existing content
37924 var tabs = new Roo.TabPanel("tabs1");
37925 tabs.addTab("script", "View Script");
37926 tabs.addTab("markup", "View Markup");
37927 tabs.activate("script");
37929 // more advanced tabs, built from javascript
37930 var jtabs = new Roo.TabPanel("jtabs");
37931 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
37933 // set up the UpdateManager
37934 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
37935 var updater = tab2.getUpdateManager();
37936 updater.setDefaultUrl("ajax1.htm");
37937 tab2.on('activate', updater.refresh, updater, true);
37939 // Use setUrl for Ajax loading
37940 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
37941 tab3.setUrl("ajax2.htm", null, true);
37944 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
37947 jtabs.activate("jtabs-1");
37950 * Create a new TabPanel.
37951 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
37952 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
37954 Roo.bootstrap.panel.Tabs = function(config){
37956 * The container element for this TabPanel.
37957 * @type Roo.Element
37959 this.el = Roo.get(config.el);
37962 if(typeof config == "boolean"){
37963 this.tabPosition = config ? "bottom" : "top";
37965 Roo.apply(this, config);
37969 if(this.tabPosition == "bottom"){
37970 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37971 this.el.addClass("roo-tabs-bottom");
37973 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
37974 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
37975 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
37976 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
37978 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
37980 if(this.tabPosition != "bottom"){
37981 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
37982 * @type Roo.Element
37984 this.bodyEl = Roo.get(this.createBody(this.el.dom));
37985 this.el.addClass("roo-tabs-top");
37989 this.bodyEl.setStyle("position", "relative");
37991 this.active = null;
37992 this.activateDelegate = this.activate.createDelegate(this);
37997 * Fires when the active tab changes
37998 * @param {Roo.TabPanel} this
37999 * @param {Roo.TabPanelItem} activePanel The new active tab
38003 * @event beforetabchange
38004 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38005 * @param {Roo.TabPanel} this
38006 * @param {Object} e Set cancel to true on this object to cancel the tab change
38007 * @param {Roo.TabPanelItem} tab The tab being changed to
38009 "beforetabchange" : true
38012 Roo.EventManager.onWindowResize(this.onResize, this);
38013 this.cpad = this.el.getPadding("lr");
38014 this.hiddenCount = 0;
38017 // toolbar on the tabbar support...
38018 if (this.toolbar) {
38019 alert("no toolbar support yet");
38020 this.toolbar = false;
38022 var tcfg = this.toolbar;
38023 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38024 this.toolbar = new Roo.Toolbar(tcfg);
38025 if (Roo.isSafari) {
38026 var tbl = tcfg.container.child('table', true);
38027 tbl.setAttribute('width', '100%');
38035 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38038 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38040 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38042 tabPosition : "top",
38044 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38046 currentTabWidth : 0,
38048 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38052 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38056 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38058 preferredTabWidth : 175,
38060 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38062 resizeTabs : false,
38064 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38066 monitorResize : true,
38068 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38073 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38074 * @param {String} id The id of the div to use <b>or create</b>
38075 * @param {String} text The text for the tab
38076 * @param {String} content (optional) Content to put in the TabPanelItem body
38077 * @param {Boolean} closable (optional) True to create a close icon on the tab
38078 * @return {Roo.TabPanelItem} The created TabPanelItem
38080 addTab : function(id, text, content, closable, tpl)
38082 var item = new Roo.bootstrap.panel.TabItem({
38086 closable : closable,
38089 this.addTabItem(item);
38091 item.setContent(content);
38097 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38098 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38099 * @return {Roo.TabPanelItem}
38101 getTab : function(id){
38102 return this.items[id];
38106 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38107 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38109 hideTab : function(id){
38110 var t = this.items[id];
38113 this.hiddenCount++;
38114 this.autoSizeTabs();
38119 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38120 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38122 unhideTab : function(id){
38123 var t = this.items[id];
38125 t.setHidden(false);
38126 this.hiddenCount--;
38127 this.autoSizeTabs();
38132 * Adds an existing {@link Roo.TabPanelItem}.
38133 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38135 addTabItem : function(item)
38137 this.items[item.id] = item;
38138 this.items.push(item);
38139 this.autoSizeTabs();
38140 // if(this.resizeTabs){
38141 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38142 // this.autoSizeTabs();
38144 // item.autoSize();
38149 * Removes a {@link Roo.TabPanelItem}.
38150 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38152 removeTab : function(id){
38153 var items = this.items;
38154 var tab = items[id];
38155 if(!tab) { return; }
38156 var index = items.indexOf(tab);
38157 if(this.active == tab && items.length > 1){
38158 var newTab = this.getNextAvailable(index);
38163 this.stripEl.dom.removeChild(tab.pnode.dom);
38164 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38165 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38167 items.splice(index, 1);
38168 delete this.items[tab.id];
38169 tab.fireEvent("close", tab);
38170 tab.purgeListeners();
38171 this.autoSizeTabs();
38174 getNextAvailable : function(start){
38175 var items = this.items;
38177 // look for a next tab that will slide over to
38178 // replace the one being removed
38179 while(index < items.length){
38180 var item = items[++index];
38181 if(item && !item.isHidden()){
38185 // if one isn't found select the previous tab (on the left)
38188 var item = items[--index];
38189 if(item && !item.isHidden()){
38197 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38198 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38200 disableTab : function(id){
38201 var tab = this.items[id];
38202 if(tab && this.active != tab){
38208 * Enables a {@link Roo.TabPanelItem} that is disabled.
38209 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38211 enableTab : function(id){
38212 var tab = this.items[id];
38217 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38218 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38219 * @return {Roo.TabPanelItem} The TabPanelItem.
38221 activate : function(id)
38223 var tab = this.items[id];
38227 if(tab == this.active || tab.disabled){
38231 this.fireEvent("beforetabchange", this, e, tab);
38232 if(e.cancel !== true && !tab.disabled){
38234 this.active.hide();
38236 this.active = this.items[id];
38237 this.active.show();
38238 this.fireEvent("tabchange", this, this.active);
38244 * Gets the active {@link Roo.TabPanelItem}.
38245 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38247 getActiveTab : function(){
38248 return this.active;
38252 * Updates the tab body element to fit the height of the container element
38253 * for overflow scrolling
38254 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38256 syncHeight : function(targetHeight){
38257 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38258 var bm = this.bodyEl.getMargins();
38259 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38260 this.bodyEl.setHeight(newHeight);
38264 onResize : function(){
38265 if(this.monitorResize){
38266 this.autoSizeTabs();
38271 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38273 beginUpdate : function(){
38274 this.updating = true;
38278 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38280 endUpdate : function(){
38281 this.updating = false;
38282 this.autoSizeTabs();
38286 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38288 autoSizeTabs : function()
38290 var count = this.items.length;
38291 var vcount = count - this.hiddenCount;
38294 this.stripEl.hide();
38296 this.stripEl.show();
38299 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38304 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38305 var availWidth = Math.floor(w / vcount);
38306 var b = this.stripBody;
38307 if(b.getWidth() > w){
38308 var tabs = this.items;
38309 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38310 if(availWidth < this.minTabWidth){
38311 /*if(!this.sleft){ // incomplete scrolling code
38312 this.createScrollButtons();
38315 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38318 if(this.currentTabWidth < this.preferredTabWidth){
38319 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38325 * Returns the number of tabs in this TabPanel.
38328 getCount : function(){
38329 return this.items.length;
38333 * Resizes all the tabs to the passed width
38334 * @param {Number} The new width
38336 setTabWidth : function(width){
38337 this.currentTabWidth = width;
38338 for(var i = 0, len = this.items.length; i < len; i++) {
38339 if(!this.items[i].isHidden()) {
38340 this.items[i].setWidth(width);
38346 * Destroys this TabPanel
38347 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38349 destroy : function(removeEl){
38350 Roo.EventManager.removeResizeListener(this.onResize, this);
38351 for(var i = 0, len = this.items.length; i < len; i++){
38352 this.items[i].purgeListeners();
38354 if(removeEl === true){
38355 this.el.update("");
38360 createStrip : function(container)
38362 var strip = document.createElement("nav");
38363 strip.className = Roo.bootstrap.version == 4 ?
38364 "navbar-light bg-light" :
38365 "navbar navbar-default"; //"x-tabs-wrap";
38366 container.appendChild(strip);
38370 createStripList : function(strip)
38372 // div wrapper for retard IE
38373 // returns the "tr" element.
38374 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38375 //'<div class="x-tabs-strip-wrap">'+
38376 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38377 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38378 return strip.firstChild; //.firstChild.firstChild.firstChild;
38380 createBody : function(container)
38382 var body = document.createElement("div");
38383 Roo.id(body, "tab-body");
38384 //Roo.fly(body).addClass("x-tabs-body");
38385 Roo.fly(body).addClass("tab-content");
38386 container.appendChild(body);
38389 createItemBody :function(bodyEl, id){
38390 var body = Roo.getDom(id);
38392 body = document.createElement("div");
38395 //Roo.fly(body).addClass("x-tabs-item-body");
38396 Roo.fly(body).addClass("tab-pane");
38397 bodyEl.insertBefore(body, bodyEl.firstChild);
38401 createStripElements : function(stripEl, text, closable, tpl)
38403 var td = document.createElement("li"); // was td..
38404 td.className = 'nav-item';
38406 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38409 stripEl.appendChild(td);
38411 td.className = "x-tabs-closable";
38412 if(!this.closeTpl){
38413 this.closeTpl = new Roo.Template(
38414 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38415 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38416 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38419 var el = this.closeTpl.overwrite(td, {"text": text});
38420 var close = el.getElementsByTagName("div")[0];
38421 var inner = el.getElementsByTagName("em")[0];
38422 return {"el": el, "close": close, "inner": inner};
38425 // not sure what this is..
38426 // if(!this.tabTpl){
38427 //this.tabTpl = new Roo.Template(
38428 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38429 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38431 // this.tabTpl = new Roo.Template(
38432 // '<a href="#">' +
38433 // '<span unselectable="on"' +
38434 // (this.disableTooltips ? '' : ' title="{text}"') +
38435 // ' >{text}</span></a>'
38441 var template = tpl || this.tabTpl || false;
38444 template = new Roo.Template(
38445 Roo.bootstrap.version == 4 ?
38447 '<a class="nav-link" href="#" unselectable="on"' +
38448 (this.disableTooltips ? '' : ' title="{text}"') +
38451 '<a class="nav-link" href="#">' +
38452 '<span unselectable="on"' +
38453 (this.disableTooltips ? '' : ' title="{text}"') +
38454 ' >{text}</span></a>'
38459 switch (typeof(template)) {
38463 template = new Roo.Template(template);
38469 var el = template.overwrite(td, {"text": text});
38471 var inner = el.getElementsByTagName("span")[0];
38473 return {"el": el, "inner": inner};
38481 * @class Roo.TabPanelItem
38482 * @extends Roo.util.Observable
38483 * Represents an individual item (tab plus body) in a TabPanel.
38484 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38485 * @param {String} id The id of this TabPanelItem
38486 * @param {String} text The text for the tab of this TabPanelItem
38487 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38489 Roo.bootstrap.panel.TabItem = function(config){
38491 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38492 * @type Roo.TabPanel
38494 this.tabPanel = config.panel;
38496 * The id for this TabPanelItem
38499 this.id = config.id;
38501 this.disabled = false;
38503 this.text = config.text;
38505 this.loaded = false;
38506 this.closable = config.closable;
38509 * The body element for this TabPanelItem.
38510 * @type Roo.Element
38512 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38513 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38514 this.bodyEl.setStyle("display", "block");
38515 this.bodyEl.setStyle("zoom", "1");
38516 //this.hideAction();
38518 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38520 this.el = Roo.get(els.el);
38521 this.inner = Roo.get(els.inner, true);
38522 this.textEl = Roo.bootstrap.version == 4 ?
38523 this.el : Roo.get(this.el.dom.firstChild, true);
38525 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38526 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38529 // this.el.on("mousedown", this.onTabMouseDown, this);
38530 this.el.on("click", this.onTabClick, this);
38532 if(config.closable){
38533 var c = Roo.get(els.close, true);
38534 c.dom.title = this.closeText;
38535 c.addClassOnOver("close-over");
38536 c.on("click", this.closeClick, this);
38542 * Fires when this tab becomes the active tab.
38543 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38544 * @param {Roo.TabPanelItem} this
38548 * @event beforeclose
38549 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38550 * @param {Roo.TabPanelItem} this
38551 * @param {Object} e Set cancel to true on this object to cancel the close.
38553 "beforeclose": true,
38556 * Fires when this tab is closed.
38557 * @param {Roo.TabPanelItem} this
38561 * @event deactivate
38562 * Fires when this tab is no longer the active tab.
38563 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38564 * @param {Roo.TabPanelItem} this
38566 "deactivate" : true
38568 this.hidden = false;
38570 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38573 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38575 purgeListeners : function(){
38576 Roo.util.Observable.prototype.purgeListeners.call(this);
38577 this.el.removeAllListeners();
38580 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38583 this.status_node.addClass("active");
38586 this.tabPanel.stripWrap.repaint();
38588 this.fireEvent("activate", this.tabPanel, this);
38592 * Returns true if this tab is the active tab.
38593 * @return {Boolean}
38595 isActive : function(){
38596 return this.tabPanel.getActiveTab() == this;
38600 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38603 this.status_node.removeClass("active");
38605 this.fireEvent("deactivate", this.tabPanel, this);
38608 hideAction : function(){
38609 this.bodyEl.hide();
38610 this.bodyEl.setStyle("position", "absolute");
38611 this.bodyEl.setLeft("-20000px");
38612 this.bodyEl.setTop("-20000px");
38615 showAction : function(){
38616 this.bodyEl.setStyle("position", "relative");
38617 this.bodyEl.setTop("");
38618 this.bodyEl.setLeft("");
38619 this.bodyEl.show();
38623 * Set the tooltip for the tab.
38624 * @param {String} tooltip The tab's tooltip
38626 setTooltip : function(text){
38627 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38628 this.textEl.dom.qtip = text;
38629 this.textEl.dom.removeAttribute('title');
38631 this.textEl.dom.title = text;
38635 onTabClick : function(e){
38636 e.preventDefault();
38637 this.tabPanel.activate(this.id);
38640 onTabMouseDown : function(e){
38641 e.preventDefault();
38642 this.tabPanel.activate(this.id);
38645 getWidth : function(){
38646 return this.inner.getWidth();
38649 setWidth : function(width){
38650 var iwidth = width - this.linode.getPadding("lr");
38651 this.inner.setWidth(iwidth);
38652 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38653 this.linode.setWidth(width);
38657 * Show or hide the tab
38658 * @param {Boolean} hidden True to hide or false to show.
38660 setHidden : function(hidden){
38661 this.hidden = hidden;
38662 this.linode.setStyle("display", hidden ? "none" : "");
38666 * Returns true if this tab is "hidden"
38667 * @return {Boolean}
38669 isHidden : function(){
38670 return this.hidden;
38674 * Returns the text for this tab
38677 getText : function(){
38681 autoSize : function(){
38682 //this.el.beginMeasure();
38683 this.textEl.setWidth(1);
38685 * #2804 [new] Tabs in Roojs
38686 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38688 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38689 //this.el.endMeasure();
38693 * Sets the text for the tab (Note: this also sets the tooltip text)
38694 * @param {String} text The tab's text and tooltip
38696 setText : function(text){
38698 this.textEl.update(text);
38699 this.setTooltip(text);
38700 //if(!this.tabPanel.resizeTabs){
38701 // this.autoSize();
38705 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38707 activate : function(){
38708 this.tabPanel.activate(this.id);
38712 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38714 disable : function(){
38715 if(this.tabPanel.active != this){
38716 this.disabled = true;
38717 this.status_node.addClass("disabled");
38722 * Enables this TabPanelItem if it was previously disabled.
38724 enable : function(){
38725 this.disabled = false;
38726 this.status_node.removeClass("disabled");
38730 * Sets the content for this TabPanelItem.
38731 * @param {String} content The content
38732 * @param {Boolean} loadScripts true to look for and load scripts
38734 setContent : function(content, loadScripts){
38735 this.bodyEl.update(content, loadScripts);
38739 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38740 * @return {Roo.UpdateManager} The UpdateManager
38742 getUpdateManager : function(){
38743 return this.bodyEl.getUpdateManager();
38747 * Set a URL to be used to load the content for this TabPanelItem.
38748 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38749 * @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)
38750 * @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)
38751 * @return {Roo.UpdateManager} The UpdateManager
38753 setUrl : function(url, params, loadOnce){
38754 if(this.refreshDelegate){
38755 this.un('activate', this.refreshDelegate);
38757 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38758 this.on("activate", this.refreshDelegate);
38759 return this.bodyEl.getUpdateManager();
38763 _handleRefresh : function(url, params, loadOnce){
38764 if(!loadOnce || !this.loaded){
38765 var updater = this.bodyEl.getUpdateManager();
38766 updater.update(url, params, this._setLoaded.createDelegate(this));
38771 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38772 * Will fail silently if the setUrl method has not been called.
38773 * This does not activate the panel, just updates its content.
38775 refresh : function(){
38776 if(this.refreshDelegate){
38777 this.loaded = false;
38778 this.refreshDelegate();
38783 _setLoaded : function(){
38784 this.loaded = true;
38788 closeClick : function(e){
38791 this.fireEvent("beforeclose", this, o);
38792 if(o.cancel !== true){
38793 this.tabPanel.removeTab(this.id);
38797 * The text displayed in the tooltip for the close icon.
38800 closeText : "Close this tab"
38803 * This script refer to:
38804 * Title: International Telephone Input
38805 * Author: Jack O'Connor
38806 * Code version: v12.1.12
38807 * Availability: https://github.com/jackocnr/intl-tel-input.git
38810 Roo.bootstrap.PhoneInputData = function() {
38813 "Afghanistan (افغانستان)",
38818 "Albania (Shqipëri)",
38823 "Algeria (الجزائر)",
38848 "Antigua and Barbuda",
38858 "Armenia (Հայաստան)",
38874 "Austria (Österreich)",
38879 "Azerbaijan (Azərbaycan)",
38889 "Bahrain (البحرين)",
38894 "Bangladesh (বাংলাদেশ)",
38904 "Belarus (Беларусь)",
38909 "Belgium (België)",
38939 "Bosnia and Herzegovina (Босна и Херцеговина)",
38954 "British Indian Ocean Territory",
38959 "British Virgin Islands",
38969 "Bulgaria (България)",
38979 "Burundi (Uburundi)",
38984 "Cambodia (កម្ពុជា)",
38989 "Cameroon (Cameroun)",
38998 ["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"]
39001 "Cape Verde (Kabu Verdi)",
39006 "Caribbean Netherlands",
39017 "Central African Republic (République centrafricaine)",
39037 "Christmas Island",
39043 "Cocos (Keeling) Islands",
39054 "Comoros (جزر القمر)",
39059 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39064 "Congo (Republic) (Congo-Brazzaville)",
39084 "Croatia (Hrvatska)",
39105 "Czech Republic (Česká republika)",
39110 "Denmark (Danmark)",
39125 "Dominican Republic (República Dominicana)",
39129 ["809", "829", "849"]
39147 "Equatorial Guinea (Guinea Ecuatorial)",
39167 "Falkland Islands (Islas Malvinas)",
39172 "Faroe Islands (Føroyar)",
39193 "French Guiana (Guyane française)",
39198 "French Polynesia (Polynésie française)",
39213 "Georgia (საქართველო)",
39218 "Germany (Deutschland)",
39238 "Greenland (Kalaallit Nunaat)",
39275 "Guinea-Bissau (Guiné Bissau)",
39300 "Hungary (Magyarország)",
39305 "Iceland (Ísland)",
39325 "Iraq (العراق)",
39341 "Israel (ישראל)",
39368 "Jordan (الأردن)",
39373 "Kazakhstan (Казахстан)",
39394 "Kuwait (الكويت)",
39399 "Kyrgyzstan (Кыргызстан)",
39409 "Latvia (Latvija)",
39414 "Lebanon (لبنان)",
39429 "Libya (ليبيا)",
39439 "Lithuania (Lietuva)",
39454 "Macedonia (FYROM) (Македонија)",
39459 "Madagascar (Madagasikara)",
39489 "Marshall Islands",
39499 "Mauritania (موريتانيا)",
39504 "Mauritius (Moris)",
39525 "Moldova (Republica Moldova)",
39535 "Mongolia (Монгол)",
39540 "Montenegro (Crna Gora)",
39550 "Morocco (المغرب)",
39556 "Mozambique (Moçambique)",
39561 "Myanmar (Burma) (မြန်မာ)",
39566 "Namibia (Namibië)",
39581 "Netherlands (Nederland)",
39586 "New Caledonia (Nouvelle-Calédonie)",
39621 "North Korea (조선 민주주의 인민 공화국)",
39626 "Northern Mariana Islands",
39642 "Pakistan (پاکستان)",
39652 "Palestine (فلسطين)",
39662 "Papua New Guinea",
39704 "Réunion (La Réunion)",
39710 "Romania (România)",
39726 "Saint Barthélemy",
39737 "Saint Kitts and Nevis",
39747 "Saint Martin (Saint-Martin (partie française))",
39753 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39758 "Saint Vincent and the Grenadines",
39773 "São Tomé and Príncipe (São Tomé e Príncipe)",
39778 "Saudi Arabia (المملكة العربية السعودية)",
39783 "Senegal (Sénégal)",
39813 "Slovakia (Slovensko)",
39818 "Slovenia (Slovenija)",
39828 "Somalia (Soomaaliya)",
39838 "South Korea (대한민국)",
39843 "South Sudan (جنوب السودان)",
39853 "Sri Lanka (ශ්රී ලංකාව)",
39858 "Sudan (السودان)",
39868 "Svalbard and Jan Mayen",
39879 "Sweden (Sverige)",
39884 "Switzerland (Schweiz)",
39889 "Syria (سوريا)",
39934 "Trinidad and Tobago",
39939 "Tunisia (تونس)",
39944 "Turkey (Türkiye)",
39954 "Turks and Caicos Islands",
39964 "U.S. Virgin Islands",
39974 "Ukraine (Україна)",
39979 "United Arab Emirates (الإمارات العربية المتحدة)",
40001 "Uzbekistan (Oʻzbekiston)",
40011 "Vatican City (Città del Vaticano)",
40022 "Vietnam (Việt Nam)",
40027 "Wallis and Futuna (Wallis-et-Futuna)",
40032 "Western Sahara (الصحراء الغربية)",
40038 "Yemen (اليمن)",
40062 * This script refer to:
40063 * Title: International Telephone Input
40064 * Author: Jack O'Connor
40065 * Code version: v12.1.12
40066 * Availability: https://github.com/jackocnr/intl-tel-input.git
40070 * @class Roo.bootstrap.PhoneInput
40071 * @extends Roo.bootstrap.TriggerField
40072 * An input with International dial-code selection
40074 * @cfg {String} defaultDialCode default '+852'
40075 * @cfg {Array} preferedCountries default []
40078 * Create a new PhoneInput.
40079 * @param {Object} config Configuration options
40082 Roo.bootstrap.PhoneInput = function(config) {
40083 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40086 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40088 listWidth: undefined,
40090 selectedClass: 'active',
40092 invalidClass : "has-warning",
40094 validClass: 'has-success',
40096 allowed: '0123456789',
40101 * @cfg {String} defaultDialCode The default dial code when initializing the input
40103 defaultDialCode: '+852',
40106 * @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
40108 preferedCountries: false,
40110 getAutoCreate : function()
40112 var data = Roo.bootstrap.PhoneInputData();
40113 var align = this.labelAlign || this.parentLabelAlign();
40116 this.allCountries = [];
40117 this.dialCodeMapping = [];
40119 for (var i = 0; i < data.length; i++) {
40121 this.allCountries[i] = {
40125 priority: c[3] || 0,
40126 areaCodes: c[4] || null
40128 this.dialCodeMapping[c[2]] = {
40131 priority: c[3] || 0,
40132 areaCodes: c[4] || null
40144 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40145 maxlength: this.max_length,
40146 cls : 'form-control tel-input',
40147 autocomplete: 'new-password'
40150 var hiddenInput = {
40153 cls: 'hidden-tel-input'
40157 hiddenInput.name = this.name;
40160 if (this.disabled) {
40161 input.disabled = true;
40164 var flag_container = {
40181 cls: this.hasFeedback ? 'has-feedback' : '',
40187 cls: 'dial-code-holder',
40194 cls: 'roo-select2-container input-group',
40201 if (this.fieldLabel.length) {
40204 tooltip: 'This field is required'
40210 cls: 'control-label',
40216 html: this.fieldLabel
40219 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40225 if(this.indicatorpos == 'right') {
40226 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40233 if(align == 'left') {
40241 if(this.labelWidth > 12){
40242 label.style = "width: " + this.labelWidth + 'px';
40244 if(this.labelWidth < 13 && this.labelmd == 0){
40245 this.labelmd = this.labelWidth;
40247 if(this.labellg > 0){
40248 label.cls += ' col-lg-' + this.labellg;
40249 input.cls += ' col-lg-' + (12 - this.labellg);
40251 if(this.labelmd > 0){
40252 label.cls += ' col-md-' + this.labelmd;
40253 container.cls += ' col-md-' + (12 - this.labelmd);
40255 if(this.labelsm > 0){
40256 label.cls += ' col-sm-' + this.labelsm;
40257 container.cls += ' col-sm-' + (12 - this.labelsm);
40259 if(this.labelxs > 0){
40260 label.cls += ' col-xs-' + this.labelxs;
40261 container.cls += ' col-xs-' + (12 - this.labelxs);
40271 var settings = this;
40273 ['xs','sm','md','lg'].map(function(size){
40274 if (settings[size]) {
40275 cfg.cls += ' col-' + size + '-' + settings[size];
40279 this.store = new Roo.data.Store({
40280 proxy : new Roo.data.MemoryProxy({}),
40281 reader : new Roo.data.JsonReader({
40292 'name' : 'dialCode',
40296 'name' : 'priority',
40300 'name' : 'areaCodes',
40307 if(!this.preferedCountries) {
40308 this.preferedCountries = [
40315 var p = this.preferedCountries.reverse();
40318 for (var i = 0; i < p.length; i++) {
40319 for (var j = 0; j < this.allCountries.length; j++) {
40320 if(this.allCountries[j].iso2 == p[i]) {
40321 var t = this.allCountries[j];
40322 this.allCountries.splice(j,1);
40323 this.allCountries.unshift(t);
40329 this.store.proxy.data = {
40331 data: this.allCountries
40337 initEvents : function()
40340 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40342 this.indicator = this.indicatorEl();
40343 this.flag = this.flagEl();
40344 this.dialCodeHolder = this.dialCodeHolderEl();
40346 this.trigger = this.el.select('div.flag-box',true).first();
40347 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40352 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40353 _this.list.setWidth(lw);
40356 this.list.on('mouseover', this.onViewOver, this);
40357 this.list.on('mousemove', this.onViewMove, this);
40358 this.inputEl().on("keyup", this.onKeyUp, this);
40359 this.inputEl().on("keypress", this.onKeyPress, this);
40361 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40363 this.view = new Roo.View(this.list, this.tpl, {
40364 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40367 this.view.on('click', this.onViewClick, this);
40368 this.setValue(this.defaultDialCode);
40371 onTriggerClick : function(e)
40373 Roo.log('trigger click');
40378 if(this.isExpanded()){
40380 this.hasFocus = false;
40382 this.store.load({});
40383 this.hasFocus = true;
40388 isExpanded : function()
40390 return this.list.isVisible();
40393 collapse : function()
40395 if(!this.isExpanded()){
40399 Roo.get(document).un('mousedown', this.collapseIf, this);
40400 Roo.get(document).un('mousewheel', this.collapseIf, this);
40401 this.fireEvent('collapse', this);
40405 expand : function()
40409 if(this.isExpanded() || !this.hasFocus){
40413 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40414 this.list.setWidth(lw);
40417 this.restrictHeight();
40419 Roo.get(document).on('mousedown', this.collapseIf, this);
40420 Roo.get(document).on('mousewheel', this.collapseIf, this);
40422 this.fireEvent('expand', this);
40425 restrictHeight : function()
40427 this.list.alignTo(this.inputEl(), this.listAlign);
40428 this.list.alignTo(this.inputEl(), this.listAlign);
40431 onViewOver : function(e, t)
40433 if(this.inKeyMode){
40436 var item = this.view.findItemFromChild(t);
40439 var index = this.view.indexOf(item);
40440 this.select(index, false);
40445 onViewClick : function(view, doFocus, el, e)
40447 var index = this.view.getSelectedIndexes()[0];
40449 var r = this.store.getAt(index);
40452 this.onSelect(r, index);
40454 if(doFocus !== false && !this.blockFocus){
40455 this.inputEl().focus();
40459 onViewMove : function(e, t)
40461 this.inKeyMode = false;
40464 select : function(index, scrollIntoView)
40466 this.selectedIndex = index;
40467 this.view.select(index);
40468 if(scrollIntoView !== false){
40469 var el = this.view.getNode(index);
40471 this.list.scrollChildIntoView(el, false);
40476 createList : function()
40478 this.list = Roo.get(document.body).createChild({
40480 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40481 style: 'display:none'
40484 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40487 collapseIf : function(e)
40489 var in_combo = e.within(this.el);
40490 var in_list = e.within(this.list);
40491 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40493 if (in_combo || in_list || is_list) {
40499 onSelect : function(record, index)
40501 if(this.fireEvent('beforeselect', this, record, index) !== false){
40503 this.setFlagClass(record.data.iso2);
40504 this.setDialCode(record.data.dialCode);
40505 this.hasFocus = false;
40507 this.fireEvent('select', this, record, index);
40511 flagEl : function()
40513 var flag = this.el.select('div.flag',true).first();
40520 dialCodeHolderEl : function()
40522 var d = this.el.select('input.dial-code-holder',true).first();
40529 setDialCode : function(v)
40531 this.dialCodeHolder.dom.value = '+'+v;
40534 setFlagClass : function(n)
40536 this.flag.dom.className = 'flag '+n;
40539 getValue : function()
40541 var v = this.inputEl().getValue();
40542 if(this.dialCodeHolder) {
40543 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40548 setValue : function(v)
40550 var d = this.getDialCode(v);
40552 //invalid dial code
40553 if(v.length == 0 || !d || d.length == 0) {
40555 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40556 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40562 this.setFlagClass(this.dialCodeMapping[d].iso2);
40563 this.setDialCode(d);
40564 this.inputEl().dom.value = v.replace('+'+d,'');
40565 this.hiddenEl().dom.value = this.getValue();
40570 getDialCode : function(v)
40574 if (v.length == 0) {
40575 return this.dialCodeHolder.dom.value;
40579 if (v.charAt(0) != "+") {
40582 var numericChars = "";
40583 for (var i = 1; i < v.length; i++) {
40584 var c = v.charAt(i);
40587 if (this.dialCodeMapping[numericChars]) {
40588 dialCode = v.substr(1, i);
40590 if (numericChars.length == 4) {
40600 this.setValue(this.defaultDialCode);
40604 hiddenEl : function()
40606 return this.el.select('input.hidden-tel-input',true).first();
40609 // after setting val
40610 onKeyUp : function(e){
40611 this.setValue(this.getValue());
40614 onKeyPress : function(e){
40615 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40622 * @class Roo.bootstrap.MoneyField
40623 * @extends Roo.bootstrap.ComboBox
40624 * Bootstrap MoneyField class
40627 * Create a new MoneyField.
40628 * @param {Object} config Configuration options
40631 Roo.bootstrap.MoneyField = function(config) {
40633 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40637 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40640 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40642 allowDecimals : true,
40644 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40646 decimalSeparator : ".",
40648 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40650 decimalPrecision : 0,
40652 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40654 allowNegative : true,
40656 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40660 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40662 minValue : Number.NEGATIVE_INFINITY,
40664 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40666 maxValue : Number.MAX_VALUE,
40668 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40670 minText : "The minimum value for this field is {0}",
40672 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40674 maxText : "The maximum value for this field is {0}",
40676 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40677 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40679 nanText : "{0} is not a valid number",
40681 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40685 * @cfg {String} defaults currency of the MoneyField
40686 * value should be in lkey
40688 defaultCurrency : false,
40690 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40692 thousandsDelimiter : false,
40694 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40705 getAutoCreate : function()
40707 var align = this.labelAlign || this.parentLabelAlign();
40719 cls : 'form-control roo-money-amount-input',
40720 autocomplete: 'new-password'
40723 var hiddenInput = {
40727 cls: 'hidden-number-input'
40730 if(this.max_length) {
40731 input.maxlength = this.max_length;
40735 hiddenInput.name = this.name;
40738 if (this.disabled) {
40739 input.disabled = true;
40742 var clg = 12 - this.inputlg;
40743 var cmd = 12 - this.inputmd;
40744 var csm = 12 - this.inputsm;
40745 var cxs = 12 - this.inputxs;
40749 cls : 'row roo-money-field',
40753 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40757 cls: 'roo-select2-container input-group',
40761 cls : 'form-control roo-money-currency-input',
40762 autocomplete: 'new-password',
40764 name : this.currencyName
40768 cls : 'input-group-addon',
40782 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40786 cls: this.hasFeedback ? 'has-feedback' : '',
40797 if (this.fieldLabel.length) {
40800 tooltip: 'This field is required'
40806 cls: 'control-label',
40812 html: this.fieldLabel
40815 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40821 if(this.indicatorpos == 'right') {
40822 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40829 if(align == 'left') {
40837 if(this.labelWidth > 12){
40838 label.style = "width: " + this.labelWidth + 'px';
40840 if(this.labelWidth < 13 && this.labelmd == 0){
40841 this.labelmd = this.labelWidth;
40843 if(this.labellg > 0){
40844 label.cls += ' col-lg-' + this.labellg;
40845 input.cls += ' col-lg-' + (12 - this.labellg);
40847 if(this.labelmd > 0){
40848 label.cls += ' col-md-' + this.labelmd;
40849 container.cls += ' col-md-' + (12 - this.labelmd);
40851 if(this.labelsm > 0){
40852 label.cls += ' col-sm-' + this.labelsm;
40853 container.cls += ' col-sm-' + (12 - this.labelsm);
40855 if(this.labelxs > 0){
40856 label.cls += ' col-xs-' + this.labelxs;
40857 container.cls += ' col-xs-' + (12 - this.labelxs);
40868 var settings = this;
40870 ['xs','sm','md','lg'].map(function(size){
40871 if (settings[size]) {
40872 cfg.cls += ' col-' + size + '-' + settings[size];
40879 initEvents : function()
40881 this.indicator = this.indicatorEl();
40883 this.initCurrencyEvent();
40885 this.initNumberEvent();
40888 initCurrencyEvent : function()
40891 throw "can not find store for combo";
40894 this.store = Roo.factory(this.store, Roo.data);
40895 this.store.parent = this;
40899 this.triggerEl = this.el.select('.input-group-addon', true).first();
40901 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
40906 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40907 _this.list.setWidth(lw);
40910 this.list.on('mouseover', this.onViewOver, this);
40911 this.list.on('mousemove', this.onViewMove, this);
40912 this.list.on('scroll', this.onViewScroll, this);
40915 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
40918 this.view = new Roo.View(this.list, this.tpl, {
40919 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40922 this.view.on('click', this.onViewClick, this);
40924 this.store.on('beforeload', this.onBeforeLoad, this);
40925 this.store.on('load', this.onLoad, this);
40926 this.store.on('loadexception', this.onLoadException, this);
40928 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
40929 "up" : function(e){
40930 this.inKeyMode = true;
40934 "down" : function(e){
40935 if(!this.isExpanded()){
40936 this.onTriggerClick();
40938 this.inKeyMode = true;
40943 "enter" : function(e){
40946 if(this.fireEvent("specialkey", this, e)){
40947 this.onViewClick(false);
40953 "esc" : function(e){
40957 "tab" : function(e){
40960 if(this.fireEvent("specialkey", this, e)){
40961 this.onViewClick(false);
40969 doRelay : function(foo, bar, hname){
40970 if(hname == 'down' || this.scope.isExpanded()){
40971 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
40979 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
40983 initNumberEvent : function(e)
40985 this.inputEl().on("keydown" , this.fireKey, this);
40986 this.inputEl().on("focus", this.onFocus, this);
40987 this.inputEl().on("blur", this.onBlur, this);
40989 this.inputEl().relayEvent('keyup', this);
40991 if(this.indicator){
40992 this.indicator.addClass('invisible');
40995 this.originalValue = this.getValue();
40997 if(this.validationEvent == 'keyup'){
40998 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
40999 this.inputEl().on('keyup', this.filterValidation, this);
41001 else if(this.validationEvent !== false){
41002 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41005 if(this.selectOnFocus){
41006 this.on("focus", this.preFocus, this);
41009 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41010 this.inputEl().on("keypress", this.filterKeys, this);
41012 this.inputEl().relayEvent('keypress', this);
41015 var allowed = "0123456789";
41017 if(this.allowDecimals){
41018 allowed += this.decimalSeparator;
41021 if(this.allowNegative){
41025 if(this.thousandsDelimiter) {
41029 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41031 var keyPress = function(e){
41033 var k = e.getKey();
41035 var c = e.getCharCode();
41038 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41039 allowed.indexOf(String.fromCharCode(c)) === -1
41045 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41049 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41054 this.inputEl().on("keypress", keyPress, this);
41058 onTriggerClick : function(e)
41065 this.loadNext = false;
41067 if(this.isExpanded()){
41072 this.hasFocus = true;
41074 if(this.triggerAction == 'all') {
41075 this.doQuery(this.allQuery, true);
41079 this.doQuery(this.getRawValue());
41082 getCurrency : function()
41084 var v = this.currencyEl().getValue();
41089 restrictHeight : function()
41091 this.list.alignTo(this.currencyEl(), this.listAlign);
41092 this.list.alignTo(this.currencyEl(), this.listAlign);
41095 onViewClick : function(view, doFocus, el, e)
41097 var index = this.view.getSelectedIndexes()[0];
41099 var r = this.store.getAt(index);
41102 this.onSelect(r, index);
41106 onSelect : function(record, index){
41108 if(this.fireEvent('beforeselect', this, record, index) !== false){
41110 this.setFromCurrencyData(index > -1 ? record.data : false);
41114 this.fireEvent('select', this, record, index);
41118 setFromCurrencyData : function(o)
41122 this.lastCurrency = o;
41124 if (this.currencyField) {
41125 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41127 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41130 this.lastSelectionText = currency;
41132 //setting default currency
41133 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41134 this.setCurrency(this.defaultCurrency);
41138 this.setCurrency(currency);
41141 setFromData : function(o)
41145 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41147 this.setFromCurrencyData(c);
41152 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41154 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41157 this.setValue(value);
41161 setCurrency : function(v)
41163 this.currencyValue = v;
41166 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41171 setValue : function(v)
41173 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41179 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41181 this.inputEl().dom.value = (v == '') ? '' :
41182 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41184 if(!this.allowZero && v === '0') {
41185 this.hiddenEl().dom.value = '';
41186 this.inputEl().dom.value = '';
41193 getRawValue : function()
41195 var v = this.inputEl().getValue();
41200 getValue : function()
41202 return this.fixPrecision(this.parseValue(this.getRawValue()));
41205 parseValue : function(value)
41207 if(this.thousandsDelimiter) {
41209 r = new RegExp(",", "g");
41210 value = value.replace(r, "");
41213 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41214 return isNaN(value) ? '' : value;
41218 fixPrecision : function(value)
41220 if(this.thousandsDelimiter) {
41222 r = new RegExp(",", "g");
41223 value = value.replace(r, "");
41226 var nan = isNaN(value);
41228 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41229 return nan ? '' : value;
41231 return parseFloat(value).toFixed(this.decimalPrecision);
41234 decimalPrecisionFcn : function(v)
41236 return Math.floor(v);
41239 validateValue : function(value)
41241 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41245 var num = this.parseValue(value);
41248 this.markInvalid(String.format(this.nanText, value));
41252 if(num < this.minValue){
41253 this.markInvalid(String.format(this.minText, this.minValue));
41257 if(num > this.maxValue){
41258 this.markInvalid(String.format(this.maxText, this.maxValue));
41265 validate : function()
41267 if(this.disabled || this.allowBlank){
41272 var currency = this.getCurrency();
41274 if(this.validateValue(this.getRawValue()) && currency.length){
41279 this.markInvalid();
41283 getName: function()
41288 beforeBlur : function()
41294 var v = this.parseValue(this.getRawValue());
41301 onBlur : function()
41305 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41306 //this.el.removeClass(this.focusClass);
41309 this.hasFocus = false;
41311 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41315 var v = this.getValue();
41317 if(String(v) !== String(this.startValue)){
41318 this.fireEvent('change', this, v, this.startValue);
41321 this.fireEvent("blur", this);
41324 inputEl : function()
41326 return this.el.select('.roo-money-amount-input', true).first();
41329 currencyEl : function()
41331 return this.el.select('.roo-money-currency-input', true).first();
41334 hiddenEl : function()
41336 return this.el.select('input.hidden-number-input',true).first();