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
2677 * Fire when the top 'x' close button is pressed.
2678 * @param {Roo.bootstrap.Modal} this
2679 * @param {Roo.EventObject} e
2683 this.buttons = this.buttons || [];
2686 this.tmpl = Roo.factory(this.tmpl);
2691 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2693 title : 'test dialog',
2703 specificTitle: false,
2705 buttonPosition: 'right',
2728 onRender : function(ct, position)
2730 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2733 var cfg = Roo.apply({}, this.getAutoCreate());
2736 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2738 //if (!cfg.name.length) {
2742 cfg.cls += ' ' + this.cls;
2745 cfg.style = this.style;
2747 this.el = Roo.get(document.body).createChild(cfg, position);
2749 //var type = this.el.dom.type;
2752 if(this.tabIndex !== undefined){
2753 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2756 this.dialogEl = this.el.select('.modal-dialog',true).first();
2757 this.bodyEl = this.el.select('.modal-body',true).first();
2758 this.closeEl = this.el.select('.modal-header .close', true).first();
2759 this.headerEl = this.el.select('.modal-header',true).first();
2760 this.titleEl = this.el.select('.modal-title',true).first();
2761 this.footerEl = this.el.select('.modal-footer',true).first();
2763 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2765 //this.el.addClass("x-dlg-modal");
2767 if (this.buttons.length) {
2768 Roo.each(this.buttons, function(bb) {
2769 var b = Roo.apply({}, bb);
2770 b.xns = b.xns || Roo.bootstrap;
2771 b.xtype = b.xtype || 'Button';
2772 if (typeof(b.listeners) == 'undefined') {
2773 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2776 var btn = Roo.factory(b);
2778 btn.render(this.getButtonContainer());
2782 // render the children.
2785 if(typeof(this.items) != 'undefined'){
2786 var items = this.items;
2789 for(var i =0;i < items.length;i++) {
2790 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2794 this.items = nitems;
2796 // where are these used - they used to be body/close/footer
2800 //this.el.addClass([this.fieldClass, this.cls]);
2804 getAutoCreate : function()
2808 html : this.html || ''
2813 cls : 'modal-title',
2817 if(this.specificTitle){
2823 if (this.allow_close && Roo.bootstrap.version == 3) {
2833 if (this.allow_close && Roo.bootstrap.version == 4) {
2843 if(this.size.length){
2844 size = 'modal-' + this.size;
2847 var footer = Roo.bootstrap.version == 3 ?
2849 cls : 'modal-footer',
2853 cls: 'btn-' + this.buttonPosition
2858 { // BS4 uses mr-auto on left buttons....
2859 cls : 'modal-footer'
2870 cls: "modal-dialog " + size,
2873 cls : "modal-content",
2876 cls : 'modal-header',
2891 modal.cls += ' fade';
2897 getChildContainer : function() {
2902 getButtonContainer : function() {
2904 return Roo.bootstrap.version == 4 ?
2905 this.el.select('.modal-footer',true).first()
2906 : this.el.select('.modal-footer div',true).first();
2909 initEvents : function()
2911 if (this.allow_close) {
2912 this.closeEl.on('click', this.hide, this);
2914 Roo.EventManager.onWindowResize(this.resize, this, true);
2922 this.maskEl.setSize(
2923 Roo.lib.Dom.getViewWidth(true),
2924 Roo.lib.Dom.getViewHeight(true)
2927 if (this.fitwindow) {
2931 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2932 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
2937 if(this.max_width !== 0) {
2939 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2942 this.setSize(w, this.height);
2946 if(this.max_height) {
2947 this.setSize(w,Math.min(
2949 Roo.lib.Dom.getViewportHeight(true) - 60
2955 if(!this.fit_content) {
2956 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2960 this.setSize(w, Math.min(
2962 this.headerEl.getHeight() +
2963 this.footerEl.getHeight() +
2964 this.getChildHeight(this.bodyEl.dom.childNodes),
2965 Roo.lib.Dom.getViewportHeight(true) - 60)
2971 setSize : function(w,h)
2982 if (!this.rendered) {
2986 //this.el.setStyle('display', 'block');
2987 this.el.removeClass('hideing');
2988 this.el.dom.style.display='block';
2990 Roo.get(document.body).addClass('modal-open');
2992 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2995 this.el.addClass('show');
2996 this.el.addClass('in');
2999 this.el.addClass('show');
3000 this.el.addClass('in');
3003 // not sure how we can show data in here..
3005 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3008 Roo.get(document.body).addClass("x-body-masked");
3010 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3011 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3012 this.maskEl.dom.style.display = 'block';
3013 this.maskEl.addClass('show');
3018 this.fireEvent('show', this);
3020 // set zindex here - otherwise it appears to be ignored...
3021 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3024 this.items.forEach( function(e) {
3025 e.layout ? e.layout() : false;
3033 if(this.fireEvent("beforehide", this) !== false){
3035 this.maskEl.removeClass('show');
3037 this.maskEl.dom.style.display = '';
3038 Roo.get(document.body).removeClass("x-body-masked");
3039 this.el.removeClass('in');
3040 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3042 if(this.animate){ // why
3043 this.el.addClass('hideing');
3044 this.el.removeClass('show');
3046 if (!this.el.hasClass('hideing')) {
3047 return; // it's been shown again...
3050 this.el.dom.style.display='';
3052 Roo.get(document.body).removeClass('modal-open');
3053 this.el.removeClass('hideing');
3057 this.el.removeClass('show');
3058 this.el.dom.style.display='';
3059 Roo.get(document.body).removeClass('modal-open');
3062 this.fireEvent('hide', this);
3065 isVisible : function()
3068 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3072 addButton : function(str, cb)
3076 var b = Roo.apply({}, { html : str } );
3077 b.xns = b.xns || Roo.bootstrap;
3078 b.xtype = b.xtype || 'Button';
3079 if (typeof(b.listeners) == 'undefined') {
3080 b.listeners = { click : cb.createDelegate(this) };
3083 var btn = Roo.factory(b);
3085 btn.render(this.getButtonContainer());
3091 setDefaultButton : function(btn)
3093 //this.el.select('.modal-footer').()
3096 resizeTo: function(w,h)
3098 this.dialogEl.setWidth(w);
3100 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
3102 this.bodyEl.setHeight(h - diff);
3104 this.fireEvent('resize', this);
3107 setContentSize : function(w, h)
3111 onButtonClick: function(btn,e)
3114 this.fireEvent('btnclick', btn.name, e);
3117 * Set the title of the Dialog
3118 * @param {String} str new Title
3120 setTitle: function(str) {
3121 this.titleEl.dom.innerHTML = str;
3124 * Set the body of the Dialog
3125 * @param {String} str new Title
3127 setBody: function(str) {
3128 this.bodyEl.dom.innerHTML = str;
3131 * Set the body of the Dialog using the template
3132 * @param {Obj} data - apply this data to the template and replace the body contents.
3134 applyBody: function(obj)
3137 Roo.log("Error - using apply Body without a template");
3140 this.tmpl.overwrite(this.bodyEl, obj);
3143 getChildHeight : function(child_nodes)
3147 child_nodes.length == 0
3152 var child_height = 0;
3154 for(var i = 0; i < child_nodes.length; i++) {
3157 * for modal with tabs...
3158 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3160 var layout_childs = child_nodes[i].childNodes;
3162 for(var j = 0; j < layout_childs.length; j++) {
3164 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3166 var layout_body_childs = layout_childs[j].childNodes;
3168 for(var k = 0; k < layout_body_childs.length; k++) {
3170 if(layout_body_childs[k].classList.contains('navbar')) {
3171 child_height += layout_body_childs[k].offsetHeight;
3175 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3177 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3179 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3181 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3182 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3197 child_height += child_nodes[i].offsetHeight;
3198 // Roo.log(child_nodes[i].offsetHeight);
3201 return child_height;
3207 Roo.apply(Roo.bootstrap.Modal, {
3209 * Button config that displays a single OK button
3218 * Button config that displays Yes and No buttons
3234 * Button config that displays OK and Cancel buttons
3249 * Button config that displays Yes, No and Cancel buttons
3273 * messagebox - can be used as a replace
3277 * @class Roo.MessageBox
3278 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3282 Roo.Msg.alert('Status', 'Changes saved successfully.');
3284 // Prompt for user data:
3285 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3287 // process text value...
3291 // Show a dialog using config options:
3293 title:'Save Changes?',
3294 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3295 buttons: Roo.Msg.YESNOCANCEL,
3302 Roo.bootstrap.MessageBox = function(){
3303 var dlg, opt, mask, waitTimer;
3304 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3305 var buttons, activeTextEl, bwidth;
3309 var handleButton = function(button){
3311 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3315 var handleHide = function(){
3317 dlg.el.removeClass(opt.cls);
3320 // Roo.TaskMgr.stop(waitTimer);
3321 // waitTimer = null;
3326 var updateButtons = function(b){
3329 buttons["ok"].hide();
3330 buttons["cancel"].hide();
3331 buttons["yes"].hide();
3332 buttons["no"].hide();
3333 dlg.footerEl.hide();
3337 dlg.footerEl.show();
3338 for(var k in buttons){
3339 if(typeof buttons[k] != "function"){
3342 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3343 width += buttons[k].el.getWidth()+15;
3353 var handleEsc = function(d, k, e){
3354 if(opt && opt.closable !== false){
3364 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3365 * @return {Roo.BasicDialog} The BasicDialog element
3367 getDialog : function(){
3369 dlg = new Roo.bootstrap.Modal( {
3372 //constraintoviewport:false,
3374 //collapsible : false,
3379 //buttonAlign:"center",
3380 closeClick : function(){
3381 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3384 handleButton("cancel");
3389 dlg.on("hide", handleHide);
3391 //dlg.addKeyListener(27, handleEsc);
3393 this.buttons = buttons;
3394 var bt = this.buttonText;
3395 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3396 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3397 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3398 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3400 bodyEl = dlg.bodyEl.createChild({
3402 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3403 '<textarea class="roo-mb-textarea"></textarea>' +
3404 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3406 msgEl = bodyEl.dom.firstChild;
3407 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3408 textboxEl.enableDisplayMode();
3409 textboxEl.addKeyListener([10,13], function(){
3410 if(dlg.isVisible() && opt && opt.buttons){
3413 }else if(opt.buttons.yes){
3414 handleButton("yes");
3418 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3419 textareaEl.enableDisplayMode();
3420 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3421 progressEl.enableDisplayMode();
3423 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3424 var pf = progressEl.dom.firstChild;
3426 pp = Roo.get(pf.firstChild);
3427 pp.setHeight(pf.offsetHeight);
3435 * Updates the message box body text
3436 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3437 * the XHTML-compliant non-breaking space character '&#160;')
3438 * @return {Roo.MessageBox} This message box
3440 updateText : function(text)
3442 if(!dlg.isVisible() && !opt.width){
3443 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3444 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3446 msgEl.innerHTML = text || ' ';
3448 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3449 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3451 Math.min(opt.width || cw , this.maxWidth),
3452 Math.max(opt.minWidth || this.minWidth, bwidth)
3455 activeTextEl.setWidth(w);
3457 if(dlg.isVisible()){
3458 dlg.fixedcenter = false;
3460 // to big, make it scroll. = But as usual stupid IE does not support
3463 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3464 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3465 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3467 bodyEl.dom.style.height = '';
3468 bodyEl.dom.style.overflowY = '';
3471 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3473 bodyEl.dom.style.overflowX = '';
3476 dlg.setContentSize(w, bodyEl.getHeight());
3477 if(dlg.isVisible()){
3478 dlg.fixedcenter = true;
3484 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3485 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3486 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3487 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3488 * @return {Roo.MessageBox} This message box
3490 updateProgress : function(value, text){
3492 this.updateText(text);
3495 if (pp) { // weird bug on my firefox - for some reason this is not defined
3496 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3497 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3503 * Returns true if the message box is currently displayed
3504 * @return {Boolean} True if the message box is visible, else false
3506 isVisible : function(){
3507 return dlg && dlg.isVisible();
3511 * Hides the message box if it is displayed
3514 if(this.isVisible()){
3520 * Displays a new message box, or reinitializes an existing message box, based on the config options
3521 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3522 * The following config object properties are supported:
3524 Property Type Description
3525 ---------- --------------- ------------------------------------------------------------------------------------
3526 animEl String/Element An id or Element from which the message box should animate as it opens and
3527 closes (defaults to undefined)
3528 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3529 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3530 closable Boolean False to hide the top-right close button (defaults to true). Note that
3531 progress and wait dialogs will ignore this property and always hide the
3532 close button as they can only be closed programmatically.
3533 cls String A custom CSS class to apply to the message box element
3534 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3535 displayed (defaults to 75)
3536 fn Function A callback function to execute after closing the dialog. The arguments to the
3537 function will be btn (the name of the button that was clicked, if applicable,
3538 e.g. "ok"), and text (the value of the active text field, if applicable).
3539 Progress and wait dialogs will ignore this option since they do not respond to
3540 user actions and can only be closed programmatically, so any required function
3541 should be called by the same code after it closes the dialog.
3542 icon String A CSS class that provides a background image to be used as an icon for
3543 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3544 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3545 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3546 modal Boolean False to allow user interaction with the page while the message box is
3547 displayed (defaults to true)
3548 msg String A string that will replace the existing message box body text (defaults
3549 to the XHTML-compliant non-breaking space character ' ')
3550 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3551 progress Boolean True to display a progress bar (defaults to false)
3552 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3553 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3554 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3555 title String The title text
3556 value String The string value to set into the active textbox element if displayed
3557 wait Boolean True to display a progress bar (defaults to false)
3558 width Number The width of the dialog in pixels
3565 msg: 'Please enter your address:',
3567 buttons: Roo.MessageBox.OKCANCEL,
3570 animEl: 'addAddressBtn'
3573 * @param {Object} config Configuration options
3574 * @return {Roo.MessageBox} This message box
3576 show : function(options)
3579 // this causes nightmares if you show one dialog after another
3580 // especially on callbacks..
3582 if(this.isVisible()){
3585 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3586 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3587 Roo.log("New Dialog Message:" + options.msg )
3588 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3589 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3592 var d = this.getDialog();
3594 d.setTitle(opt.title || " ");
3595 d.closeEl.setDisplayed(opt.closable !== false);
3596 activeTextEl = textboxEl;
3597 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3602 textareaEl.setHeight(typeof opt.multiline == "number" ?
3603 opt.multiline : this.defaultTextHeight);
3604 activeTextEl = textareaEl;
3613 progressEl.setDisplayed(opt.progress === true);
3615 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3617 this.updateProgress(0);
3618 activeTextEl.dom.value = opt.value || "";
3620 dlg.setDefaultButton(activeTextEl);
3622 var bs = opt.buttons;
3626 }else if(bs && bs.yes){
3627 db = buttons["yes"];
3629 dlg.setDefaultButton(db);
3631 bwidth = updateButtons(opt.buttons);
3632 this.updateText(opt.msg);
3634 d.el.addClass(opt.cls);
3636 d.proxyDrag = opt.proxyDrag === true;
3637 d.modal = opt.modal !== false;
3638 d.mask = opt.modal !== false ? mask : false;
3640 // force it to the end of the z-index stack so it gets a cursor in FF
3641 document.body.appendChild(dlg.el.dom);
3642 d.animateTarget = null;
3643 d.show(options.animEl);
3649 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3650 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3651 * and closing the message box when the process is complete.
3652 * @param {String} title The title bar text
3653 * @param {String} msg The message box body text
3654 * @return {Roo.MessageBox} This message box
3656 progress : function(title, msg){
3663 minWidth: this.minProgressWidth,
3670 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3671 * If a callback function is passed it will be called after the user clicks the button, and the
3672 * id of the button that was clicked will be passed as the only parameter to the callback
3673 * (could also be the top-right close button).
3674 * @param {String} title The title bar text
3675 * @param {String} msg The message box body text
3676 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3677 * @param {Object} scope (optional) The scope of the callback function
3678 * @return {Roo.MessageBox} This message box
3680 alert : function(title, msg, fn, scope)
3695 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3696 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3697 * You are responsible for closing the message box when the process is complete.
3698 * @param {String} msg The message box body text
3699 * @param {String} title (optional) The title bar text
3700 * @return {Roo.MessageBox} This message box
3702 wait : function(msg, title){
3713 waitTimer = Roo.TaskMgr.start({
3715 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3723 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3724 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3725 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3726 * @param {String} title The title bar text
3727 * @param {String} msg The message box body text
3728 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3729 * @param {Object} scope (optional) The scope of the callback function
3730 * @return {Roo.MessageBox} This message box
3732 confirm : function(title, msg, fn, scope){
3736 buttons: this.YESNO,
3745 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3746 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3747 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3748 * (could also be the top-right close button) and the text that was entered will be passed as the two
3749 * parameters to the callback.
3750 * @param {String} title The title bar text
3751 * @param {String} msg The message box body text
3752 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3753 * @param {Object} scope (optional) The scope of the callback function
3754 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3755 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3756 * @return {Roo.MessageBox} This message box
3758 prompt : function(title, msg, fn, scope, multiline){
3762 buttons: this.OKCANCEL,
3767 multiline: multiline,
3774 * Button config that displays a single OK button
3779 * Button config that displays Yes and No buttons
3782 YESNO : {yes:true, no:true},
3784 * Button config that displays OK and Cancel buttons
3787 OKCANCEL : {ok:true, cancel:true},
3789 * Button config that displays Yes, No and Cancel buttons
3792 YESNOCANCEL : {yes:true, no:true, cancel:true},
3795 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3798 defaultTextHeight : 75,
3800 * The maximum width in pixels of the message box (defaults to 600)
3805 * The minimum width in pixels of the message box (defaults to 100)
3810 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3811 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3814 minProgressWidth : 250,
3816 * An object containing the default button text strings that can be overriden for localized language support.
3817 * Supported properties are: ok, cancel, yes and no.
3818 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3831 * Shorthand for {@link Roo.MessageBox}
3833 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3834 Roo.Msg = Roo.Msg || Roo.MessageBox;
3843 * @class Roo.bootstrap.Navbar
3844 * @extends Roo.bootstrap.Component
3845 * Bootstrap Navbar class
3848 * Create a new Navbar
3849 * @param {Object} config The config object
3853 Roo.bootstrap.Navbar = function(config){
3854 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3858 * @event beforetoggle
3859 * Fire before toggle the menu
3860 * @param {Roo.EventObject} e
3862 "beforetoggle" : true
3866 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3875 getAutoCreate : function(){
3878 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3882 initEvents :function ()
3884 //Roo.log(this.el.select('.navbar-toggle',true));
3885 this.el.select('.navbar-toggle',true).on('click', function() {
3886 if(this.fireEvent('beforetoggle', this) !== false){
3887 var ce = this.el.select('.navbar-collapse',true).first();
3888 ce.toggleClass('in'); // old...
3889 if (ce.hasClass('collapse')) {
3891 ce.removeClass('collapse');
3892 ce.addClass('show');
3893 var h = ce.getHeight();
3895 ce.removeClass('show');
3896 // at this point we should be able to see it..
3897 ce.addClass('collapsing');
3899 ce.setHeight(0); // resize it ...
3900 ce.on('transitionend', function() {
3901 Roo.log('done transition');
3902 ce.removeClass('collapsing');
3903 ce.addClass('show');
3904 ce.removeClass('collapse');
3906 ce.dom.style.height = '';
3907 }, this, { single: true} );
3911 ce.setHeight(ce.getHeight());
3912 ce.removeClass('show');
3913 ce.addClass('collapsing');
3915 ce.on('transitionend', function() {
3916 ce.dom.style.height = '';
3917 ce.removeClass('collapsing');
3918 ce.addClass('collapse');
3919 }, this, { single: true} );
3931 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3933 var size = this.el.getSize();
3934 this.maskEl.setSize(size.width, size.height);
3935 this.maskEl.enableDisplayMode("block");
3944 getChildContainer : function()
3946 if (this.el.select('.collapse').getCount()) {
3947 return this.el.select('.collapse',true).first();
3980 * @class Roo.bootstrap.NavSimplebar
3981 * @extends Roo.bootstrap.Navbar
3982 * Bootstrap Sidebar class
3984 * @cfg {Boolean} inverse is inverted color
3986 * @cfg {String} type (nav | pills | tabs)
3987 * @cfg {Boolean} arrangement stacked | justified
3988 * @cfg {String} align (left | right) alignment
3990 * @cfg {Boolean} main (true|false) main nav bar? default false
3991 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3993 * @cfg {String} tag (header|footer|nav|div) default is nav
3995 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
3999 * Create a new Sidebar
4000 * @param {Object} config The config object
4004 Roo.bootstrap.NavSimplebar = function(config){
4005 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4008 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4024 getAutoCreate : function(){
4028 tag : this.tag || 'div',
4029 cls : 'navbar navbar-expand-lg roo-navbar-simple'
4031 if (['light','white'].indexOf(this.weight) > -1) {
4032 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4034 cfg.cls += ' bg-' + this.weight;
4037 cfg.cls += ' navbar-inverse';
4041 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4043 //if (Roo.bootstrap.version == 4) {
4055 this.type = this.type || 'nav';
4056 if (['tabs','pills'].indexOf(this.type) != -1) {
4057 cfg.cn[0].cls += ' nav-' + this.type
4061 if (this.type!=='nav') {
4062 Roo.log('nav type must be nav/tabs/pills')
4064 cfg.cn[0].cls += ' navbar-nav'
4070 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4071 cfg.cn[0].cls += ' nav-' + this.arrangement;
4075 if (this.align === 'right') {
4076 cfg.cn[0].cls += ' navbar-right';
4101 * navbar-expand-md fixed-top
4105 * @class Roo.bootstrap.NavHeaderbar
4106 * @extends Roo.bootstrap.NavSimplebar
4107 * Bootstrap Sidebar class
4109 * @cfg {String} brand what is brand
4110 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4111 * @cfg {String} brand_href href of the brand
4112 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4113 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4114 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4115 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4118 * Create a new Sidebar
4119 * @param {Object} config The config object
4123 Roo.bootstrap.NavHeaderbar = function(config){
4124 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4128 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4135 desktopCenter : false,
4138 getAutoCreate : function(){
4141 tag: this.nav || 'nav',
4142 cls: 'navbar navbar-expand-md',
4148 if (this.desktopCenter) {
4149 cn.push({cls : 'container', cn : []});
4157 cls: 'navbar-toggle navbar-toggler',
4158 'data-toggle': 'collapse',
4163 html: 'Toggle navigation'
4167 cls: 'icon-bar navbar-toggler-icon'
4180 cn.push( Roo.bootstrap.version == 4 ? btn : {
4182 cls: 'navbar-header',
4191 cls: 'collapse navbar-collapse',
4195 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4197 if (['light','white'].indexOf(this.weight) > -1) {
4198 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4200 cfg.cls += ' bg-' + this.weight;
4203 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4204 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4206 // tag can override this..
4208 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4211 if (this.brand !== '') {
4212 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4213 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4215 href: this.brand_href ? this.brand_href : '#',
4216 cls: 'navbar-brand',
4224 cfg.cls += ' main-nav';
4232 getHeaderChildContainer : function()
4234 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4235 return this.el.select('.navbar-header',true).first();
4238 return this.getChildContainer();
4242 initEvents : function()
4244 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4246 if (this.autohide) {
4251 Roo.get(document).on('scroll',function(e) {
4252 var ns = Roo.get(document).getScroll().top;
4253 var os = prevScroll;
4257 ft.removeClass('slideDown');
4258 ft.addClass('slideUp');
4261 ft.removeClass('slideUp');
4262 ft.addClass('slideDown');
4283 * @class Roo.bootstrap.NavSidebar
4284 * @extends Roo.bootstrap.Navbar
4285 * Bootstrap Sidebar class
4288 * Create a new Sidebar
4289 * @param {Object} config The config object
4293 Roo.bootstrap.NavSidebar = function(config){
4294 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4297 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4299 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4301 getAutoCreate : function(){
4306 cls: 'sidebar sidebar-nav'
4328 * @class Roo.bootstrap.NavGroup
4329 * @extends Roo.bootstrap.Component
4330 * Bootstrap NavGroup class
4331 * @cfg {String} align (left|right)
4332 * @cfg {Boolean} inverse
4333 * @cfg {String} type (nav|pills|tab) default nav
4334 * @cfg {String} navId - reference Id for navbar.
4338 * Create a new nav group
4339 * @param {Object} config The config object
4342 Roo.bootstrap.NavGroup = function(config){
4343 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4346 Roo.bootstrap.NavGroup.register(this);
4350 * Fires when the active item changes
4351 * @param {Roo.bootstrap.NavGroup} this
4352 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4353 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4360 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4371 getAutoCreate : function()
4373 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4379 if (Roo.bootstrap.version == 4) {
4380 if (['tabs','pills'].indexOf(this.type) != -1) {
4381 cfg.cls += ' nav-' + this.type;
4383 cfg.cls += ' navbar-nav';
4386 if (['tabs','pills'].indexOf(this.type) != -1) {
4387 cfg.cls += ' nav-' + this.type
4389 if (this.type !== 'nav') {
4390 Roo.log('nav type must be nav/tabs/pills')
4392 cfg.cls += ' navbar-nav'
4396 if (this.parent() && this.parent().sidebar) {
4399 cls: 'dashboard-menu sidebar-menu'
4405 if (this.form === true) {
4408 cls: 'navbar-form form-inline'
4411 if (this.align === 'right') {
4412 cfg.cls += ' navbar-right ml-md-auto';
4414 cfg.cls += ' navbar-left';
4418 if (this.align === 'right') {
4419 cfg.cls += ' navbar-right ml-md-auto';
4421 cfg.cls += ' mr-auto';
4425 cfg.cls += ' navbar-inverse';
4433 * sets the active Navigation item
4434 * @param {Roo.bootstrap.NavItem} the new current navitem
4436 setActiveItem : function(item)
4439 Roo.each(this.navItems, function(v){
4444 v.setActive(false, true);
4451 item.setActive(true, true);
4452 this.fireEvent('changed', this, item, prev);
4457 * gets the active Navigation item
4458 * @return {Roo.bootstrap.NavItem} the current navitem
4460 getActive : function()
4464 Roo.each(this.navItems, function(v){
4475 indexOfNav : function()
4479 Roo.each(this.navItems, function(v,i){
4490 * adds a Navigation item
4491 * @param {Roo.bootstrap.NavItem} the navitem to add
4493 addItem : function(cfg)
4495 if (this.form && Roo.bootstrap.version == 4) {
4498 var cn = new Roo.bootstrap.NavItem(cfg);
4500 cn.parentId = this.id;
4501 cn.onRender(this.el, null);
4505 * register a Navigation item
4506 * @param {Roo.bootstrap.NavItem} the navitem to add
4508 register : function(item)
4510 this.navItems.push( item);
4511 item.navId = this.navId;
4516 * clear all the Navigation item
4519 clearAll : function()
4522 this.el.dom.innerHTML = '';
4525 getNavItem: function(tabId)
4528 Roo.each(this.navItems, function(e) {
4529 if (e.tabId == tabId) {
4539 setActiveNext : function()
4541 var i = this.indexOfNav(this.getActive());
4542 if (i > this.navItems.length) {
4545 this.setActiveItem(this.navItems[i+1]);
4547 setActivePrev : function()
4549 var i = this.indexOfNav(this.getActive());
4553 this.setActiveItem(this.navItems[i-1]);
4555 clearWasActive : function(except) {
4556 Roo.each(this.navItems, function(e) {
4557 if (e.tabId != except.tabId && e.was_active) {
4558 e.was_active = false;
4565 getWasActive : function ()
4568 Roo.each(this.navItems, function(e) {
4583 Roo.apply(Roo.bootstrap.NavGroup, {
4587 * register a Navigation Group
4588 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4590 register : function(navgrp)
4592 this.groups[navgrp.navId] = navgrp;
4596 * fetch a Navigation Group based on the navigation ID
4597 * @param {string} the navgroup to add
4598 * @returns {Roo.bootstrap.NavGroup} the navgroup
4600 get: function(navId) {
4601 if (typeof(this.groups[navId]) == 'undefined') {
4603 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4605 return this.groups[navId] ;
4620 * @class Roo.bootstrap.NavItem
4621 * @extends Roo.bootstrap.Component
4622 * Bootstrap Navbar.NavItem class
4623 * @cfg {String} href link to
4624 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4626 * @cfg {String} html content of button
4627 * @cfg {String} badge text inside badge
4628 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4629 * @cfg {String} glyphicon DEPRICATED - use fa
4630 * @cfg {String} icon DEPRICATED - use fa
4631 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4632 * @cfg {Boolean} active Is item active
4633 * @cfg {Boolean} disabled Is item disabled
4635 * @cfg {Boolean} preventDefault (true | false) default false
4636 * @cfg {String} tabId the tab that this item activates.
4637 * @cfg {String} tagtype (a|span) render as a href or span?
4638 * @cfg {Boolean} animateRef (true|false) link to element default false
4641 * Create a new Navbar Item
4642 * @param {Object} config The config object
4644 Roo.bootstrap.NavItem = function(config){
4645 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4650 * The raw click event for the entire grid.
4651 * @param {Roo.EventObject} e
4656 * Fires when the active item active state changes
4657 * @param {Roo.bootstrap.NavItem} this
4658 * @param {boolean} state the new state
4664 * Fires when scroll to element
4665 * @param {Roo.bootstrap.NavItem} this
4666 * @param {Object} options
4667 * @param {Roo.EventObject} e
4675 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4684 preventDefault : false,
4692 button_outline : false,
4696 getAutoCreate : function(){
4704 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4706 if (this.disabled) {
4707 cfg.cls += ' disabled';
4711 if (this.button_weight.length) {
4712 cfg.tag = this.href ? 'a' : 'button';
4713 cfg.html = this.html || '';
4714 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4716 cfg.href = this.href;
4719 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4722 // menu .. should add dropdown-menu class - so no need for carat..
4724 if (this.badge !== '') {
4726 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4731 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4735 href : this.href || "#",
4736 html: this.html || ''
4739 if (this.tagtype == 'a') {
4740 cfg.cn[0].cls = 'nav-link';
4743 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4746 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4748 if(this.glyphicon) {
4749 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4754 cfg.cn[0].html += " <span class='caret'></span>";
4758 if (this.badge !== '') {
4760 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4768 onRender : function(ct, position)
4770 // Roo.log("Call onRender: " + this.xtype);
4771 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4775 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4776 this.navLink = this.el.select('.nav-link',true).first();
4781 initEvents: function()
4783 if (typeof (this.menu) != 'undefined') {
4784 this.menu.parentType = this.xtype;
4785 this.menu.triggerEl = this.el;
4786 this.menu = this.addxtype(Roo.apply({}, this.menu));
4789 this.el.select('a',true).on('click', this.onClick, this);
4791 if(this.tagtype == 'span'){
4792 this.el.select('span',true).on('click', this.onClick, this);
4795 // at this point parent should be available..
4796 this.parent().register(this);
4799 onClick : function(e)
4801 if (e.getTarget('.dropdown-menu-item')) {
4802 // did you click on a menu itemm.... - then don't trigger onclick..
4807 this.preventDefault ||
4810 Roo.log("NavItem - prevent Default?");
4814 if (this.disabled) {
4818 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4819 if (tg && tg.transition) {
4820 Roo.log("waiting for the transitionend");
4826 //Roo.log("fire event clicked");
4827 if(this.fireEvent('click', this, e) === false){
4831 if(this.tagtype == 'span'){
4835 //Roo.log(this.href);
4836 var ael = this.el.select('a',true).first();
4839 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4840 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4841 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4842 return; // ignore... - it's a 'hash' to another page.
4844 Roo.log("NavItem - prevent Default?");
4846 this.scrollToElement(e);
4850 var p = this.parent();
4852 if (['tabs','pills'].indexOf(p.type)!==-1) {
4853 if (typeof(p.setActiveItem) !== 'undefined') {
4854 p.setActiveItem(this);
4858 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4859 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4860 // remove the collapsed menu expand...
4861 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4865 isActive: function () {
4868 setActive : function(state, fire, is_was_active)
4870 if (this.active && !state && this.navId) {
4871 this.was_active = true;
4872 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4874 nv.clearWasActive(this);
4878 this.active = state;
4881 this.el.removeClass('active');
4882 this.navLink ? this.navLink.removeClass('active') : false;
4883 } else if (!this.el.hasClass('active')) {
4885 this.el.addClass('active');
4886 if (Roo.bootstrap.version == 4 && this.navLink ) {
4887 this.navLink.addClass('active');
4892 this.fireEvent('changed', this, state);
4895 // show a panel if it's registered and related..
4897 if (!this.navId || !this.tabId || !state || is_was_active) {
4901 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4905 var pan = tg.getPanelByName(this.tabId);
4909 // if we can not flip to new panel - go back to old nav highlight..
4910 if (false == tg.showPanel(pan)) {
4911 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4913 var onav = nv.getWasActive();
4915 onav.setActive(true, false, true);
4924 // this should not be here...
4925 setDisabled : function(state)
4927 this.disabled = state;
4929 this.el.removeClass('disabled');
4930 } else if (!this.el.hasClass('disabled')) {
4931 this.el.addClass('disabled');
4937 * Fetch the element to display the tooltip on.
4938 * @return {Roo.Element} defaults to this.el
4940 tooltipEl : function()
4942 return this.el.select('' + this.tagtype + '', true).first();
4945 scrollToElement : function(e)
4947 var c = document.body;
4950 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4952 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4953 c = document.documentElement;
4956 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4962 var o = target.calcOffsetsTo(c);
4969 this.fireEvent('scrollto', this, options, e);
4971 Roo.get(c).scrollTo('top', options.value, true);
4984 * <span> icon </span>
4985 * <span> text </span>
4986 * <span>badge </span>
4990 * @class Roo.bootstrap.NavSidebarItem
4991 * @extends Roo.bootstrap.NavItem
4992 * Bootstrap Navbar.NavSidebarItem class
4993 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4994 * {Boolean} open is the menu open
4995 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4996 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4997 * {String} buttonSize (sm|md|lg)the extra classes for the button
4998 * {Boolean} showArrow show arrow next to the text (default true)
5000 * Create a new Navbar Button
5001 * @param {Object} config The config object
5003 Roo.bootstrap.NavSidebarItem = function(config){
5004 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5009 * The raw click event for the entire grid.
5010 * @param {Roo.EventObject} e
5015 * Fires when the active item active state changes
5016 * @param {Roo.bootstrap.NavSidebarItem} this
5017 * @param {boolean} state the new state
5025 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5027 badgeWeight : 'default',
5033 buttonWeight : 'default',
5039 getAutoCreate : function(){
5044 href : this.href || '#',
5050 if(this.buttonView){
5053 href : this.href || '#',
5054 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5067 cfg.cls += ' active';
5070 if (this.disabled) {
5071 cfg.cls += ' disabled';
5074 cfg.cls += ' open x-open';
5077 if (this.glyphicon || this.icon) {
5078 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5079 a.cn.push({ tag : 'i', cls : c }) ;
5082 if(!this.buttonView){
5085 html : this.html || ''
5092 if (this.badge !== '') {
5093 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5099 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5102 a.cls += ' dropdown-toggle treeview' ;
5108 initEvents : function()
5110 if (typeof (this.menu) != 'undefined') {
5111 this.menu.parentType = this.xtype;
5112 this.menu.triggerEl = this.el;
5113 this.menu = this.addxtype(Roo.apply({}, this.menu));
5116 this.el.on('click', this.onClick, this);
5118 if(this.badge !== ''){
5119 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5124 onClick : function(e)
5131 if(this.preventDefault){
5135 this.fireEvent('click', this);
5138 disable : function()
5140 this.setDisabled(true);
5145 this.setDisabled(false);
5148 setDisabled : function(state)
5150 if(this.disabled == state){
5154 this.disabled = state;
5157 this.el.addClass('disabled');
5161 this.el.removeClass('disabled');
5166 setActive : function(state)
5168 if(this.active == state){
5172 this.active = state;
5175 this.el.addClass('active');
5179 this.el.removeClass('active');
5184 isActive: function ()
5189 setBadge : function(str)
5195 this.badgeEl.dom.innerHTML = str;
5212 * @class Roo.bootstrap.Row
5213 * @extends Roo.bootstrap.Component
5214 * Bootstrap Row class (contains columns...)
5218 * @param {Object} config The config object
5221 Roo.bootstrap.Row = function(config){
5222 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5225 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5227 getAutoCreate : function(){
5246 * @class Roo.bootstrap.Element
5247 * @extends Roo.bootstrap.Component
5248 * Bootstrap Element class
5249 * @cfg {String} html contents of the element
5250 * @cfg {String} tag tag of the element
5251 * @cfg {String} cls class of the element
5252 * @cfg {Boolean} preventDefault (true|false) default false
5253 * @cfg {Boolean} clickable (true|false) default false
5256 * Create a new Element
5257 * @param {Object} config The config object
5260 Roo.bootstrap.Element = function(config){
5261 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5267 * When a element is chick
5268 * @param {Roo.bootstrap.Element} this
5269 * @param {Roo.EventObject} e
5275 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5280 preventDefault: false,
5283 getAutoCreate : function(){
5287 // cls: this.cls, double assign in parent class Component.js :: onRender
5294 initEvents: function()
5296 Roo.bootstrap.Element.superclass.initEvents.call(this);
5299 this.el.on('click', this.onClick, this);
5304 onClick : function(e)
5306 if(this.preventDefault){
5310 this.fireEvent('click', this, e);
5313 getValue : function()
5315 return this.el.dom.innerHTML;
5318 setValue : function(value)
5320 this.el.dom.innerHTML = value;
5335 * @class Roo.bootstrap.Pagination
5336 * @extends Roo.bootstrap.Component
5337 * Bootstrap Pagination class
5338 * @cfg {String} size xs | sm | md | lg
5339 * @cfg {Boolean} inverse false | true
5342 * Create a new Pagination
5343 * @param {Object} config The config object
5346 Roo.bootstrap.Pagination = function(config){
5347 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5350 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5356 getAutoCreate : function(){
5362 cfg.cls += ' inverse';
5368 cfg.cls += " " + this.cls;
5386 * @class Roo.bootstrap.PaginationItem
5387 * @extends Roo.bootstrap.Component
5388 * Bootstrap PaginationItem class
5389 * @cfg {String} html text
5390 * @cfg {String} href the link
5391 * @cfg {Boolean} preventDefault (true | false) default true
5392 * @cfg {Boolean} active (true | false) default false
5393 * @cfg {Boolean} disabled default false
5397 * Create a new PaginationItem
5398 * @param {Object} config The config object
5402 Roo.bootstrap.PaginationItem = function(config){
5403 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5408 * The raw click event for the entire grid.
5409 * @param {Roo.EventObject} e
5415 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5419 preventDefault: true,
5424 getAutoCreate : function(){
5430 href : this.href ? this.href : '#',
5431 html : this.html ? this.html : ''
5441 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5445 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5451 initEvents: function() {
5453 this.el.on('click', this.onClick, this);
5456 onClick : function(e)
5458 Roo.log('PaginationItem on click ');
5459 if(this.preventDefault){
5467 this.fireEvent('click', this, e);
5483 * @class Roo.bootstrap.Slider
5484 * @extends Roo.bootstrap.Component
5485 * Bootstrap Slider class
5488 * Create a new Slider
5489 * @param {Object} config The config object
5492 Roo.bootstrap.Slider = function(config){
5493 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5496 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5498 getAutoCreate : function(){
5502 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5506 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5518 * Ext JS Library 1.1.1
5519 * Copyright(c) 2006-2007, Ext JS, LLC.
5521 * Originally Released Under LGPL - original licence link has changed is not relivant.
5524 * <script type="text/javascript">
5529 * @class Roo.grid.ColumnModel
5530 * @extends Roo.util.Observable
5531 * This is the default implementation of a ColumnModel used by the Grid. It defines
5532 * the columns in the grid.
5535 var colModel = new Roo.grid.ColumnModel([
5536 {header: "Ticker", width: 60, sortable: true, locked: true},
5537 {header: "Company Name", width: 150, sortable: true},
5538 {header: "Market Cap.", width: 100, sortable: true},
5539 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5540 {header: "Employees", width: 100, sortable: true, resizable: false}
5545 * The config options listed for this class are options which may appear in each
5546 * individual column definition.
5547 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5549 * @param {Object} config An Array of column config objects. See this class's
5550 * config objects for details.
5552 Roo.grid.ColumnModel = function(config){
5554 * The config passed into the constructor
5556 this.config = config;
5559 // if no id, create one
5560 // if the column does not have a dataIndex mapping,
5561 // map it to the order it is in the config
5562 for(var i = 0, len = config.length; i < len; i++){
5564 if(typeof c.dataIndex == "undefined"){
5567 if(typeof c.renderer == "string"){
5568 c.renderer = Roo.util.Format[c.renderer];
5570 if(typeof c.id == "undefined"){
5573 if(c.editor && c.editor.xtype){
5574 c.editor = Roo.factory(c.editor, Roo.grid);
5576 if(c.editor && c.editor.isFormField){
5577 c.editor = new Roo.grid.GridEditor(c.editor);
5579 this.lookup[c.id] = c;
5583 * The width of columns which have no width specified (defaults to 100)
5586 this.defaultWidth = 100;
5589 * Default sortable of columns which have no sortable specified (defaults to false)
5592 this.defaultSortable = false;
5596 * @event widthchange
5597 * Fires when the width of a column changes.
5598 * @param {ColumnModel} this
5599 * @param {Number} columnIndex The column index
5600 * @param {Number} newWidth The new width
5602 "widthchange": true,
5604 * @event headerchange
5605 * Fires when the text of a header changes.
5606 * @param {ColumnModel} this
5607 * @param {Number} columnIndex The column index
5608 * @param {Number} newText The new header text
5610 "headerchange": true,
5612 * @event hiddenchange
5613 * Fires when a column is hidden or "unhidden".
5614 * @param {ColumnModel} this
5615 * @param {Number} columnIndex The column index
5616 * @param {Boolean} hidden true if hidden, false otherwise
5618 "hiddenchange": true,
5620 * @event columnmoved
5621 * Fires when a column is moved.
5622 * @param {ColumnModel} this
5623 * @param {Number} oldIndex
5624 * @param {Number} newIndex
5626 "columnmoved" : true,
5628 * @event columlockchange
5629 * Fires when a column's locked state is changed
5630 * @param {ColumnModel} this
5631 * @param {Number} colIndex
5632 * @param {Boolean} locked true if locked
5634 "columnlockchange" : true
5636 Roo.grid.ColumnModel.superclass.constructor.call(this);
5638 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5640 * @cfg {String} header The header text to display in the Grid view.
5643 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5644 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5645 * specified, the column's index is used as an index into the Record's data Array.
5648 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5649 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5652 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5653 * Defaults to the value of the {@link #defaultSortable} property.
5654 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5657 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5660 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5663 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5666 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5669 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5670 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5671 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5672 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5675 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5678 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5681 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5684 * @cfg {String} cursor (Optional)
5687 * @cfg {String} tooltip (Optional)
5690 * @cfg {Number} xs (Optional)
5693 * @cfg {Number} sm (Optional)
5696 * @cfg {Number} md (Optional)
5699 * @cfg {Number} lg (Optional)
5702 * Returns the id of the column at the specified index.
5703 * @param {Number} index The column index
5704 * @return {String} the id
5706 getColumnId : function(index){
5707 return this.config[index].id;
5711 * Returns the column for a specified id.
5712 * @param {String} id The column id
5713 * @return {Object} the column
5715 getColumnById : function(id){
5716 return this.lookup[id];
5721 * Returns the column for a specified dataIndex.
5722 * @param {String} dataIndex The column dataIndex
5723 * @return {Object|Boolean} the column or false if not found
5725 getColumnByDataIndex: function(dataIndex){
5726 var index = this.findColumnIndex(dataIndex);
5727 return index > -1 ? this.config[index] : false;
5731 * Returns the index for a specified column id.
5732 * @param {String} id The column id
5733 * @return {Number} the index, or -1 if not found
5735 getIndexById : function(id){
5736 for(var i = 0, len = this.config.length; i < len; i++){
5737 if(this.config[i].id == id){
5745 * Returns the index for a specified column dataIndex.
5746 * @param {String} dataIndex The column dataIndex
5747 * @return {Number} the index, or -1 if not found
5750 findColumnIndex : function(dataIndex){
5751 for(var i = 0, len = this.config.length; i < len; i++){
5752 if(this.config[i].dataIndex == dataIndex){
5760 moveColumn : function(oldIndex, newIndex){
5761 var c = this.config[oldIndex];
5762 this.config.splice(oldIndex, 1);
5763 this.config.splice(newIndex, 0, c);
5764 this.dataMap = null;
5765 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5768 isLocked : function(colIndex){
5769 return this.config[colIndex].locked === true;
5772 setLocked : function(colIndex, value, suppressEvent){
5773 if(this.isLocked(colIndex) == value){
5776 this.config[colIndex].locked = value;
5778 this.fireEvent("columnlockchange", this, colIndex, value);
5782 getTotalLockedWidth : function(){
5784 for(var i = 0; i < this.config.length; i++){
5785 if(this.isLocked(i) && !this.isHidden(i)){
5786 this.totalWidth += this.getColumnWidth(i);
5792 getLockedCount : function(){
5793 for(var i = 0, len = this.config.length; i < len; i++){
5794 if(!this.isLocked(i)){
5799 return this.config.length;
5803 * Returns the number of columns.
5806 getColumnCount : function(visibleOnly){
5807 if(visibleOnly === true){
5809 for(var i = 0, len = this.config.length; i < len; i++){
5810 if(!this.isHidden(i)){
5816 return this.config.length;
5820 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5821 * @param {Function} fn
5822 * @param {Object} scope (optional)
5823 * @return {Array} result
5825 getColumnsBy : function(fn, scope){
5827 for(var i = 0, len = this.config.length; i < len; i++){
5828 var c = this.config[i];
5829 if(fn.call(scope||this, c, i) === true){
5837 * Returns true if the specified column is sortable.
5838 * @param {Number} col The column index
5841 isSortable : function(col){
5842 if(typeof this.config[col].sortable == "undefined"){
5843 return this.defaultSortable;
5845 return this.config[col].sortable;
5849 * Returns the rendering (formatting) function defined for the column.
5850 * @param {Number} col The column index.
5851 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5853 getRenderer : function(col){
5854 if(!this.config[col].renderer){
5855 return Roo.grid.ColumnModel.defaultRenderer;
5857 return this.config[col].renderer;
5861 * Sets the rendering (formatting) function for a column.
5862 * @param {Number} col The column index
5863 * @param {Function} fn The function to use to process the cell's raw data
5864 * to return HTML markup for the grid view. The render function is called with
5865 * the following parameters:<ul>
5866 * <li>Data value.</li>
5867 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5868 * <li>css A CSS style string to apply to the table cell.</li>
5869 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5870 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5871 * <li>Row index</li>
5872 * <li>Column index</li>
5873 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5875 setRenderer : function(col, fn){
5876 this.config[col].renderer = fn;
5880 * Returns the width for the specified column.
5881 * @param {Number} col The column index
5884 getColumnWidth : function(col){
5885 return this.config[col].width * 1 || this.defaultWidth;
5889 * Sets the width for a column.
5890 * @param {Number} col The column index
5891 * @param {Number} width The new width
5893 setColumnWidth : function(col, width, suppressEvent){
5894 this.config[col].width = width;
5895 this.totalWidth = null;
5897 this.fireEvent("widthchange", this, col, width);
5902 * Returns the total width of all columns.
5903 * @param {Boolean} includeHidden True to include hidden column widths
5906 getTotalWidth : function(includeHidden){
5907 if(!this.totalWidth){
5908 this.totalWidth = 0;
5909 for(var i = 0, len = this.config.length; i < len; i++){
5910 if(includeHidden || !this.isHidden(i)){
5911 this.totalWidth += this.getColumnWidth(i);
5915 return this.totalWidth;
5919 * Returns the header for the specified column.
5920 * @param {Number} col The column index
5923 getColumnHeader : function(col){
5924 return this.config[col].header;
5928 * Sets the header for a column.
5929 * @param {Number} col The column index
5930 * @param {String} header The new header
5932 setColumnHeader : function(col, header){
5933 this.config[col].header = header;
5934 this.fireEvent("headerchange", this, col, header);
5938 * Returns the tooltip for the specified column.
5939 * @param {Number} col The column index
5942 getColumnTooltip : function(col){
5943 return this.config[col].tooltip;
5946 * Sets the tooltip for a column.
5947 * @param {Number} col The column index
5948 * @param {String} tooltip The new tooltip
5950 setColumnTooltip : function(col, tooltip){
5951 this.config[col].tooltip = tooltip;
5955 * Returns the dataIndex for the specified column.
5956 * @param {Number} col The column index
5959 getDataIndex : function(col){
5960 return this.config[col].dataIndex;
5964 * Sets the dataIndex for a column.
5965 * @param {Number} col The column index
5966 * @param {Number} dataIndex The new dataIndex
5968 setDataIndex : function(col, dataIndex){
5969 this.config[col].dataIndex = dataIndex;
5975 * Returns true if the cell is editable.
5976 * @param {Number} colIndex The column index
5977 * @param {Number} rowIndex The row index - this is nto actually used..?
5980 isCellEditable : function(colIndex, rowIndex){
5981 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5985 * Returns the editor defined for the cell/column.
5986 * return false or null to disable editing.
5987 * @param {Number} colIndex The column index
5988 * @param {Number} rowIndex The row index
5991 getCellEditor : function(colIndex, rowIndex){
5992 return this.config[colIndex].editor;
5996 * Sets if a column is editable.
5997 * @param {Number} col The column index
5998 * @param {Boolean} editable True if the column is editable
6000 setEditable : function(col, editable){
6001 this.config[col].editable = editable;
6006 * Returns true if the column is hidden.
6007 * @param {Number} colIndex The column index
6010 isHidden : function(colIndex){
6011 return this.config[colIndex].hidden;
6016 * Returns true if the column width cannot be changed
6018 isFixed : function(colIndex){
6019 return this.config[colIndex].fixed;
6023 * Returns true if the column can be resized
6026 isResizable : function(colIndex){
6027 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6030 * Sets if a column is hidden.
6031 * @param {Number} colIndex The column index
6032 * @param {Boolean} hidden True if the column is hidden
6034 setHidden : function(colIndex, hidden){
6035 this.config[colIndex].hidden = hidden;
6036 this.totalWidth = null;
6037 this.fireEvent("hiddenchange", this, colIndex, hidden);
6041 * Sets the editor for a column.
6042 * @param {Number} col The column index
6043 * @param {Object} editor The editor object
6045 setEditor : function(col, editor){
6046 this.config[col].editor = editor;
6050 Roo.grid.ColumnModel.defaultRenderer = function(value)
6052 if(typeof value == "object") {
6055 if(typeof value == "string" && value.length < 1){
6059 return String.format("{0}", value);
6062 // Alias for backwards compatibility
6063 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6066 * Ext JS Library 1.1.1
6067 * Copyright(c) 2006-2007, Ext JS, LLC.
6069 * Originally Released Under LGPL - original licence link has changed is not relivant.
6072 * <script type="text/javascript">
6076 * @class Roo.LoadMask
6077 * A simple utility class for generically masking elements while loading data. If the element being masked has
6078 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6079 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6080 * element's UpdateManager load indicator and will be destroyed after the initial load.
6082 * Create a new LoadMask
6083 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6084 * @param {Object} config The config object
6086 Roo.LoadMask = function(el, config){
6087 this.el = Roo.get(el);
6088 Roo.apply(this, config);
6090 this.store.on('beforeload', this.onBeforeLoad, this);
6091 this.store.on('load', this.onLoad, this);
6092 this.store.on('loadexception', this.onLoadException, this);
6093 this.removeMask = false;
6095 var um = this.el.getUpdateManager();
6096 um.showLoadIndicator = false; // disable the default indicator
6097 um.on('beforeupdate', this.onBeforeLoad, this);
6098 um.on('update', this.onLoad, this);
6099 um.on('failure', this.onLoad, this);
6100 this.removeMask = true;
6104 Roo.LoadMask.prototype = {
6106 * @cfg {Boolean} removeMask
6107 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6108 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6112 * The text to display in a centered loading message box (defaults to 'Loading...')
6116 * @cfg {String} msgCls
6117 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6119 msgCls : 'x-mask-loading',
6122 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6128 * Disables the mask to prevent it from being displayed
6130 disable : function(){
6131 this.disabled = true;
6135 * Enables the mask so that it can be displayed
6137 enable : function(){
6138 this.disabled = false;
6141 onLoadException : function()
6145 if (typeof(arguments[3]) != 'undefined') {
6146 Roo.MessageBox.alert("Error loading",arguments[3]);
6150 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6151 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6158 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6163 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6167 onBeforeLoad : function(){
6169 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6174 destroy : function(){
6176 this.store.un('beforeload', this.onBeforeLoad, this);
6177 this.store.un('load', this.onLoad, this);
6178 this.store.un('loadexception', this.onLoadException, this);
6180 var um = this.el.getUpdateManager();
6181 um.un('beforeupdate', this.onBeforeLoad, this);
6182 um.un('update', this.onLoad, this);
6183 um.un('failure', this.onLoad, this);
6194 * @class Roo.bootstrap.Table
6195 * @extends Roo.bootstrap.Component
6196 * Bootstrap Table class
6197 * @cfg {String} cls table class
6198 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6199 * @cfg {String} bgcolor Specifies the background color for a table
6200 * @cfg {Number} border Specifies whether the table cells should have borders or not
6201 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6202 * @cfg {Number} cellspacing Specifies the space between cells
6203 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6204 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6205 * @cfg {String} sortable Specifies that the table should be sortable
6206 * @cfg {String} summary Specifies a summary of the content of a table
6207 * @cfg {Number} width Specifies the width of a table
6208 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6210 * @cfg {boolean} striped Should the rows be alternative striped
6211 * @cfg {boolean} bordered Add borders to the table
6212 * @cfg {boolean} hover Add hover highlighting
6213 * @cfg {boolean} condensed Format condensed
6214 * @cfg {boolean} responsive Format condensed
6215 * @cfg {Boolean} loadMask (true|false) default false
6216 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6217 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6218 * @cfg {Boolean} rowSelection (true|false) default false
6219 * @cfg {Boolean} cellSelection (true|false) default false
6220 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6221 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6222 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6223 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6227 * Create a new Table
6228 * @param {Object} config The config object
6231 Roo.bootstrap.Table = function(config){
6232 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6237 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6238 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6239 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6240 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6242 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6244 this.sm.grid = this;
6245 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6246 this.sm = this.selModel;
6247 this.sm.xmodule = this.xmodule || false;
6250 if (this.cm && typeof(this.cm.config) == 'undefined') {
6251 this.colModel = new Roo.grid.ColumnModel(this.cm);
6252 this.cm = this.colModel;
6253 this.cm.xmodule = this.xmodule || false;
6256 this.store= Roo.factory(this.store, Roo.data);
6257 this.ds = this.store;
6258 this.ds.xmodule = this.xmodule || false;
6261 if (this.footer && this.store) {
6262 this.footer.dataSource = this.ds;
6263 this.footer = Roo.factory(this.footer);
6270 * Fires when a cell is clicked
6271 * @param {Roo.bootstrap.Table} this
6272 * @param {Roo.Element} el
6273 * @param {Number} rowIndex
6274 * @param {Number} columnIndex
6275 * @param {Roo.EventObject} e
6279 * @event celldblclick
6280 * Fires when a cell is double clicked
6281 * @param {Roo.bootstrap.Table} this
6282 * @param {Roo.Element} el
6283 * @param {Number} rowIndex
6284 * @param {Number} columnIndex
6285 * @param {Roo.EventObject} e
6287 "celldblclick" : true,
6290 * Fires when a row is clicked
6291 * @param {Roo.bootstrap.Table} this
6292 * @param {Roo.Element} el
6293 * @param {Number} rowIndex
6294 * @param {Roo.EventObject} e
6298 * @event rowdblclick
6299 * Fires when a row is double clicked
6300 * @param {Roo.bootstrap.Table} this
6301 * @param {Roo.Element} el
6302 * @param {Number} rowIndex
6303 * @param {Roo.EventObject} e
6305 "rowdblclick" : true,
6308 * Fires when a mouseover occur
6309 * @param {Roo.bootstrap.Table} this
6310 * @param {Roo.Element} el
6311 * @param {Number} rowIndex
6312 * @param {Number} columnIndex
6313 * @param {Roo.EventObject} e
6318 * Fires when a mouseout occur
6319 * @param {Roo.bootstrap.Table} this
6320 * @param {Roo.Element} el
6321 * @param {Number} rowIndex
6322 * @param {Number} columnIndex
6323 * @param {Roo.EventObject} e
6328 * Fires when a row is rendered, so you can change add a style to it.
6329 * @param {Roo.bootstrap.Table} this
6330 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6334 * @event rowsrendered
6335 * Fires when all the rows have been rendered
6336 * @param {Roo.bootstrap.Table} this
6338 'rowsrendered' : true,
6340 * @event contextmenu
6341 * The raw contextmenu event for the entire grid.
6342 * @param {Roo.EventObject} e
6344 "contextmenu" : true,
6346 * @event rowcontextmenu
6347 * Fires when a row is right clicked
6348 * @param {Roo.bootstrap.Table} this
6349 * @param {Number} rowIndex
6350 * @param {Roo.EventObject} e
6352 "rowcontextmenu" : true,
6354 * @event cellcontextmenu
6355 * Fires when a cell is right clicked
6356 * @param {Roo.bootstrap.Table} this
6357 * @param {Number} rowIndex
6358 * @param {Number} cellIndex
6359 * @param {Roo.EventObject} e
6361 "cellcontextmenu" : true,
6363 * @event headercontextmenu
6364 * Fires when a header is right clicked
6365 * @param {Roo.bootstrap.Table} this
6366 * @param {Number} columnIndex
6367 * @param {Roo.EventObject} e
6369 "headercontextmenu" : true
6373 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6399 rowSelection : false,
6400 cellSelection : false,
6403 // Roo.Element - the tbody
6405 // Roo.Element - thead element
6408 container: false, // used by gridpanel...
6414 auto_hide_footer : false,
6416 getAutoCreate : function()
6418 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6425 if (this.scrollBody) {
6426 cfg.cls += ' table-body-fixed';
6429 cfg.cls += ' table-striped';
6433 cfg.cls += ' table-hover';
6435 if (this.bordered) {
6436 cfg.cls += ' table-bordered';
6438 if (this.condensed) {
6439 cfg.cls += ' table-condensed';
6441 if (this.responsive) {
6442 cfg.cls += ' table-responsive';
6446 cfg.cls+= ' ' +this.cls;
6449 // this lot should be simplifed...
6462 ].forEach(function(k) {
6470 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6473 if(this.store || this.cm){
6474 if(this.headerShow){
6475 cfg.cn.push(this.renderHeader());
6478 cfg.cn.push(this.renderBody());
6480 if(this.footerShow){
6481 cfg.cn.push(this.renderFooter());
6483 // where does this come from?
6484 //cfg.cls+= ' TableGrid';
6487 return { cn : [ cfg ] };
6490 initEvents : function()
6492 if(!this.store || !this.cm){
6495 if (this.selModel) {
6496 this.selModel.initEvents();
6500 //Roo.log('initEvents with ds!!!!');
6502 this.mainBody = this.el.select('tbody', true).first();
6503 this.mainHead = this.el.select('thead', true).first();
6504 this.mainFoot = this.el.select('tfoot', true).first();
6510 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6511 e.on('click', _this.sort, _this);
6514 this.mainBody.on("click", this.onClick, this);
6515 this.mainBody.on("dblclick", this.onDblClick, this);
6517 // why is this done????? = it breaks dialogs??
6518 //this.parent().el.setStyle('position', 'relative');
6522 this.footer.parentId = this.id;
6523 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6526 this.el.select('tfoot tr td').first().addClass('hide');
6531 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6534 this.store.on('load', this.onLoad, this);
6535 this.store.on('beforeload', this.onBeforeLoad, this);
6536 this.store.on('update', this.onUpdate, this);
6537 this.store.on('add', this.onAdd, this);
6538 this.store.on("clear", this.clear, this);
6540 this.el.on("contextmenu", this.onContextMenu, this);
6542 this.mainBody.on('scroll', this.onBodyScroll, this);
6544 this.cm.on("headerchange", this.onHeaderChange, this);
6546 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6550 onContextMenu : function(e, t)
6552 this.processEvent("contextmenu", e);
6555 processEvent : function(name, e)
6557 if (name != 'touchstart' ) {
6558 this.fireEvent(name, e);
6561 var t = e.getTarget();
6563 var cell = Roo.get(t);
6569 if(cell.findParent('tfoot', false, true)){
6573 if(cell.findParent('thead', false, true)){
6575 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6576 cell = Roo.get(t).findParent('th', false, true);
6578 Roo.log("failed to find th in thead?");
6579 Roo.log(e.getTarget());
6584 var cellIndex = cell.dom.cellIndex;
6586 var ename = name == 'touchstart' ? 'click' : name;
6587 this.fireEvent("header" + ename, this, cellIndex, e);
6592 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6593 cell = Roo.get(t).findParent('td', false, true);
6595 Roo.log("failed to find th in tbody?");
6596 Roo.log(e.getTarget());
6601 var row = cell.findParent('tr', false, true);
6602 var cellIndex = cell.dom.cellIndex;
6603 var rowIndex = row.dom.rowIndex - 1;
6607 this.fireEvent("row" + name, this, rowIndex, e);
6611 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6617 onMouseover : function(e, el)
6619 var cell = Roo.get(el);
6625 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6626 cell = cell.findParent('td', false, true);
6629 var row = cell.findParent('tr', false, true);
6630 var cellIndex = cell.dom.cellIndex;
6631 var rowIndex = row.dom.rowIndex - 1; // start from 0
6633 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6637 onMouseout : function(e, el)
6639 var cell = Roo.get(el);
6645 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6646 cell = cell.findParent('td', false, true);
6649 var row = cell.findParent('tr', false, true);
6650 var cellIndex = cell.dom.cellIndex;
6651 var rowIndex = row.dom.rowIndex - 1; // start from 0
6653 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6657 onClick : function(e, el)
6659 var cell = Roo.get(el);
6661 if(!cell || (!this.cellSelection && !this.rowSelection)){
6665 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6666 cell = cell.findParent('td', false, true);
6669 if(!cell || typeof(cell) == 'undefined'){
6673 var row = cell.findParent('tr', false, true);
6675 if(!row || typeof(row) == 'undefined'){
6679 var cellIndex = cell.dom.cellIndex;
6680 var rowIndex = this.getRowIndex(row);
6682 // why??? - should these not be based on SelectionModel?
6683 if(this.cellSelection){
6684 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6687 if(this.rowSelection){
6688 this.fireEvent('rowclick', this, row, rowIndex, e);
6694 onDblClick : function(e,el)
6696 var cell = Roo.get(el);
6698 if(!cell || (!this.cellSelection && !this.rowSelection)){
6702 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6703 cell = cell.findParent('td', false, true);
6706 if(!cell || typeof(cell) == 'undefined'){
6710 var row = cell.findParent('tr', false, true);
6712 if(!row || typeof(row) == 'undefined'){
6716 var cellIndex = cell.dom.cellIndex;
6717 var rowIndex = this.getRowIndex(row);
6719 if(this.cellSelection){
6720 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6723 if(this.rowSelection){
6724 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6728 sort : function(e,el)
6730 var col = Roo.get(el);
6732 if(!col.hasClass('sortable')){
6736 var sort = col.attr('sort');
6739 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6743 this.store.sortInfo = {field : sort, direction : dir};
6746 Roo.log("calling footer first");
6747 this.footer.onClick('first');
6750 this.store.load({ params : { start : 0 } });
6754 renderHeader : function()
6762 this.totalWidth = 0;
6764 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6766 var config = cm.config[i];
6770 cls : 'x-hcol-' + i,
6772 html: cm.getColumnHeader(i)
6777 if(typeof(config.sortable) != 'undefined' && config.sortable){
6779 c.html = '<i class="glyphicon"></i>' + c.html;
6782 if(typeof(config.lgHeader) != 'undefined'){
6783 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6786 if(typeof(config.mdHeader) != 'undefined'){
6787 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6790 if(typeof(config.smHeader) != 'undefined'){
6791 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6794 if(typeof(config.xsHeader) != 'undefined'){
6795 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6802 if(typeof(config.tooltip) != 'undefined'){
6803 c.tooltip = config.tooltip;
6806 if(typeof(config.colspan) != 'undefined'){
6807 c.colspan = config.colspan;
6810 if(typeof(config.hidden) != 'undefined' && config.hidden){
6811 c.style += ' display:none;';
6814 if(typeof(config.dataIndex) != 'undefined'){
6815 c.sort = config.dataIndex;
6820 if(typeof(config.align) != 'undefined' && config.align.length){
6821 c.style += ' text-align:' + config.align + ';';
6824 if(typeof(config.width) != 'undefined'){
6825 c.style += ' width:' + config.width + 'px;';
6826 this.totalWidth += config.width;
6828 this.totalWidth += 100; // assume minimum of 100 per column?
6831 if(typeof(config.cls) != 'undefined'){
6832 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6835 ['xs','sm','md','lg'].map(function(size){
6837 if(typeof(config[size]) == 'undefined'){
6841 if (!config[size]) { // 0 = hidden
6842 c.cls += ' hidden-' + size;
6846 c.cls += ' col-' + size + '-' + config[size];
6856 renderBody : function()
6866 colspan : this.cm.getColumnCount()
6876 renderFooter : function()
6886 colspan : this.cm.getColumnCount()
6900 // Roo.log('ds onload');
6905 var ds = this.store;
6907 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6908 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6909 if (_this.store.sortInfo) {
6911 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6912 e.select('i', true).addClass(['glyphicon-arrow-up']);
6915 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6916 e.select('i', true).addClass(['glyphicon-arrow-down']);
6921 var tbody = this.mainBody;
6923 if(ds.getCount() > 0){
6924 ds.data.each(function(d,rowIndex){
6925 var row = this.renderRow(cm, ds, rowIndex);
6927 tbody.createChild(row);
6931 if(row.cellObjects.length){
6932 Roo.each(row.cellObjects, function(r){
6933 _this.renderCellObject(r);
6940 var tfoot = this.el.select('tfoot', true).first();
6942 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6944 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6946 var total = this.ds.getTotalCount();
6948 if(this.footer.pageSize < total){
6949 this.mainFoot.show();
6953 Roo.each(this.el.select('tbody td', true).elements, function(e){
6954 e.on('mouseover', _this.onMouseover, _this);
6957 Roo.each(this.el.select('tbody td', true).elements, function(e){
6958 e.on('mouseout', _this.onMouseout, _this);
6960 this.fireEvent('rowsrendered', this);
6966 onUpdate : function(ds,record)
6968 this.refreshRow(record);
6972 onRemove : function(ds, record, index, isUpdate){
6973 if(isUpdate !== true){
6974 this.fireEvent("beforerowremoved", this, index, record);
6976 var bt = this.mainBody.dom;
6978 var rows = this.el.select('tbody > tr', true).elements;
6980 if(typeof(rows[index]) != 'undefined'){
6981 bt.removeChild(rows[index].dom);
6984 // if(bt.rows[index]){
6985 // bt.removeChild(bt.rows[index]);
6988 if(isUpdate !== true){
6989 //this.stripeRows(index);
6990 //this.syncRowHeights(index, index);
6992 this.fireEvent("rowremoved", this, index, record);
6996 onAdd : function(ds, records, rowIndex)
6998 //Roo.log('on Add called');
6999 // - note this does not handle multiple adding very well..
7000 var bt = this.mainBody.dom;
7001 for (var i =0 ; i < records.length;i++) {
7002 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
7003 //Roo.log(records[i]);
7004 //Roo.log(this.store.getAt(rowIndex+i));
7005 this.insertRow(this.store, rowIndex + i, false);
7012 refreshRow : function(record){
7013 var ds = this.store, index;
7014 if(typeof record == 'number'){
7016 record = ds.getAt(index);
7018 index = ds.indexOf(record);
7020 this.insertRow(ds, index, true);
7022 this.onRemove(ds, record, index+1, true);
7024 //this.syncRowHeights(index, index);
7026 this.fireEvent("rowupdated", this, index, record);
7029 insertRow : function(dm, rowIndex, isUpdate){
7032 this.fireEvent("beforerowsinserted", this, rowIndex);
7034 //var s = this.getScrollState();
7035 var row = this.renderRow(this.cm, this.store, rowIndex);
7036 // insert before rowIndex..
7037 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7041 if(row.cellObjects.length){
7042 Roo.each(row.cellObjects, function(r){
7043 _this.renderCellObject(r);
7048 this.fireEvent("rowsinserted", this, rowIndex);
7049 //this.syncRowHeights(firstRow, lastRow);
7050 //this.stripeRows(firstRow);
7057 getRowDom : function(rowIndex)
7059 var rows = this.el.select('tbody > tr', true).elements;
7061 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7064 // returns the object tree for a tr..
7067 renderRow : function(cm, ds, rowIndex)
7069 var d = ds.getAt(rowIndex);
7073 cls : 'x-row-' + rowIndex,
7077 var cellObjects = [];
7079 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7080 var config = cm.config[i];
7082 var renderer = cm.getRenderer(i);
7086 if(typeof(renderer) !== 'undefined'){
7087 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7089 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7090 // and are rendered into the cells after the row is rendered - using the id for the element.
7092 if(typeof(value) === 'object'){
7102 rowIndex : rowIndex,
7107 this.fireEvent('rowclass', this, rowcfg);
7111 cls : rowcfg.rowClass + ' x-col-' + i,
7113 html: (typeof(value) === 'object') ? '' : value
7120 if(typeof(config.colspan) != 'undefined'){
7121 td.colspan = config.colspan;
7124 if(typeof(config.hidden) != 'undefined' && config.hidden){
7125 td.style += ' display:none;';
7128 if(typeof(config.align) != 'undefined' && config.align.length){
7129 td.style += ' text-align:' + config.align + ';';
7131 if(typeof(config.valign) != 'undefined' && config.valign.length){
7132 td.style += ' vertical-align:' + config.valign + ';';
7135 if(typeof(config.width) != 'undefined'){
7136 td.style += ' width:' + config.width + 'px;';
7139 if(typeof(config.cursor) != 'undefined'){
7140 td.style += ' cursor:' + config.cursor + ';';
7143 if(typeof(config.cls) != 'undefined'){
7144 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7147 ['xs','sm','md','lg'].map(function(size){
7149 if(typeof(config[size]) == 'undefined'){
7153 if (!config[size]) { // 0 = hidden
7154 td.cls += ' hidden-' + size;
7158 td.cls += ' col-' + size + '-' + config[size];
7166 row.cellObjects = cellObjects;
7174 onBeforeLoad : function()
7183 this.el.select('tbody', true).first().dom.innerHTML = '';
7186 * Show or hide a row.
7187 * @param {Number} rowIndex to show or hide
7188 * @param {Boolean} state hide
7190 setRowVisibility : function(rowIndex, state)
7192 var bt = this.mainBody.dom;
7194 var rows = this.el.select('tbody > tr', true).elements;
7196 if(typeof(rows[rowIndex]) == 'undefined'){
7199 rows[rowIndex].dom.style.display = state ? '' : 'none';
7203 getSelectionModel : function(){
7205 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7207 return this.selModel;
7210 * Render the Roo.bootstrap object from renderder
7212 renderCellObject : function(r)
7216 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7218 var t = r.cfg.render(r.container);
7221 Roo.each(r.cfg.cn, function(c){
7223 container: t.getChildContainer(),
7226 _this.renderCellObject(child);
7231 getRowIndex : function(row)
7235 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7246 * Returns the grid's underlying element = used by panel.Grid
7247 * @return {Element} The element
7249 getGridEl : function(){
7253 * Forces a resize - used by panel.Grid
7254 * @return {Element} The element
7256 autoSize : function()
7258 //var ctr = Roo.get(this.container.dom.parentElement);
7259 var ctr = Roo.get(this.el.dom);
7261 var thd = this.getGridEl().select('thead',true).first();
7262 var tbd = this.getGridEl().select('tbody', true).first();
7263 var tfd = this.getGridEl().select('tfoot', true).first();
7265 var cw = ctr.getWidth();
7269 tbd.setSize(ctr.getWidth(),
7270 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7272 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7275 cw = Math.max(cw, this.totalWidth);
7276 this.getGridEl().select('tr',true).setWidth(cw);
7277 // resize 'expandable coloumn?
7279 return; // we doe not have a view in this design..
7282 onBodyScroll: function()
7284 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7286 this.mainHead.setStyle({
7287 'position' : 'relative',
7288 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7294 var scrollHeight = this.mainBody.dom.scrollHeight;
7296 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7298 var height = this.mainBody.getHeight();
7300 if(scrollHeight - height == scrollTop) {
7302 var total = this.ds.getTotalCount();
7304 if(this.footer.cursor + this.footer.pageSize < total){
7306 this.footer.ds.load({
7308 start : this.footer.cursor + this.footer.pageSize,
7309 limit : this.footer.pageSize
7319 onHeaderChange : function()
7321 var header = this.renderHeader();
7322 var table = this.el.select('table', true).first();
7324 this.mainHead.remove();
7325 this.mainHead = table.createChild(header, this.mainBody, false);
7328 onHiddenChange : function(colModel, colIndex, hidden)
7330 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7331 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7333 this.CSS.updateRule(thSelector, "display", "");
7334 this.CSS.updateRule(tdSelector, "display", "");
7337 this.CSS.updateRule(thSelector, "display", "none");
7338 this.CSS.updateRule(tdSelector, "display", "none");
7341 this.onHeaderChange();
7345 setColumnWidth: function(col_index, width)
7347 // width = "md-2 xs-2..."
7348 if(!this.colModel.config[col_index]) {
7352 var w = width.split(" ");
7354 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7356 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7359 for(var j = 0; j < w.length; j++) {
7365 var size_cls = w[j].split("-");
7367 if(!Number.isInteger(size_cls[1] * 1)) {
7371 if(!this.colModel.config[col_index][size_cls[0]]) {
7375 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7379 h_row[0].classList.replace(
7380 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7381 "col-"+size_cls[0]+"-"+size_cls[1]
7384 for(var i = 0; i < rows.length; i++) {
7386 var size_cls = w[j].split("-");
7388 if(!Number.isInteger(size_cls[1] * 1)) {
7392 if(!this.colModel.config[col_index][size_cls[0]]) {
7396 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7400 rows[i].classList.replace(
7401 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7402 "col-"+size_cls[0]+"-"+size_cls[1]
7406 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7421 * @class Roo.bootstrap.TableCell
7422 * @extends Roo.bootstrap.Component
7423 * Bootstrap TableCell class
7424 * @cfg {String} html cell contain text
7425 * @cfg {String} cls cell class
7426 * @cfg {String} tag cell tag (td|th) default td
7427 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7428 * @cfg {String} align Aligns the content in a cell
7429 * @cfg {String} axis Categorizes cells
7430 * @cfg {String} bgcolor Specifies the background color of a cell
7431 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7432 * @cfg {Number} colspan Specifies the number of columns a cell should span
7433 * @cfg {String} headers Specifies one or more header cells a cell is related to
7434 * @cfg {Number} height Sets the height of a cell
7435 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7436 * @cfg {Number} rowspan Sets the number of rows a cell should span
7437 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7438 * @cfg {String} valign Vertical aligns the content in a cell
7439 * @cfg {Number} width Specifies the width of a cell
7442 * Create a new TableCell
7443 * @param {Object} config The config object
7446 Roo.bootstrap.TableCell = function(config){
7447 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7450 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7470 getAutoCreate : function(){
7471 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7491 cfg.align=this.align
7497 cfg.bgcolor=this.bgcolor
7500 cfg.charoff=this.charoff
7503 cfg.colspan=this.colspan
7506 cfg.headers=this.headers
7509 cfg.height=this.height
7512 cfg.nowrap=this.nowrap
7515 cfg.rowspan=this.rowspan
7518 cfg.scope=this.scope
7521 cfg.valign=this.valign
7524 cfg.width=this.width
7543 * @class Roo.bootstrap.TableRow
7544 * @extends Roo.bootstrap.Component
7545 * Bootstrap TableRow class
7546 * @cfg {String} cls row class
7547 * @cfg {String} align Aligns the content in a table row
7548 * @cfg {String} bgcolor Specifies a background color for a table row
7549 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7550 * @cfg {String} valign Vertical aligns the content in a table row
7553 * Create a new TableRow
7554 * @param {Object} config The config object
7557 Roo.bootstrap.TableRow = function(config){
7558 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7561 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7569 getAutoCreate : function(){
7570 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7580 cfg.align = this.align;
7583 cfg.bgcolor = this.bgcolor;
7586 cfg.charoff = this.charoff;
7589 cfg.valign = this.valign;
7607 * @class Roo.bootstrap.TableBody
7608 * @extends Roo.bootstrap.Component
7609 * Bootstrap TableBody class
7610 * @cfg {String} cls element class
7611 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7612 * @cfg {String} align Aligns the content inside the element
7613 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7614 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7617 * Create a new TableBody
7618 * @param {Object} config The config object
7621 Roo.bootstrap.TableBody = function(config){
7622 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7625 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7633 getAutoCreate : function(){
7634 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7648 cfg.align = this.align;
7651 cfg.charoff = this.charoff;
7654 cfg.valign = this.valign;
7661 // initEvents : function()
7668 // this.store = Roo.factory(this.store, Roo.data);
7669 // this.store.on('load', this.onLoad, this);
7671 // this.store.load();
7675 // onLoad: function ()
7677 // this.fireEvent('load', this);
7687 * Ext JS Library 1.1.1
7688 * Copyright(c) 2006-2007, Ext JS, LLC.
7690 * Originally Released Under LGPL - original licence link has changed is not relivant.
7693 * <script type="text/javascript">
7696 // as we use this in bootstrap.
7697 Roo.namespace('Roo.form');
7699 * @class Roo.form.Action
7700 * Internal Class used to handle form actions
7702 * @param {Roo.form.BasicForm} el The form element or its id
7703 * @param {Object} config Configuration options
7708 // define the action interface
7709 Roo.form.Action = function(form, options){
7711 this.options = options || {};
7714 * Client Validation Failed
7717 Roo.form.Action.CLIENT_INVALID = 'client';
7719 * Server Validation Failed
7722 Roo.form.Action.SERVER_INVALID = 'server';
7724 * Connect to Server Failed
7727 Roo.form.Action.CONNECT_FAILURE = 'connect';
7729 * Reading Data from Server Failed
7732 Roo.form.Action.LOAD_FAILURE = 'load';
7734 Roo.form.Action.prototype = {
7736 failureType : undefined,
7737 response : undefined,
7741 run : function(options){
7746 success : function(response){
7751 handleResponse : function(response){
7755 // default connection failure
7756 failure : function(response){
7758 this.response = response;
7759 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7760 this.form.afterAction(this, false);
7763 processResponse : function(response){
7764 this.response = response;
7765 if(!response.responseText){
7768 this.result = this.handleResponse(response);
7772 // utility functions used internally
7773 getUrl : function(appendParams){
7774 var url = this.options.url || this.form.url || this.form.el.dom.action;
7776 var p = this.getParams();
7778 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7784 getMethod : function(){
7785 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7788 getParams : function(){
7789 var bp = this.form.baseParams;
7790 var p = this.options.params;
7792 if(typeof p == "object"){
7793 p = Roo.urlEncode(Roo.applyIf(p, bp));
7794 }else if(typeof p == 'string' && bp){
7795 p += '&' + Roo.urlEncode(bp);
7798 p = Roo.urlEncode(bp);
7803 createCallback : function(){
7805 success: this.success,
7806 failure: this.failure,
7808 timeout: (this.form.timeout*1000),
7809 upload: this.form.fileUpload ? this.success : undefined
7814 Roo.form.Action.Submit = function(form, options){
7815 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7818 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7821 haveProgress : false,
7822 uploadComplete : false,
7824 // uploadProgress indicator.
7825 uploadProgress : function()
7827 if (!this.form.progressUrl) {
7831 if (!this.haveProgress) {
7832 Roo.MessageBox.progress("Uploading", "Uploading");
7834 if (this.uploadComplete) {
7835 Roo.MessageBox.hide();
7839 this.haveProgress = true;
7841 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7843 var c = new Roo.data.Connection();
7845 url : this.form.progressUrl,
7850 success : function(req){
7851 //console.log(data);
7855 rdata = Roo.decode(req.responseText)
7857 Roo.log("Invalid data from server..");
7861 if (!rdata || !rdata.success) {
7863 Roo.MessageBox.alert(Roo.encode(rdata));
7866 var data = rdata.data;
7868 if (this.uploadComplete) {
7869 Roo.MessageBox.hide();
7874 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7875 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7878 this.uploadProgress.defer(2000,this);
7881 failure: function(data) {
7882 Roo.log('progress url failed ');
7893 // run get Values on the form, so it syncs any secondary forms.
7894 this.form.getValues();
7896 var o = this.options;
7897 var method = this.getMethod();
7898 var isPost = method == 'POST';
7899 if(o.clientValidation === false || this.form.isValid()){
7901 if (this.form.progressUrl) {
7902 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7903 (new Date() * 1) + '' + Math.random());
7908 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7909 form:this.form.el.dom,
7910 url:this.getUrl(!isPost),
7912 params:isPost ? this.getParams() : null,
7913 isUpload: this.form.fileUpload
7916 this.uploadProgress();
7918 }else if (o.clientValidation !== false){ // client validation failed
7919 this.failureType = Roo.form.Action.CLIENT_INVALID;
7920 this.form.afterAction(this, false);
7924 success : function(response)
7926 this.uploadComplete= true;
7927 if (this.haveProgress) {
7928 Roo.MessageBox.hide();
7932 var result = this.processResponse(response);
7933 if(result === true || result.success){
7934 this.form.afterAction(this, true);
7938 this.form.markInvalid(result.errors);
7939 this.failureType = Roo.form.Action.SERVER_INVALID;
7941 this.form.afterAction(this, false);
7943 failure : function(response)
7945 this.uploadComplete= true;
7946 if (this.haveProgress) {
7947 Roo.MessageBox.hide();
7950 this.response = response;
7951 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7952 this.form.afterAction(this, false);
7955 handleResponse : function(response){
7956 if(this.form.errorReader){
7957 var rs = this.form.errorReader.read(response);
7960 for(var i = 0, len = rs.records.length; i < len; i++) {
7961 var r = rs.records[i];
7965 if(errors.length < 1){
7969 success : rs.success,
7975 ret = Roo.decode(response.responseText);
7979 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7989 Roo.form.Action.Load = function(form, options){
7990 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7991 this.reader = this.form.reader;
7994 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7999 Roo.Ajax.request(Roo.apply(
8000 this.createCallback(), {
8001 method:this.getMethod(),
8002 url:this.getUrl(false),
8003 params:this.getParams()
8007 success : function(response){
8009 var result = this.processResponse(response);
8010 if(result === true || !result.success || !result.data){
8011 this.failureType = Roo.form.Action.LOAD_FAILURE;
8012 this.form.afterAction(this, false);
8015 this.form.clearInvalid();
8016 this.form.setValues(result.data);
8017 this.form.afterAction(this, true);
8020 handleResponse : function(response){
8021 if(this.form.reader){
8022 var rs = this.form.reader.read(response);
8023 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8025 success : rs.success,
8029 return Roo.decode(response.responseText);
8033 Roo.form.Action.ACTION_TYPES = {
8034 'load' : Roo.form.Action.Load,
8035 'submit' : Roo.form.Action.Submit
8044 * @class Roo.bootstrap.Form
8045 * @extends Roo.bootstrap.Component
8046 * Bootstrap Form class
8047 * @cfg {String} method GET | POST (default POST)
8048 * @cfg {String} labelAlign top | left (default top)
8049 * @cfg {String} align left | right - for navbars
8050 * @cfg {Boolean} loadMask load mask when submit (default true)
8055 * @param {Object} config The config object
8059 Roo.bootstrap.Form = function(config){
8061 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8063 Roo.bootstrap.Form.popover.apply();
8067 * @event clientvalidation
8068 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8069 * @param {Form} this
8070 * @param {Boolean} valid true if the form has passed client-side validation
8072 clientvalidation: true,
8074 * @event beforeaction
8075 * Fires before any action is performed. Return false to cancel the action.
8076 * @param {Form} this
8077 * @param {Action} action The action to be performed
8081 * @event actionfailed
8082 * Fires when an action fails.
8083 * @param {Form} this
8084 * @param {Action} action The action that failed
8086 actionfailed : true,
8088 * @event actioncomplete
8089 * Fires when an action is completed.
8090 * @param {Form} this
8091 * @param {Action} action The action that completed
8093 actioncomplete : true
8097 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8100 * @cfg {String} method
8101 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8106 * The URL to use for form actions if one isn't supplied in the action options.
8109 * @cfg {Boolean} fileUpload
8110 * Set to true if this form is a file upload.
8114 * @cfg {Object} baseParams
8115 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8119 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8123 * @cfg {Sting} align (left|right) for navbar forms
8128 activeAction : null,
8131 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8132 * element by passing it or its id or mask the form itself by passing in true.
8135 waitMsgTarget : false,
8140 * @cfg {Boolean} errorMask (true|false) default false
8145 * @cfg {Number} maskOffset Default 100
8150 * @cfg {Boolean} maskBody
8154 getAutoCreate : function(){
8158 method : this.method || 'POST',
8159 id : this.id || Roo.id(),
8162 if (this.parent().xtype.match(/^Nav/)) {
8163 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8167 if (this.labelAlign == 'left' ) {
8168 cfg.cls += ' form-horizontal';
8174 initEvents : function()
8176 this.el.on('submit', this.onSubmit, this);
8177 // this was added as random key presses on the form where triggering form submit.
8178 this.el.on('keypress', function(e) {
8179 if (e.getCharCode() != 13) {
8182 // we might need to allow it for textareas.. and some other items.
8183 // check e.getTarget().
8185 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8189 Roo.log("keypress blocked");
8197 onSubmit : function(e){
8202 * Returns true if client-side validation on the form is successful.
8205 isValid : function(){
8206 var items = this.getItems();
8210 items.each(function(f){
8216 Roo.log('invalid field: ' + f.name);
8220 if(!target && f.el.isVisible(true)){
8226 if(this.errorMask && !valid){
8227 Roo.bootstrap.Form.popover.mask(this, target);
8234 * Returns true if any fields in this form have changed since their original load.
8237 isDirty : function(){
8239 var items = this.getItems();
8240 items.each(function(f){
8250 * Performs a predefined action (submit or load) or custom actions you define on this form.
8251 * @param {String} actionName The name of the action type
8252 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8253 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8254 * accept other config options):
8256 Property Type Description
8257 ---------------- --------------- ----------------------------------------------------------------------------------
8258 url String The url for the action (defaults to the form's url)
8259 method String The form method to use (defaults to the form's method, or POST if not defined)
8260 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8261 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8262 validate the form on the client (defaults to false)
8264 * @return {BasicForm} this
8266 doAction : function(action, options){
8267 if(typeof action == 'string'){
8268 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8270 if(this.fireEvent('beforeaction', this, action) !== false){
8271 this.beforeAction(action);
8272 action.run.defer(100, action);
8278 beforeAction : function(action){
8279 var o = action.options;
8284 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8286 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8289 // not really supported yet.. ??
8291 //if(this.waitMsgTarget === true){
8292 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8293 //}else if(this.waitMsgTarget){
8294 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8295 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8297 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8303 afterAction : function(action, success){
8304 this.activeAction = null;
8305 var o = action.options;
8310 Roo.get(document.body).unmask();
8316 //if(this.waitMsgTarget === true){
8317 // this.el.unmask();
8318 //}else if(this.waitMsgTarget){
8319 // this.waitMsgTarget.unmask();
8321 // Roo.MessageBox.updateProgress(1);
8322 // Roo.MessageBox.hide();
8329 Roo.callback(o.success, o.scope, [this, action]);
8330 this.fireEvent('actioncomplete', this, action);
8334 // failure condition..
8335 // we have a scenario where updates need confirming.
8336 // eg. if a locking scenario exists..
8337 // we look for { errors : { needs_confirm : true }} in the response.
8339 (typeof(action.result) != 'undefined') &&
8340 (typeof(action.result.errors) != 'undefined') &&
8341 (typeof(action.result.errors.needs_confirm) != 'undefined')
8344 Roo.log("not supported yet");
8347 Roo.MessageBox.confirm(
8348 "Change requires confirmation",
8349 action.result.errorMsg,
8354 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8364 Roo.callback(o.failure, o.scope, [this, action]);
8365 // show an error message if no failed handler is set..
8366 if (!this.hasListener('actionfailed')) {
8367 Roo.log("need to add dialog support");
8369 Roo.MessageBox.alert("Error",
8370 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8371 action.result.errorMsg :
8372 "Saving Failed, please check your entries or try again"
8377 this.fireEvent('actionfailed', this, action);
8382 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8383 * @param {String} id The value to search for
8386 findField : function(id){
8387 var items = this.getItems();
8388 var field = items.get(id);
8390 items.each(function(f){
8391 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8398 return field || null;
8401 * Mark fields in this form invalid in bulk.
8402 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8403 * @return {BasicForm} this
8405 markInvalid : function(errors){
8406 if(errors instanceof Array){
8407 for(var i = 0, len = errors.length; i < len; i++){
8408 var fieldError = errors[i];
8409 var f = this.findField(fieldError.id);
8411 f.markInvalid(fieldError.msg);
8417 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8418 field.markInvalid(errors[id]);
8422 //Roo.each(this.childForms || [], function (f) {
8423 // f.markInvalid(errors);
8430 * Set values for fields in this form in bulk.
8431 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8432 * @return {BasicForm} this
8434 setValues : function(values){
8435 if(values instanceof Array){ // array of objects
8436 for(var i = 0, len = values.length; i < len; i++){
8438 var f = this.findField(v.id);
8440 f.setValue(v.value);
8441 if(this.trackResetOnLoad){
8442 f.originalValue = f.getValue();
8446 }else{ // object hash
8449 if(typeof values[id] != 'function' && (field = this.findField(id))){
8451 if (field.setFromData &&
8453 field.displayField &&
8454 // combos' with local stores can
8455 // be queried via setValue()
8456 // to set their value..
8457 (field.store && !field.store.isLocal)
8461 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8462 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8463 field.setFromData(sd);
8465 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8467 field.setFromData(values);
8470 field.setValue(values[id]);
8474 if(this.trackResetOnLoad){
8475 field.originalValue = field.getValue();
8481 //Roo.each(this.childForms || [], function (f) {
8482 // f.setValues(values);
8489 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8490 * they are returned as an array.
8491 * @param {Boolean} asString
8494 getValues : function(asString){
8495 //if (this.childForms) {
8496 // copy values from the child forms
8497 // Roo.each(this.childForms, function (f) {
8498 // this.setValues(f.getValues());
8504 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8505 if(asString === true){
8508 return Roo.urlDecode(fs);
8512 * Returns the fields in this form as an object with key/value pairs.
8513 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8516 getFieldValues : function(with_hidden)
8518 var items = this.getItems();
8520 items.each(function(f){
8526 var v = f.getValue();
8528 if (f.inputType =='radio') {
8529 if (typeof(ret[f.getName()]) == 'undefined') {
8530 ret[f.getName()] = ''; // empty..
8533 if (!f.el.dom.checked) {
8541 if(f.xtype == 'MoneyField'){
8542 ret[f.currencyName] = f.getCurrency();
8545 // not sure if this supported any more..
8546 if ((typeof(v) == 'object') && f.getRawValue) {
8547 v = f.getRawValue() ; // dates..
8549 // combo boxes where name != hiddenName...
8550 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8551 ret[f.name] = f.getRawValue();
8553 ret[f.getName()] = v;
8560 * Clears all invalid messages in this form.
8561 * @return {BasicForm} this
8563 clearInvalid : function(){
8564 var items = this.getItems();
8566 items.each(function(f){
8575 * @return {BasicForm} this
8578 var items = this.getItems();
8579 items.each(function(f){
8583 Roo.each(this.childForms || [], function (f) {
8591 getItems : function()
8593 var r=new Roo.util.MixedCollection(false, function(o){
8594 return o.id || (o.id = Roo.id());
8596 var iter = function(el) {
8603 Roo.each(el.items,function(e) {
8612 hideFields : function(items)
8614 Roo.each(items, function(i){
8616 var f = this.findField(i);
8627 showFields : function(items)
8629 Roo.each(items, function(i){
8631 var f = this.findField(i);
8644 Roo.apply(Roo.bootstrap.Form, {
8671 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8672 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8673 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8674 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8677 this.maskEl.top.enableDisplayMode("block");
8678 this.maskEl.left.enableDisplayMode("block");
8679 this.maskEl.bottom.enableDisplayMode("block");
8680 this.maskEl.right.enableDisplayMode("block");
8682 this.toolTip = new Roo.bootstrap.Tooltip({
8683 cls : 'roo-form-error-popover',
8685 'left' : ['r-l', [-2,0], 'right'],
8686 'right' : ['l-r', [2,0], 'left'],
8687 'bottom' : ['tl-bl', [0,2], 'top'],
8688 'top' : [ 'bl-tl', [0,-2], 'bottom']
8692 this.toolTip.render(Roo.get(document.body));
8694 this.toolTip.el.enableDisplayMode("block");
8696 Roo.get(document.body).on('click', function(){
8700 Roo.get(document.body).on('touchstart', function(){
8704 this.isApplied = true
8707 mask : function(form, target)
8711 this.target = target;
8713 if(!this.form.errorMask || !target.el){
8717 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8719 Roo.log(scrollable);
8721 var ot = this.target.el.calcOffsetsTo(scrollable);
8723 var scrollTo = ot[1] - this.form.maskOffset;
8725 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8727 scrollable.scrollTo('top', scrollTo);
8729 var box = this.target.el.getBox();
8731 var zIndex = Roo.bootstrap.Modal.zIndex++;
8734 this.maskEl.top.setStyle('position', 'absolute');
8735 this.maskEl.top.setStyle('z-index', zIndex);
8736 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8737 this.maskEl.top.setLeft(0);
8738 this.maskEl.top.setTop(0);
8739 this.maskEl.top.show();
8741 this.maskEl.left.setStyle('position', 'absolute');
8742 this.maskEl.left.setStyle('z-index', zIndex);
8743 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8744 this.maskEl.left.setLeft(0);
8745 this.maskEl.left.setTop(box.y - this.padding);
8746 this.maskEl.left.show();
8748 this.maskEl.bottom.setStyle('position', 'absolute');
8749 this.maskEl.bottom.setStyle('z-index', zIndex);
8750 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8751 this.maskEl.bottom.setLeft(0);
8752 this.maskEl.bottom.setTop(box.bottom + this.padding);
8753 this.maskEl.bottom.show();
8755 this.maskEl.right.setStyle('position', 'absolute');
8756 this.maskEl.right.setStyle('z-index', zIndex);
8757 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8758 this.maskEl.right.setLeft(box.right + this.padding);
8759 this.maskEl.right.setTop(box.y - this.padding);
8760 this.maskEl.right.show();
8762 this.toolTip.bindEl = this.target.el;
8764 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8766 var tip = this.target.blankText;
8768 if(this.target.getValue() !== '' ) {
8770 if (this.target.invalidText.length) {
8771 tip = this.target.invalidText;
8772 } else if (this.target.regexText.length){
8773 tip = this.target.regexText;
8777 this.toolTip.show(tip);
8779 this.intervalID = window.setInterval(function() {
8780 Roo.bootstrap.Form.popover.unmask();
8783 window.onwheel = function(){ return false;};
8785 (function(){ this.isMasked = true; }).defer(500, this);
8791 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8795 this.maskEl.top.setStyle('position', 'absolute');
8796 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8797 this.maskEl.top.hide();
8799 this.maskEl.left.setStyle('position', 'absolute');
8800 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8801 this.maskEl.left.hide();
8803 this.maskEl.bottom.setStyle('position', 'absolute');
8804 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8805 this.maskEl.bottom.hide();
8807 this.maskEl.right.setStyle('position', 'absolute');
8808 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8809 this.maskEl.right.hide();
8811 this.toolTip.hide();
8813 this.toolTip.el.hide();
8815 window.onwheel = function(){ return true;};
8817 if(this.intervalID){
8818 window.clearInterval(this.intervalID);
8819 this.intervalID = false;
8822 this.isMasked = false;
8832 * Ext JS Library 1.1.1
8833 * Copyright(c) 2006-2007, Ext JS, LLC.
8835 * Originally Released Under LGPL - original licence link has changed is not relivant.
8838 * <script type="text/javascript">
8841 * @class Roo.form.VTypes
8842 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8845 Roo.form.VTypes = function(){
8846 // closure these in so they are only created once.
8847 var alpha = /^[a-zA-Z_]+$/;
8848 var alphanum = /^[a-zA-Z0-9_]+$/;
8849 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8850 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8852 // All these messages and functions are configurable
8855 * The function used to validate email addresses
8856 * @param {String} value The email address
8858 'email' : function(v){
8859 return email.test(v);
8862 * The error text to display when the email validation function returns false
8865 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8867 * The keystroke filter mask to be applied on email input
8870 'emailMask' : /[a-z0-9_\.\-@]/i,
8873 * The function used to validate URLs
8874 * @param {String} value The URL
8876 'url' : function(v){
8880 * The error text to display when the url validation function returns false
8883 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8886 * The function used to validate alpha values
8887 * @param {String} value The value
8889 'alpha' : function(v){
8890 return alpha.test(v);
8893 * The error text to display when the alpha validation function returns false
8896 'alphaText' : 'This field should only contain letters and _',
8898 * The keystroke filter mask to be applied on alpha input
8901 'alphaMask' : /[a-z_]/i,
8904 * The function used to validate alphanumeric values
8905 * @param {String} value The value
8907 'alphanum' : function(v){
8908 return alphanum.test(v);
8911 * The error text to display when the alphanumeric validation function returns false
8914 'alphanumText' : 'This field should only contain letters, numbers and _',
8916 * The keystroke filter mask to be applied on alphanumeric input
8919 'alphanumMask' : /[a-z0-9_]/i
8929 * @class Roo.bootstrap.Input
8930 * @extends Roo.bootstrap.Component
8931 * Bootstrap Input class
8932 * @cfg {Boolean} disabled is it disabled
8933 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8934 * @cfg {String} name name of the input
8935 * @cfg {string} fieldLabel - the label associated
8936 * @cfg {string} placeholder - placeholder to put in text.
8937 * @cfg {string} before - input group add on before
8938 * @cfg {string} after - input group add on after
8939 * @cfg {string} size - (lg|sm) or leave empty..
8940 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8941 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8942 * @cfg {Number} md colspan out of 12 for computer-sized screens
8943 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8944 * @cfg {string} value default value of the input
8945 * @cfg {Number} labelWidth set the width of label
8946 * @cfg {Number} labellg set the width of label (1-12)
8947 * @cfg {Number} labelmd set the width of label (1-12)
8948 * @cfg {Number} labelsm set the width of label (1-12)
8949 * @cfg {Number} labelxs set the width of label (1-12)
8950 * @cfg {String} labelAlign (top|left)
8951 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8952 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8953 * @cfg {String} indicatorpos (left|right) default left
8954 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8955 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8957 * @cfg {String} align (left|center|right) Default left
8958 * @cfg {Boolean} forceFeedback (true|false) Default false
8961 * Create a new Input
8962 * @param {Object} config The config object
8965 Roo.bootstrap.Input = function(config){
8967 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8972 * Fires when this field receives input focus.
8973 * @param {Roo.form.Field} this
8978 * Fires when this field loses input focus.
8979 * @param {Roo.form.Field} this
8984 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8985 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8986 * @param {Roo.form.Field} this
8987 * @param {Roo.EventObject} e The event object
8992 * Fires just before the field blurs if the field value has changed.
8993 * @param {Roo.form.Field} this
8994 * @param {Mixed} newValue The new value
8995 * @param {Mixed} oldValue The original value
9000 * Fires after the field has been marked as invalid.
9001 * @param {Roo.form.Field} this
9002 * @param {String} msg The validation message
9007 * Fires after the field has been validated with no errors.
9008 * @param {Roo.form.Field} this
9013 * Fires after the key up
9014 * @param {Roo.form.Field} this
9015 * @param {Roo.EventObject} e The event Object
9021 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9023 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9024 automatic validation (defaults to "keyup").
9026 validationEvent : "keyup",
9028 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9030 validateOnBlur : true,
9032 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9034 validationDelay : 250,
9036 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9038 focusClass : "x-form-focus", // not needed???
9042 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9044 invalidClass : "has-warning",
9047 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9049 validClass : "has-success",
9052 * @cfg {Boolean} hasFeedback (true|false) default true
9057 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9059 invalidFeedbackClass : "glyphicon-warning-sign",
9062 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9064 validFeedbackClass : "glyphicon-ok",
9067 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9069 selectOnFocus : false,
9072 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9076 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9081 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9083 disableKeyFilter : false,
9086 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9090 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9094 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9096 blankText : "Please complete this mandatory field",
9099 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9103 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9105 maxLength : Number.MAX_VALUE,
9107 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9109 minLengthText : "The minimum length for this field is {0}",
9111 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9113 maxLengthText : "The maximum length for this field is {0}",
9117 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9118 * If available, this function will be called only after the basic validators all return true, and will be passed the
9119 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9123 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9124 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9125 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9129 * @cfg {String} regexText -- Depricated - use Invalid Text
9134 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9140 autocomplete: false,
9159 formatedValue : false,
9160 forceFeedback : false,
9162 indicatorpos : 'left',
9172 parentLabelAlign : function()
9175 while (parent.parent()) {
9176 parent = parent.parent();
9177 if (typeof(parent.labelAlign) !='undefined') {
9178 return parent.labelAlign;
9185 getAutoCreate : function()
9187 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9193 if(this.inputType != 'hidden'){
9194 cfg.cls = 'form-group' //input-group
9200 type : this.inputType,
9202 cls : 'form-control',
9203 placeholder : this.placeholder || '',
9204 autocomplete : this.autocomplete || 'new-password'
9207 if(this.capture.length){
9208 input.capture = this.capture;
9211 if(this.accept.length){
9212 input.accept = this.accept + "/*";
9216 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9219 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9220 input.maxLength = this.maxLength;
9223 if (this.disabled) {
9224 input.disabled=true;
9227 if (this.readOnly) {
9228 input.readonly=true;
9232 input.name = this.name;
9236 input.cls += ' input-' + this.size;
9240 ['xs','sm','md','lg'].map(function(size){
9241 if (settings[size]) {
9242 cfg.cls += ' col-' + size + '-' + settings[size];
9246 var inputblock = input;
9250 cls: 'glyphicon form-control-feedback'
9253 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9256 cls : 'has-feedback',
9264 if (this.before || this.after) {
9267 cls : 'input-group',
9271 if (this.before && typeof(this.before) == 'string') {
9273 inputblock.cn.push({
9275 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9279 if (this.before && typeof(this.before) == 'object') {
9280 this.before = Roo.factory(this.before);
9282 inputblock.cn.push({
9284 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9285 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9289 inputblock.cn.push(input);
9291 if (this.after && typeof(this.after) == 'string') {
9292 inputblock.cn.push({
9294 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9298 if (this.after && typeof(this.after) == 'object') {
9299 this.after = Roo.factory(this.after);
9301 inputblock.cn.push({
9303 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9304 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9308 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9309 inputblock.cls += ' has-feedback';
9310 inputblock.cn.push(feedback);
9315 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9316 tooltip : 'This field is required'
9318 if (Roo.bootstrap.version == 4) {
9321 style : 'display-none'
9324 if (align ==='left' && this.fieldLabel.length) {
9326 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9333 cls : 'control-label col-form-label',
9334 html : this.fieldLabel
9345 var labelCfg = cfg.cn[1];
9346 var contentCfg = cfg.cn[2];
9348 if(this.indicatorpos == 'right'){
9353 cls : 'control-label col-form-label',
9357 html : this.fieldLabel
9371 labelCfg = cfg.cn[0];
9372 contentCfg = cfg.cn[1];
9376 if(this.labelWidth > 12){
9377 labelCfg.style = "width: " + this.labelWidth + 'px';
9380 if(this.labelWidth < 13 && this.labelmd == 0){
9381 this.labelmd = this.labelWidth;
9384 if(this.labellg > 0){
9385 labelCfg.cls += ' col-lg-' + this.labellg;
9386 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9389 if(this.labelmd > 0){
9390 labelCfg.cls += ' col-md-' + this.labelmd;
9391 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9394 if(this.labelsm > 0){
9395 labelCfg.cls += ' col-sm-' + this.labelsm;
9396 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9399 if(this.labelxs > 0){
9400 labelCfg.cls += ' col-xs-' + this.labelxs;
9401 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9405 } else if ( this.fieldLabel.length) {
9410 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9411 tooltip : 'This field is required'
9415 //cls : 'input-group-addon',
9416 html : this.fieldLabel
9424 if(this.indicatorpos == 'right'){
9429 //cls : 'input-group-addon',
9430 html : this.fieldLabel
9435 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9436 tooltip : 'This field is required'
9456 if (this.parentType === 'Navbar' && this.parent().bar) {
9457 cfg.cls += ' navbar-form';
9460 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9461 // on BS4 we do this only if not form
9462 cfg.cls += ' navbar-form';
9470 * return the real input element.
9472 inputEl: function ()
9474 return this.el.select('input.form-control',true).first();
9477 tooltipEl : function()
9479 return this.inputEl();
9482 indicatorEl : function()
9484 if (Roo.bootstrap.version == 4) {
9485 return false; // not enabled in v4 yet.
9488 var indicator = this.el.select('i.roo-required-indicator',true).first();
9498 setDisabled : function(v)
9500 var i = this.inputEl().dom;
9502 i.removeAttribute('disabled');
9506 i.setAttribute('disabled','true');
9508 initEvents : function()
9511 this.inputEl().on("keydown" , this.fireKey, this);
9512 this.inputEl().on("focus", this.onFocus, this);
9513 this.inputEl().on("blur", this.onBlur, this);
9515 this.inputEl().relayEvent('keyup', this);
9517 this.indicator = this.indicatorEl();
9520 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9523 // reference to original value for reset
9524 this.originalValue = this.getValue();
9525 //Roo.form.TextField.superclass.initEvents.call(this);
9526 if(this.validationEvent == 'keyup'){
9527 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9528 this.inputEl().on('keyup', this.filterValidation, this);
9530 else if(this.validationEvent !== false){
9531 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9534 if(this.selectOnFocus){
9535 this.on("focus", this.preFocus, this);
9538 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9539 this.inputEl().on("keypress", this.filterKeys, this);
9541 this.inputEl().relayEvent('keypress', this);
9544 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9545 this.el.on("click", this.autoSize, this);
9548 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9549 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9552 if (typeof(this.before) == 'object') {
9553 this.before.render(this.el.select('.roo-input-before',true).first());
9555 if (typeof(this.after) == 'object') {
9556 this.after.render(this.el.select('.roo-input-after',true).first());
9559 this.inputEl().on('change', this.onChange, this);
9562 filterValidation : function(e){
9563 if(!e.isNavKeyPress()){
9564 this.validationTask.delay(this.validationDelay);
9568 * Validates the field value
9569 * @return {Boolean} True if the value is valid, else false
9571 validate : function(){
9572 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9573 if(this.disabled || this.validateValue(this.getRawValue())){
9584 * Validates a value according to the field's validation rules and marks the field as invalid
9585 * if the validation fails
9586 * @param {Mixed} value The value to validate
9587 * @return {Boolean} True if the value is valid, else false
9589 validateValue : function(value)
9591 if(this.getVisibilityEl().hasClass('hidden')){
9595 if(value.length < 1) { // if it's blank
9596 if(this.allowBlank){
9602 if(value.length < this.minLength){
9605 if(value.length > this.maxLength){
9609 var vt = Roo.form.VTypes;
9610 if(!vt[this.vtype](value, this)){
9614 if(typeof this.validator == "function"){
9615 var msg = this.validator(value);
9619 if (typeof(msg) == 'string') {
9620 this.invalidText = msg;
9624 if(this.regex && !this.regex.test(value)){
9632 fireKey : function(e){
9633 //Roo.log('field ' + e.getKey());
9634 if(e.isNavKeyPress()){
9635 this.fireEvent("specialkey", this, e);
9638 focus : function (selectText){
9640 this.inputEl().focus();
9641 if(selectText === true){
9642 this.inputEl().dom.select();
9648 onFocus : function(){
9649 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9650 // this.el.addClass(this.focusClass);
9653 this.hasFocus = true;
9654 this.startValue = this.getValue();
9655 this.fireEvent("focus", this);
9659 beforeBlur : Roo.emptyFn,
9663 onBlur : function(){
9665 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9666 //this.el.removeClass(this.focusClass);
9668 this.hasFocus = false;
9669 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9672 var v = this.getValue();
9673 if(String(v) !== String(this.startValue)){
9674 this.fireEvent('change', this, v, this.startValue);
9676 this.fireEvent("blur", this);
9679 onChange : function(e)
9681 var v = this.getValue();
9682 if(String(v) !== String(this.startValue)){
9683 this.fireEvent('change', this, v, this.startValue);
9689 * Resets the current field value to the originally loaded value and clears any validation messages
9692 this.setValue(this.originalValue);
9696 * Returns the name of the field
9697 * @return {Mixed} name The name field
9699 getName: function(){
9703 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9704 * @return {Mixed} value The field value
9706 getValue : function(){
9708 var v = this.inputEl().getValue();
9713 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9714 * @return {Mixed} value The field value
9716 getRawValue : function(){
9717 var v = this.inputEl().getValue();
9723 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9724 * @param {Mixed} value The value to set
9726 setRawValue : function(v){
9727 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9730 selectText : function(start, end){
9731 var v = this.getRawValue();
9733 start = start === undefined ? 0 : start;
9734 end = end === undefined ? v.length : end;
9735 var d = this.inputEl().dom;
9736 if(d.setSelectionRange){
9737 d.setSelectionRange(start, end);
9738 }else if(d.createTextRange){
9739 var range = d.createTextRange();
9740 range.moveStart("character", start);
9741 range.moveEnd("character", v.length-end);
9748 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9749 * @param {Mixed} value The value to set
9751 setValue : function(v){
9754 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9760 processValue : function(value){
9761 if(this.stripCharsRe){
9762 var newValue = value.replace(this.stripCharsRe, '');
9763 if(newValue !== value){
9764 this.setRawValue(newValue);
9771 preFocus : function(){
9773 if(this.selectOnFocus){
9774 this.inputEl().dom.select();
9777 filterKeys : function(e){
9779 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9782 var c = e.getCharCode(), cc = String.fromCharCode(c);
9783 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9786 if(!this.maskRe.test(cc)){
9791 * Clear any invalid styles/messages for this field
9793 clearInvalid : function(){
9795 if(!this.el || this.preventMark){ // not rendered
9800 this.el.removeClass([this.invalidClass, 'is-invalid']);
9802 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9804 var feedback = this.el.select('.form-control-feedback', true).first();
9807 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9813 this.indicator.removeClass('visible');
9814 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9817 this.fireEvent('valid', this);
9821 * Mark this field as valid
9823 markValid : function()
9825 if(!this.el || this.preventMark){ // not rendered...
9829 this.el.removeClass([this.invalidClass, this.validClass]);
9830 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9832 var feedback = this.el.select('.form-control-feedback', true).first();
9835 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9839 this.indicator.removeClass('visible');
9840 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9847 if(this.allowBlank && !this.getRawValue().length){
9850 if (Roo.bootstrap.version == 3) {
9851 this.el.addClass(this.validClass);
9853 this.inputEl().addClass('is-valid');
9856 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9858 var feedback = this.el.select('.form-control-feedback', true).first();
9861 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9862 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9867 this.fireEvent('valid', this);
9871 * Mark this field as invalid
9872 * @param {String} msg The validation message
9874 markInvalid : function(msg)
9876 if(!this.el || this.preventMark){ // not rendered
9880 this.el.removeClass([this.invalidClass, this.validClass]);
9881 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9883 var feedback = this.el.select('.form-control-feedback', true).first();
9886 this.el.select('.form-control-feedback', true).first().removeClass(
9887 [this.invalidFeedbackClass, this.validFeedbackClass]);
9894 if(this.allowBlank && !this.getRawValue().length){
9899 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9900 this.indicator.addClass('visible');
9902 if (Roo.bootstrap.version == 3) {
9903 this.el.addClass(this.invalidClass);
9905 this.inputEl().addClass('is-invalid');
9910 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9912 var feedback = this.el.select('.form-control-feedback', true).first();
9915 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9917 if(this.getValue().length || this.forceFeedback){
9918 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9925 this.fireEvent('invalid', this, msg);
9928 SafariOnKeyDown : function(event)
9930 // this is a workaround for a password hang bug on chrome/ webkit.
9931 if (this.inputEl().dom.type != 'password') {
9935 var isSelectAll = false;
9937 if(this.inputEl().dom.selectionEnd > 0){
9938 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9940 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9941 event.preventDefault();
9946 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9948 event.preventDefault();
9949 // this is very hacky as keydown always get's upper case.
9951 var cc = String.fromCharCode(event.getCharCode());
9952 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9956 adjustWidth : function(tag, w){
9957 tag = tag.toLowerCase();
9958 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9959 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9963 if(tag == 'textarea'){
9966 }else if(Roo.isOpera){
9970 if(tag == 'textarea'){
9978 setFieldLabel : function(v)
9984 if(this.indicatorEl()){
9985 var ar = this.el.select('label > span',true);
9987 if (ar.elements.length) {
9988 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9989 this.fieldLabel = v;
9993 var br = this.el.select('label',true);
9995 if(br.elements.length) {
9996 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9997 this.fieldLabel = v;
10001 Roo.log('Cannot Found any of label > span || label in input');
10005 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10006 this.fieldLabel = v;
10021 * @class Roo.bootstrap.TextArea
10022 * @extends Roo.bootstrap.Input
10023 * Bootstrap TextArea class
10024 * @cfg {Number} cols Specifies the visible width of a text area
10025 * @cfg {Number} rows Specifies the visible number of lines in a text area
10026 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10027 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10028 * @cfg {string} html text
10031 * Create a new TextArea
10032 * @param {Object} config The config object
10035 Roo.bootstrap.TextArea = function(config){
10036 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10040 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10050 getAutoCreate : function(){
10052 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10058 if(this.inputType != 'hidden'){
10059 cfg.cls = 'form-group' //input-group
10067 value : this.value || '',
10068 html: this.html || '',
10069 cls : 'form-control',
10070 placeholder : this.placeholder || ''
10074 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10075 input.maxLength = this.maxLength;
10079 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10083 input.cols = this.cols;
10086 if (this.readOnly) {
10087 input.readonly = true;
10091 input.name = this.name;
10095 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10099 ['xs','sm','md','lg'].map(function(size){
10100 if (settings[size]) {
10101 cfg.cls += ' col-' + size + '-' + settings[size];
10105 var inputblock = input;
10107 if(this.hasFeedback && !this.allowBlank){
10111 cls: 'glyphicon form-control-feedback'
10115 cls : 'has-feedback',
10124 if (this.before || this.after) {
10127 cls : 'input-group',
10131 inputblock.cn.push({
10133 cls : 'input-group-addon',
10138 inputblock.cn.push(input);
10140 if(this.hasFeedback && !this.allowBlank){
10141 inputblock.cls += ' has-feedback';
10142 inputblock.cn.push(feedback);
10146 inputblock.cn.push({
10148 cls : 'input-group-addon',
10155 if (align ==='left' && this.fieldLabel.length) {
10160 cls : 'control-label',
10161 html : this.fieldLabel
10172 if(this.labelWidth > 12){
10173 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10176 if(this.labelWidth < 13 && this.labelmd == 0){
10177 this.labelmd = this.labelWidth;
10180 if(this.labellg > 0){
10181 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10182 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10185 if(this.labelmd > 0){
10186 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10187 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10190 if(this.labelsm > 0){
10191 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10192 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10195 if(this.labelxs > 0){
10196 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10197 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10200 } else if ( this.fieldLabel.length) {
10205 //cls : 'input-group-addon',
10206 html : this.fieldLabel
10224 if (this.disabled) {
10225 input.disabled=true;
10232 * return the real textarea element.
10234 inputEl: function ()
10236 return this.el.select('textarea.form-control',true).first();
10240 * Clear any invalid styles/messages for this field
10242 clearInvalid : function()
10245 if(!this.el || this.preventMark){ // not rendered
10249 var label = this.el.select('label', true).first();
10250 var icon = this.el.select('i.fa-star', true).first();
10255 this.el.removeClass( this.validClass);
10256 this.inputEl().removeClass('is-invalid');
10258 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10260 var feedback = this.el.select('.form-control-feedback', true).first();
10263 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10268 this.fireEvent('valid', this);
10272 * Mark this field as valid
10274 markValid : function()
10276 if(!this.el || this.preventMark){ // not rendered
10280 this.el.removeClass([this.invalidClass, this.validClass]);
10281 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10283 var feedback = this.el.select('.form-control-feedback', true).first();
10286 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10289 if(this.disabled || this.allowBlank){
10293 var label = this.el.select('label', true).first();
10294 var icon = this.el.select('i.fa-star', true).first();
10299 if (Roo.bootstrap.version == 3) {
10300 this.el.addClass(this.validClass);
10302 this.inputEl().addClass('is-valid');
10306 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10308 var feedback = this.el.select('.form-control-feedback', true).first();
10311 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10312 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10317 this.fireEvent('valid', this);
10321 * Mark this field as invalid
10322 * @param {String} msg The validation message
10324 markInvalid : function(msg)
10326 if(!this.el || this.preventMark){ // not rendered
10330 this.el.removeClass([this.invalidClass, this.validClass]);
10331 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10333 var feedback = this.el.select('.form-control-feedback', true).first();
10336 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10339 if(this.disabled || this.allowBlank){
10343 var label = this.el.select('label', true).first();
10344 var icon = this.el.select('i.fa-star', true).first();
10346 if(!this.getValue().length && label && !icon){
10347 this.el.createChild({
10349 cls : 'text-danger fa fa-lg fa-star',
10350 tooltip : 'This field is required',
10351 style : 'margin-right:5px;'
10355 if (Roo.bootstrap.version == 3) {
10356 this.el.addClass(this.invalidClass);
10358 this.inputEl().addClass('is-invalid');
10361 // fixme ... this may be depricated need to test..
10362 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10364 var feedback = this.el.select('.form-control-feedback', true).first();
10367 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10369 if(this.getValue().length || this.forceFeedback){
10370 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10377 this.fireEvent('invalid', this, msg);
10385 * trigger field - base class for combo..
10390 * @class Roo.bootstrap.TriggerField
10391 * @extends Roo.bootstrap.Input
10392 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10393 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10394 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10395 * for which you can provide a custom implementation. For example:
10397 var trigger = new Roo.bootstrap.TriggerField();
10398 trigger.onTriggerClick = myTriggerFn;
10399 trigger.applyTo('my-field');
10402 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10403 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10404 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10405 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10406 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10409 * Create a new TriggerField.
10410 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10411 * to the base TextField)
10413 Roo.bootstrap.TriggerField = function(config){
10414 this.mimicing = false;
10415 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10418 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10420 * @cfg {String} triggerClass A CSS class to apply to the trigger
10423 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10428 * @cfg {Boolean} removable (true|false) special filter default false
10432 /** @cfg {Boolean} grow @hide */
10433 /** @cfg {Number} growMin @hide */
10434 /** @cfg {Number} growMax @hide */
10440 autoSize: Roo.emptyFn,
10444 deferHeight : true,
10447 actionMode : 'wrap',
10452 getAutoCreate : function(){
10454 var align = this.labelAlign || this.parentLabelAlign();
10459 cls: 'form-group' //input-group
10466 type : this.inputType,
10467 cls : 'form-control',
10468 autocomplete: 'new-password',
10469 placeholder : this.placeholder || ''
10473 input.name = this.name;
10476 input.cls += ' input-' + this.size;
10479 if (this.disabled) {
10480 input.disabled=true;
10483 var inputblock = input;
10485 if(this.hasFeedback && !this.allowBlank){
10489 cls: 'glyphicon form-control-feedback'
10492 if(this.removable && !this.editable && !this.tickable){
10494 cls : 'has-feedback',
10500 cls : 'roo-combo-removable-btn close'
10507 cls : 'has-feedback',
10516 if(this.removable && !this.editable && !this.tickable){
10518 cls : 'roo-removable',
10524 cls : 'roo-combo-removable-btn close'
10531 if (this.before || this.after) {
10534 cls : 'input-group',
10538 inputblock.cn.push({
10540 cls : 'input-group-addon input-group-prepend input-group-text',
10545 inputblock.cn.push(input);
10547 if(this.hasFeedback && !this.allowBlank){
10548 inputblock.cls += ' has-feedback';
10549 inputblock.cn.push(feedback);
10553 inputblock.cn.push({
10555 cls : 'input-group-addon input-group-append input-group-text',
10564 var ibwrap = inputblock;
10569 cls: 'roo-select2-choices',
10573 cls: 'roo-select2-search-field',
10585 cls: 'roo-select2-container input-group',
10590 cls: 'form-hidden-field'
10596 if(!this.multiple && this.showToggleBtn){
10602 if (this.caret != false) {
10605 cls: 'fa fa-' + this.caret
10612 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10617 cls: 'combobox-clear',
10631 combobox.cls += ' roo-select2-container-multi';
10635 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10636 tooltip : 'This field is required'
10638 if (Roo.bootstrap.version == 4) {
10641 style : 'display:none'
10646 if (align ==='left' && this.fieldLabel.length) {
10648 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10655 cls : 'control-label',
10656 html : this.fieldLabel
10668 var labelCfg = cfg.cn[1];
10669 var contentCfg = cfg.cn[2];
10671 if(this.indicatorpos == 'right'){
10676 cls : 'control-label',
10680 html : this.fieldLabel
10694 labelCfg = cfg.cn[0];
10695 contentCfg = cfg.cn[1];
10698 if(this.labelWidth > 12){
10699 labelCfg.style = "width: " + this.labelWidth + 'px';
10702 if(this.labelWidth < 13 && this.labelmd == 0){
10703 this.labelmd = this.labelWidth;
10706 if(this.labellg > 0){
10707 labelCfg.cls += ' col-lg-' + this.labellg;
10708 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10711 if(this.labelmd > 0){
10712 labelCfg.cls += ' col-md-' + this.labelmd;
10713 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10716 if(this.labelsm > 0){
10717 labelCfg.cls += ' col-sm-' + this.labelsm;
10718 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10721 if(this.labelxs > 0){
10722 labelCfg.cls += ' col-xs-' + this.labelxs;
10723 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10726 } else if ( this.fieldLabel.length) {
10727 // Roo.log(" label");
10732 //cls : 'input-group-addon',
10733 html : this.fieldLabel
10741 if(this.indicatorpos == 'right'){
10749 html : this.fieldLabel
10763 // Roo.log(" no label && no align");
10770 ['xs','sm','md','lg'].map(function(size){
10771 if (settings[size]) {
10772 cfg.cls += ' col-' + size + '-' + settings[size];
10783 onResize : function(w, h){
10784 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10785 // if(typeof w == 'number'){
10786 // var x = w - this.trigger.getWidth();
10787 // this.inputEl().setWidth(this.adjustWidth('input', x));
10788 // this.trigger.setStyle('left', x+'px');
10793 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10796 getResizeEl : function(){
10797 return this.inputEl();
10801 getPositionEl : function(){
10802 return this.inputEl();
10806 alignErrorIcon : function(){
10807 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10811 initEvents : function(){
10815 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10816 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10817 if(!this.multiple && this.showToggleBtn){
10818 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10819 if(this.hideTrigger){
10820 this.trigger.setDisplayed(false);
10822 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10826 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10829 if(this.removable && !this.editable && !this.tickable){
10830 var close = this.closeTriggerEl();
10833 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10834 close.on('click', this.removeBtnClick, this, close);
10838 //this.trigger.addClassOnOver('x-form-trigger-over');
10839 //this.trigger.addClassOnClick('x-form-trigger-click');
10842 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10846 closeTriggerEl : function()
10848 var close = this.el.select('.roo-combo-removable-btn', true).first();
10849 return close ? close : false;
10852 removeBtnClick : function(e, h, el)
10854 e.preventDefault();
10856 if(this.fireEvent("remove", this) !== false){
10858 this.fireEvent("afterremove", this)
10862 createList : function()
10864 this.list = Roo.get(document.body).createChild({
10865 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10866 cls: 'typeahead typeahead-long dropdown-menu',
10867 style: 'display:none'
10870 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10875 initTrigger : function(){
10880 onDestroy : function(){
10882 this.trigger.removeAllListeners();
10883 // this.trigger.remove();
10886 // this.wrap.remove();
10888 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10892 onFocus : function(){
10893 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10895 if(!this.mimicing){
10896 this.wrap.addClass('x-trigger-wrap-focus');
10897 this.mimicing = true;
10898 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10899 if(this.monitorTab){
10900 this.el.on("keydown", this.checkTab, this);
10907 checkTab : function(e){
10908 if(e.getKey() == e.TAB){
10909 this.triggerBlur();
10914 onBlur : function(){
10919 mimicBlur : function(e, t){
10921 if(!this.wrap.contains(t) && this.validateBlur()){
10922 this.triggerBlur();
10928 triggerBlur : function(){
10929 this.mimicing = false;
10930 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10931 if(this.monitorTab){
10932 this.el.un("keydown", this.checkTab, this);
10934 //this.wrap.removeClass('x-trigger-wrap-focus');
10935 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10939 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10940 validateBlur : function(e, t){
10945 onDisable : function(){
10946 this.inputEl().dom.disabled = true;
10947 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10949 // this.wrap.addClass('x-item-disabled');
10954 onEnable : function(){
10955 this.inputEl().dom.disabled = false;
10956 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10958 // this.el.removeClass('x-item-disabled');
10963 onShow : function(){
10964 var ae = this.getActionEl();
10967 ae.dom.style.display = '';
10968 ae.dom.style.visibility = 'visible';
10974 onHide : function(){
10975 var ae = this.getActionEl();
10976 ae.dom.style.display = 'none';
10980 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10981 * by an implementing function.
10983 * @param {EventObject} e
10985 onTriggerClick : Roo.emptyFn
10989 * Ext JS Library 1.1.1
10990 * Copyright(c) 2006-2007, Ext JS, LLC.
10992 * Originally Released Under LGPL - original licence link has changed is not relivant.
10995 * <script type="text/javascript">
11000 * @class Roo.data.SortTypes
11002 * Defines the default sorting (casting?) comparison functions used when sorting data.
11004 Roo.data.SortTypes = {
11006 * Default sort that does nothing
11007 * @param {Mixed} s The value being converted
11008 * @return {Mixed} The comparison value
11010 none : function(s){
11015 * The regular expression used to strip tags
11019 stripTagsRE : /<\/?[^>]+>/gi,
11022 * Strips all HTML tags to sort on text only
11023 * @param {Mixed} s The value being converted
11024 * @return {String} The comparison value
11026 asText : function(s){
11027 return String(s).replace(this.stripTagsRE, "");
11031 * Strips all HTML tags to sort on text only - Case insensitive
11032 * @param {Mixed} s The value being converted
11033 * @return {String} The comparison value
11035 asUCText : function(s){
11036 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11040 * Case insensitive string
11041 * @param {Mixed} s The value being converted
11042 * @return {String} The comparison value
11044 asUCString : function(s) {
11045 return String(s).toUpperCase();
11050 * @param {Mixed} s The value being converted
11051 * @return {Number} The comparison value
11053 asDate : function(s) {
11057 if(s instanceof Date){
11058 return s.getTime();
11060 return Date.parse(String(s));
11065 * @param {Mixed} s The value being converted
11066 * @return {Float} The comparison value
11068 asFloat : function(s) {
11069 var val = parseFloat(String(s).replace(/,/g, ""));
11078 * @param {Mixed} s The value being converted
11079 * @return {Number} The comparison value
11081 asInt : function(s) {
11082 var val = parseInt(String(s).replace(/,/g, ""));
11090 * Ext JS Library 1.1.1
11091 * Copyright(c) 2006-2007, Ext JS, LLC.
11093 * Originally Released Under LGPL - original licence link has changed is not relivant.
11096 * <script type="text/javascript">
11100 * @class Roo.data.Record
11101 * Instances of this class encapsulate both record <em>definition</em> information, and record
11102 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11103 * to access Records cached in an {@link Roo.data.Store} object.<br>
11105 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11106 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11109 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11111 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11112 * {@link #create}. The parameters are the same.
11113 * @param {Array} data An associative Array of data values keyed by the field name.
11114 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11115 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11116 * not specified an integer id is generated.
11118 Roo.data.Record = function(data, id){
11119 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11124 * Generate a constructor for a specific record layout.
11125 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11126 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11127 * Each field definition object may contain the following properties: <ul>
11128 * <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,
11129 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11130 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11131 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11132 * is being used, then this is a string containing the javascript expression to reference the data relative to
11133 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11134 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11135 * this may be omitted.</p></li>
11136 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11137 * <ul><li>auto (Default, implies no conversion)</li>
11142 * <li>date</li></ul></p></li>
11143 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11144 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11145 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11146 * by the Reader into an object that will be stored in the Record. It is passed the
11147 * following parameters:<ul>
11148 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11150 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11152 * <br>usage:<br><pre><code>
11153 var TopicRecord = Roo.data.Record.create(
11154 {name: 'title', mapping: 'topic_title'},
11155 {name: 'author', mapping: 'username'},
11156 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11157 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11158 {name: 'lastPoster', mapping: 'user2'},
11159 {name: 'excerpt', mapping: 'post_text'}
11162 var myNewRecord = new TopicRecord({
11163 title: 'Do my job please',
11166 lastPost: new Date(),
11167 lastPoster: 'Animal',
11168 excerpt: 'No way dude!'
11170 myStore.add(myNewRecord);
11175 Roo.data.Record.create = function(o){
11176 var f = function(){
11177 f.superclass.constructor.apply(this, arguments);
11179 Roo.extend(f, Roo.data.Record);
11180 var p = f.prototype;
11181 p.fields = new Roo.util.MixedCollection(false, function(field){
11184 for(var i = 0, len = o.length; i < len; i++){
11185 p.fields.add(new Roo.data.Field(o[i]));
11187 f.getField = function(name){
11188 return p.fields.get(name);
11193 Roo.data.Record.AUTO_ID = 1000;
11194 Roo.data.Record.EDIT = 'edit';
11195 Roo.data.Record.REJECT = 'reject';
11196 Roo.data.Record.COMMIT = 'commit';
11198 Roo.data.Record.prototype = {
11200 * Readonly flag - true if this record has been modified.
11209 join : function(store){
11210 this.store = store;
11214 * Set the named field to the specified value.
11215 * @param {String} name The name of the field to set.
11216 * @param {Object} value The value to set the field to.
11218 set : function(name, value){
11219 if(this.data[name] == value){
11223 if(!this.modified){
11224 this.modified = {};
11226 if(typeof this.modified[name] == 'undefined'){
11227 this.modified[name] = this.data[name];
11229 this.data[name] = value;
11230 if(!this.editing && this.store){
11231 this.store.afterEdit(this);
11236 * Get the value of the named field.
11237 * @param {String} name The name of the field to get the value of.
11238 * @return {Object} The value of the field.
11240 get : function(name){
11241 return this.data[name];
11245 beginEdit : function(){
11246 this.editing = true;
11247 this.modified = {};
11251 cancelEdit : function(){
11252 this.editing = false;
11253 delete this.modified;
11257 endEdit : function(){
11258 this.editing = false;
11259 if(this.dirty && this.store){
11260 this.store.afterEdit(this);
11265 * Usually called by the {@link Roo.data.Store} which owns the Record.
11266 * Rejects all changes made to the Record since either creation, or the last commit operation.
11267 * Modified fields are reverted to their original values.
11269 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11270 * of reject operations.
11272 reject : function(){
11273 var m = this.modified;
11275 if(typeof m[n] != "function"){
11276 this.data[n] = m[n];
11279 this.dirty = false;
11280 delete this.modified;
11281 this.editing = false;
11283 this.store.afterReject(this);
11288 * Usually called by the {@link Roo.data.Store} which owns the Record.
11289 * Commits all changes made to the Record since either creation, or the last commit operation.
11291 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11292 * of commit operations.
11294 commit : function(){
11295 this.dirty = false;
11296 delete this.modified;
11297 this.editing = false;
11299 this.store.afterCommit(this);
11304 hasError : function(){
11305 return this.error != null;
11309 clearError : function(){
11314 * Creates a copy of this record.
11315 * @param {String} id (optional) A new record id if you don't want to use this record's id
11318 copy : function(newId) {
11319 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11323 * Ext JS Library 1.1.1
11324 * Copyright(c) 2006-2007, Ext JS, LLC.
11326 * Originally Released Under LGPL - original licence link has changed is not relivant.
11329 * <script type="text/javascript">
11335 * @class Roo.data.Store
11336 * @extends Roo.util.Observable
11337 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11338 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11340 * 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
11341 * has no knowledge of the format of the data returned by the Proxy.<br>
11343 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11344 * instances from the data object. These records are cached and made available through accessor functions.
11346 * Creates a new Store.
11347 * @param {Object} config A config object containing the objects needed for the Store to access data,
11348 * and read the data into Records.
11350 Roo.data.Store = function(config){
11351 this.data = new Roo.util.MixedCollection(false);
11352 this.data.getKey = function(o){
11355 this.baseParams = {};
11357 this.paramNames = {
11362 "multisort" : "_multisort"
11365 if(config && config.data){
11366 this.inlineData = config.data;
11367 delete config.data;
11370 Roo.apply(this, config);
11372 if(this.reader){ // reader passed
11373 this.reader = Roo.factory(this.reader, Roo.data);
11374 this.reader.xmodule = this.xmodule || false;
11375 if(!this.recordType){
11376 this.recordType = this.reader.recordType;
11378 if(this.reader.onMetaChange){
11379 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11383 if(this.recordType){
11384 this.fields = this.recordType.prototype.fields;
11386 this.modified = [];
11390 * @event datachanged
11391 * Fires when the data cache has changed, and a widget which is using this Store
11392 * as a Record cache should refresh its view.
11393 * @param {Store} this
11395 datachanged : true,
11397 * @event metachange
11398 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11399 * @param {Store} this
11400 * @param {Object} meta The JSON metadata
11405 * Fires when Records have been added to the Store
11406 * @param {Store} this
11407 * @param {Roo.data.Record[]} records The array of Records added
11408 * @param {Number} index The index at which the record(s) were added
11413 * Fires when a Record has been removed from the Store
11414 * @param {Store} this
11415 * @param {Roo.data.Record} record The Record that was removed
11416 * @param {Number} index The index at which the record was removed
11421 * Fires when a Record has been updated
11422 * @param {Store} this
11423 * @param {Roo.data.Record} record The Record that was updated
11424 * @param {String} operation The update operation being performed. Value may be one of:
11426 Roo.data.Record.EDIT
11427 Roo.data.Record.REJECT
11428 Roo.data.Record.COMMIT
11434 * Fires when the data cache has been cleared.
11435 * @param {Store} this
11439 * @event beforeload
11440 * Fires before a request is made for a new data object. If the beforeload handler returns false
11441 * the load action will be canceled.
11442 * @param {Store} this
11443 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11447 * @event beforeloadadd
11448 * Fires after a new set of Records has been loaded.
11449 * @param {Store} this
11450 * @param {Roo.data.Record[]} records The Records that were loaded
11451 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11453 beforeloadadd : true,
11456 * Fires after a new set of Records has been loaded, before they are added to the store.
11457 * @param {Store} this
11458 * @param {Roo.data.Record[]} records The Records that were loaded
11459 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11460 * @params {Object} return from reader
11464 * @event loadexception
11465 * Fires if an exception occurs in the Proxy during loading.
11466 * Called with the signature of the Proxy's "loadexception" event.
11467 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11470 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11471 * @param {Object} load options
11472 * @param {Object} jsonData from your request (normally this contains the Exception)
11474 loadexception : true
11478 this.proxy = Roo.factory(this.proxy, Roo.data);
11479 this.proxy.xmodule = this.xmodule || false;
11480 this.relayEvents(this.proxy, ["loadexception"]);
11482 this.sortToggle = {};
11483 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11485 Roo.data.Store.superclass.constructor.call(this);
11487 if(this.inlineData){
11488 this.loadData(this.inlineData);
11489 delete this.inlineData;
11493 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11495 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11496 * without a remote query - used by combo/forms at present.
11500 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11503 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11506 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11507 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11510 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11511 * on any HTTP request
11514 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11517 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11521 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11522 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11524 remoteSort : false,
11527 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11528 * loaded or when a record is removed. (defaults to false).
11530 pruneModifiedRecords : false,
11533 lastOptions : null,
11536 * Add Records to the Store and fires the add event.
11537 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11539 add : function(records){
11540 records = [].concat(records);
11541 for(var i = 0, len = records.length; i < len; i++){
11542 records[i].join(this);
11544 var index = this.data.length;
11545 this.data.addAll(records);
11546 this.fireEvent("add", this, records, index);
11550 * Remove a Record from the Store and fires the remove event.
11551 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11553 remove : function(record){
11554 var index = this.data.indexOf(record);
11555 this.data.removeAt(index);
11557 if(this.pruneModifiedRecords){
11558 this.modified.remove(record);
11560 this.fireEvent("remove", this, record, index);
11564 * Remove all Records from the Store and fires the clear event.
11566 removeAll : function(){
11568 if(this.pruneModifiedRecords){
11569 this.modified = [];
11571 this.fireEvent("clear", this);
11575 * Inserts Records to the Store at the given index and fires the add event.
11576 * @param {Number} index The start index at which to insert the passed Records.
11577 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11579 insert : function(index, records){
11580 records = [].concat(records);
11581 for(var i = 0, len = records.length; i < len; i++){
11582 this.data.insert(index, records[i]);
11583 records[i].join(this);
11585 this.fireEvent("add", this, records, index);
11589 * Get the index within the cache of the passed Record.
11590 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11591 * @return {Number} The index of the passed Record. Returns -1 if not found.
11593 indexOf : function(record){
11594 return this.data.indexOf(record);
11598 * Get the index within the cache of the Record with the passed id.
11599 * @param {String} id The id of the Record to find.
11600 * @return {Number} The index of the Record. Returns -1 if not found.
11602 indexOfId : function(id){
11603 return this.data.indexOfKey(id);
11607 * Get the Record with the specified id.
11608 * @param {String} id The id of the Record to find.
11609 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11611 getById : function(id){
11612 return this.data.key(id);
11616 * Get the Record at the specified index.
11617 * @param {Number} index The index of the Record to find.
11618 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11620 getAt : function(index){
11621 return this.data.itemAt(index);
11625 * Returns a range of Records between specified indices.
11626 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11627 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11628 * @return {Roo.data.Record[]} An array of Records
11630 getRange : function(start, end){
11631 return this.data.getRange(start, end);
11635 storeOptions : function(o){
11636 o = Roo.apply({}, o);
11639 this.lastOptions = o;
11643 * Loads the Record cache from the configured Proxy using the configured Reader.
11645 * If using remote paging, then the first load call must specify the <em>start</em>
11646 * and <em>limit</em> properties in the options.params property to establish the initial
11647 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11649 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11650 * and this call will return before the new data has been loaded. Perform any post-processing
11651 * in a callback function, or in a "load" event handler.</strong>
11653 * @param {Object} options An object containing properties which control loading options:<ul>
11654 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11655 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11656 * passed the following arguments:<ul>
11657 * <li>r : Roo.data.Record[]</li>
11658 * <li>options: Options object from the load call</li>
11659 * <li>success: Boolean success indicator</li></ul></li>
11660 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11661 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11664 load : function(options){
11665 options = options || {};
11666 if(this.fireEvent("beforeload", this, options) !== false){
11667 this.storeOptions(options);
11668 var p = Roo.apply(options.params || {}, this.baseParams);
11669 // if meta was not loaded from remote source.. try requesting it.
11670 if (!this.reader.metaFromRemote) {
11671 p._requestMeta = 1;
11673 if(this.sortInfo && this.remoteSort){
11674 var pn = this.paramNames;
11675 p[pn["sort"]] = this.sortInfo.field;
11676 p[pn["dir"]] = this.sortInfo.direction;
11678 if (this.multiSort) {
11679 var pn = this.paramNames;
11680 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11683 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11688 * Reloads the Record cache from the configured Proxy using the configured Reader and
11689 * the options from the last load operation performed.
11690 * @param {Object} options (optional) An object containing properties which may override the options
11691 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11692 * the most recently used options are reused).
11694 reload : function(options){
11695 this.load(Roo.applyIf(options||{}, this.lastOptions));
11699 // Called as a callback by the Reader during a load operation.
11700 loadRecords : function(o, options, success){
11701 if(!o || success === false){
11702 if(success !== false){
11703 this.fireEvent("load", this, [], options, o);
11705 if(options.callback){
11706 options.callback.call(options.scope || this, [], options, false);
11710 // if data returned failure - throw an exception.
11711 if (o.success === false) {
11712 // show a message if no listener is registered.
11713 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11714 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11716 // loadmask wil be hooked into this..
11717 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11720 var r = o.records, t = o.totalRecords || r.length;
11722 this.fireEvent("beforeloadadd", this, r, options, o);
11724 if(!options || options.add !== true){
11725 if(this.pruneModifiedRecords){
11726 this.modified = [];
11728 for(var i = 0, len = r.length; i < len; i++){
11732 this.data = this.snapshot;
11733 delete this.snapshot;
11736 this.data.addAll(r);
11737 this.totalLength = t;
11739 this.fireEvent("datachanged", this);
11741 this.totalLength = Math.max(t, this.data.length+r.length);
11745 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11747 var e = new Roo.data.Record({});
11749 e.set(this.parent.displayField, this.parent.emptyTitle);
11750 e.set(this.parent.valueField, '');
11755 this.fireEvent("load", this, r, options, o);
11756 if(options.callback){
11757 options.callback.call(options.scope || this, r, options, true);
11763 * Loads data from a passed data block. A Reader which understands the format of the data
11764 * must have been configured in the constructor.
11765 * @param {Object} data The data block from which to read the Records. The format of the data expected
11766 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11767 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11769 loadData : function(o, append){
11770 var r = this.reader.readRecords(o);
11771 this.loadRecords(r, {add: append}, true);
11775 * Gets the number of cached records.
11777 * <em>If using paging, this may not be the total size of the dataset. If the data object
11778 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11779 * the data set size</em>
11781 getCount : function(){
11782 return this.data.length || 0;
11786 * Gets the total number of records in the dataset as returned by the server.
11788 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11789 * the dataset size</em>
11791 getTotalCount : function(){
11792 return this.totalLength || 0;
11796 * Returns the sort state of the Store as an object with two properties:
11798 field {String} The name of the field by which the Records are sorted
11799 direction {String} The sort order, "ASC" or "DESC"
11802 getSortState : function(){
11803 return this.sortInfo;
11807 applySort : function(){
11808 if(this.sortInfo && !this.remoteSort){
11809 var s = this.sortInfo, f = s.field;
11810 var st = this.fields.get(f).sortType;
11811 var fn = function(r1, r2){
11812 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11813 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11815 this.data.sort(s.direction, fn);
11816 if(this.snapshot && this.snapshot != this.data){
11817 this.snapshot.sort(s.direction, fn);
11823 * Sets the default sort column and order to be used by the next load operation.
11824 * @param {String} fieldName The name of the field to sort by.
11825 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11827 setDefaultSort : function(field, dir){
11828 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11832 * Sort the Records.
11833 * If remote sorting is used, the sort is performed on the server, and the cache is
11834 * reloaded. If local sorting is used, the cache is sorted internally.
11835 * @param {String} fieldName The name of the field to sort by.
11836 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11838 sort : function(fieldName, dir){
11839 var f = this.fields.get(fieldName);
11841 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11843 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11844 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11849 this.sortToggle[f.name] = dir;
11850 this.sortInfo = {field: f.name, direction: dir};
11851 if(!this.remoteSort){
11853 this.fireEvent("datachanged", this);
11855 this.load(this.lastOptions);
11860 * Calls the specified function for each of the Records in the cache.
11861 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11862 * Returning <em>false</em> aborts and exits the iteration.
11863 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11865 each : function(fn, scope){
11866 this.data.each(fn, scope);
11870 * Gets all records modified since the last commit. Modified records are persisted across load operations
11871 * (e.g., during paging).
11872 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11874 getModifiedRecords : function(){
11875 return this.modified;
11879 createFilterFn : function(property, value, anyMatch){
11880 if(!value.exec){ // not a regex
11881 value = String(value);
11882 if(value.length == 0){
11885 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11887 return function(r){
11888 return value.test(r.data[property]);
11893 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11894 * @param {String} property A field on your records
11895 * @param {Number} start The record index to start at (defaults to 0)
11896 * @param {Number} end The last record index to include (defaults to length - 1)
11897 * @return {Number} The sum
11899 sum : function(property, start, end){
11900 var rs = this.data.items, v = 0;
11901 start = start || 0;
11902 end = (end || end === 0) ? end : rs.length-1;
11904 for(var i = start; i <= end; i++){
11905 v += (rs[i].data[property] || 0);
11911 * Filter the records by a specified property.
11912 * @param {String} field A field on your records
11913 * @param {String/RegExp} value Either a string that the field
11914 * should start with or a RegExp to test against the field
11915 * @param {Boolean} anyMatch True to match any part not just the beginning
11917 filter : function(property, value, anyMatch){
11918 var fn = this.createFilterFn(property, value, anyMatch);
11919 return fn ? this.filterBy(fn) : this.clearFilter();
11923 * Filter by a function. The specified function will be called with each
11924 * record in this data source. If the function returns true the record is included,
11925 * otherwise it is filtered.
11926 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11927 * @param {Object} scope (optional) The scope of the function (defaults to this)
11929 filterBy : function(fn, scope){
11930 this.snapshot = this.snapshot || this.data;
11931 this.data = this.queryBy(fn, scope||this);
11932 this.fireEvent("datachanged", this);
11936 * Query the records by a specified property.
11937 * @param {String} field A field on your records
11938 * @param {String/RegExp} value Either a string that the field
11939 * should start with or a RegExp to test against the field
11940 * @param {Boolean} anyMatch True to match any part not just the beginning
11941 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11943 query : function(property, value, anyMatch){
11944 var fn = this.createFilterFn(property, value, anyMatch);
11945 return fn ? this.queryBy(fn) : this.data.clone();
11949 * Query by a function. The specified function will be called with each
11950 * record in this data source. If the function returns true the record is included
11952 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11953 * @param {Object} scope (optional) The scope of the function (defaults to this)
11954 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11956 queryBy : function(fn, scope){
11957 var data = this.snapshot || this.data;
11958 return data.filterBy(fn, scope||this);
11962 * Collects unique values for a particular dataIndex from this store.
11963 * @param {String} dataIndex The property to collect
11964 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11965 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11966 * @return {Array} An array of the unique values
11968 collect : function(dataIndex, allowNull, bypassFilter){
11969 var d = (bypassFilter === true && this.snapshot) ?
11970 this.snapshot.items : this.data.items;
11971 var v, sv, r = [], l = {};
11972 for(var i = 0, len = d.length; i < len; i++){
11973 v = d[i].data[dataIndex];
11975 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11984 * Revert to a view of the Record cache with no filtering applied.
11985 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11987 clearFilter : function(suppressEvent){
11988 if(this.snapshot && this.snapshot != this.data){
11989 this.data = this.snapshot;
11990 delete this.snapshot;
11991 if(suppressEvent !== true){
11992 this.fireEvent("datachanged", this);
11998 afterEdit : function(record){
11999 if(this.modified.indexOf(record) == -1){
12000 this.modified.push(record);
12002 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12006 afterReject : function(record){
12007 this.modified.remove(record);
12008 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12012 afterCommit : function(record){
12013 this.modified.remove(record);
12014 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12018 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12019 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12021 commitChanges : function(){
12022 var m = this.modified.slice(0);
12023 this.modified = [];
12024 for(var i = 0, len = m.length; i < len; i++){
12030 * Cancel outstanding changes on all changed records.
12032 rejectChanges : function(){
12033 var m = this.modified.slice(0);
12034 this.modified = [];
12035 for(var i = 0, len = m.length; i < len; i++){
12040 onMetaChange : function(meta, rtype, o){
12041 this.recordType = rtype;
12042 this.fields = rtype.prototype.fields;
12043 delete this.snapshot;
12044 this.sortInfo = meta.sortInfo || this.sortInfo;
12045 this.modified = [];
12046 this.fireEvent('metachange', this, this.reader.meta);
12049 moveIndex : function(data, type)
12051 var index = this.indexOf(data);
12053 var newIndex = index + type;
12057 this.insert(newIndex, data);
12062 * Ext JS Library 1.1.1
12063 * Copyright(c) 2006-2007, Ext JS, LLC.
12065 * Originally Released Under LGPL - original licence link has changed is not relivant.
12068 * <script type="text/javascript">
12072 * @class Roo.data.SimpleStore
12073 * @extends Roo.data.Store
12074 * Small helper class to make creating Stores from Array data easier.
12075 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12076 * @cfg {Array} fields An array of field definition objects, or field name strings.
12077 * @cfg {Array} data The multi-dimensional array of data
12079 * @param {Object} config
12081 Roo.data.SimpleStore = function(config){
12082 Roo.data.SimpleStore.superclass.constructor.call(this, {
12084 reader: new Roo.data.ArrayReader({
12087 Roo.data.Record.create(config.fields)
12089 proxy : new Roo.data.MemoryProxy(config.data)
12093 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12095 * Ext JS Library 1.1.1
12096 * Copyright(c) 2006-2007, Ext JS, LLC.
12098 * Originally Released Under LGPL - original licence link has changed is not relivant.
12101 * <script type="text/javascript">
12106 * @extends Roo.data.Store
12107 * @class Roo.data.JsonStore
12108 * Small helper class to make creating Stores for JSON data easier. <br/>
12110 var store = new Roo.data.JsonStore({
12111 url: 'get-images.php',
12113 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12116 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12117 * JsonReader and HttpProxy (unless inline data is provided).</b>
12118 * @cfg {Array} fields An array of field definition objects, or field name strings.
12120 * @param {Object} config
12122 Roo.data.JsonStore = function(c){
12123 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12124 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12125 reader: new Roo.data.JsonReader(c, c.fields)
12128 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12130 * Ext JS Library 1.1.1
12131 * Copyright(c) 2006-2007, Ext JS, LLC.
12133 * Originally Released Under LGPL - original licence link has changed is not relivant.
12136 * <script type="text/javascript">
12140 Roo.data.Field = function(config){
12141 if(typeof config == "string"){
12142 config = {name: config};
12144 Roo.apply(this, config);
12147 this.type = "auto";
12150 var st = Roo.data.SortTypes;
12151 // named sortTypes are supported, here we look them up
12152 if(typeof this.sortType == "string"){
12153 this.sortType = st[this.sortType];
12156 // set default sortType for strings and dates
12157 if(!this.sortType){
12160 this.sortType = st.asUCString;
12163 this.sortType = st.asDate;
12166 this.sortType = st.none;
12171 var stripRe = /[\$,%]/g;
12173 // prebuilt conversion function for this field, instead of
12174 // switching every time we're reading a value
12176 var cv, dateFormat = this.dateFormat;
12181 cv = function(v){ return v; };
12184 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12188 return v !== undefined && v !== null && v !== '' ?
12189 parseInt(String(v).replace(stripRe, ""), 10) : '';
12194 return v !== undefined && v !== null && v !== '' ?
12195 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12200 cv = function(v){ return v === true || v === "true" || v == 1; };
12207 if(v instanceof Date){
12211 if(dateFormat == "timestamp"){
12212 return new Date(v*1000);
12214 return Date.parseDate(v, dateFormat);
12216 var parsed = Date.parse(v);
12217 return parsed ? new Date(parsed) : null;
12226 Roo.data.Field.prototype = {
12234 * Ext JS Library 1.1.1
12235 * Copyright(c) 2006-2007, Ext JS, LLC.
12237 * Originally Released Under LGPL - original licence link has changed is not relivant.
12240 * <script type="text/javascript">
12243 // Base class for reading structured data from a data source. This class is intended to be
12244 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12247 * @class Roo.data.DataReader
12248 * Base class for reading structured data from a data source. This class is intended to be
12249 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12252 Roo.data.DataReader = function(meta, recordType){
12256 this.recordType = recordType instanceof Array ?
12257 Roo.data.Record.create(recordType) : recordType;
12260 Roo.data.DataReader.prototype = {
12262 * Create an empty record
12263 * @param {Object} data (optional) - overlay some values
12264 * @return {Roo.data.Record} record created.
12266 newRow : function(d) {
12268 this.recordType.prototype.fields.each(function(c) {
12270 case 'int' : da[c.name] = 0; break;
12271 case 'date' : da[c.name] = new Date(); break;
12272 case 'float' : da[c.name] = 0.0; break;
12273 case 'boolean' : da[c.name] = false; break;
12274 default : da[c.name] = ""; break;
12278 return new this.recordType(Roo.apply(da, d));
12283 * Ext JS Library 1.1.1
12284 * Copyright(c) 2006-2007, Ext JS, LLC.
12286 * Originally Released Under LGPL - original licence link has changed is not relivant.
12289 * <script type="text/javascript">
12293 * @class Roo.data.DataProxy
12294 * @extends Roo.data.Observable
12295 * This class is an abstract base class for implementations which provide retrieval of
12296 * unformatted data objects.<br>
12298 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12299 * (of the appropriate type which knows how to parse the data object) to provide a block of
12300 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12302 * Custom implementations must implement the load method as described in
12303 * {@link Roo.data.HttpProxy#load}.
12305 Roo.data.DataProxy = function(){
12308 * @event beforeload
12309 * Fires before a network request is made to retrieve a data object.
12310 * @param {Object} This DataProxy object.
12311 * @param {Object} params The params parameter to the load function.
12316 * Fires before the load method's callback is called.
12317 * @param {Object} This DataProxy object.
12318 * @param {Object} o The data object.
12319 * @param {Object} arg The callback argument object passed to the load function.
12323 * @event loadexception
12324 * Fires if an Exception occurs during data retrieval.
12325 * @param {Object} This DataProxy object.
12326 * @param {Object} o The data object.
12327 * @param {Object} arg The callback argument object passed to the load function.
12328 * @param {Object} e The Exception.
12330 loadexception : true
12332 Roo.data.DataProxy.superclass.constructor.call(this);
12335 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12338 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
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.MemoryProxy
12352 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12353 * to the Reader when its load method is called.
12355 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12357 Roo.data.MemoryProxy = function(data){
12361 Roo.data.MemoryProxy.superclass.constructor.call(this);
12365 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12368 * Load data from the requested source (in this case an in-memory
12369 * data object passed to the constructor), read the data object into
12370 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12371 * process that block using the passed callback.
12372 * @param {Object} params This parameter is not used by the MemoryProxy class.
12373 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12374 * object into a block of Roo.data.Records.
12375 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12376 * The function must be passed <ul>
12377 * <li>The Record block object</li>
12378 * <li>The "arg" argument from the load function</li>
12379 * <li>A boolean success indicator</li>
12381 * @param {Object} scope The scope in which to call the callback
12382 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12384 load : function(params, reader, callback, scope, arg){
12385 params = params || {};
12388 result = reader.readRecords(this.data);
12390 this.fireEvent("loadexception", this, arg, null, e);
12391 callback.call(scope, null, arg, false);
12394 callback.call(scope, result, arg, true);
12398 update : function(params, records){
12403 * Ext JS Library 1.1.1
12404 * Copyright(c) 2006-2007, Ext JS, LLC.
12406 * Originally Released Under LGPL - original licence link has changed is not relivant.
12409 * <script type="text/javascript">
12412 * @class Roo.data.HttpProxy
12413 * @extends Roo.data.DataProxy
12414 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12415 * configured to reference a certain URL.<br><br>
12417 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12418 * from which the running page was served.<br><br>
12420 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12422 * Be aware that to enable the browser to parse an XML document, the server must set
12423 * the Content-Type header in the HTTP response to "text/xml".
12425 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12426 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12427 * will be used to make the request.
12429 Roo.data.HttpProxy = function(conn){
12430 Roo.data.HttpProxy.superclass.constructor.call(this);
12431 // is conn a conn config or a real conn?
12433 this.useAjax = !conn || !conn.events;
12437 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12438 // thse are take from connection...
12441 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12444 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12445 * extra parameters to each request made by this object. (defaults to undefined)
12448 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12449 * to each request made by this object. (defaults to undefined)
12452 * @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)
12455 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12458 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12464 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12468 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12469 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12470 * a finer-grained basis than the DataProxy events.
12472 getConnection : function(){
12473 return this.useAjax ? Roo.Ajax : this.conn;
12477 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12478 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12479 * process that block using the passed callback.
12480 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12481 * for the request to the remote server.
12482 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12483 * object into a block of Roo.data.Records.
12484 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12485 * The function must be passed <ul>
12486 * <li>The Record block object</li>
12487 * <li>The "arg" argument from the load function</li>
12488 * <li>A boolean success indicator</li>
12490 * @param {Object} scope The scope in which to call the callback
12491 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12493 load : function(params, reader, callback, scope, arg){
12494 if(this.fireEvent("beforeload", this, params) !== false){
12496 params : params || {},
12498 callback : callback,
12503 callback : this.loadResponse,
12507 Roo.applyIf(o, this.conn);
12508 if(this.activeRequest){
12509 Roo.Ajax.abort(this.activeRequest);
12511 this.activeRequest = Roo.Ajax.request(o);
12513 this.conn.request(o);
12516 callback.call(scope||this, null, arg, false);
12521 loadResponse : function(o, success, response){
12522 delete this.activeRequest;
12524 this.fireEvent("loadexception", this, o, response);
12525 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12530 result = o.reader.read(response);
12532 this.fireEvent("loadexception", this, o, response, e);
12533 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12537 this.fireEvent("load", this, o, o.request.arg);
12538 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12542 update : function(dataSet){
12547 updateResponse : function(dataSet){
12552 * Ext JS Library 1.1.1
12553 * Copyright(c) 2006-2007, Ext JS, LLC.
12555 * Originally Released Under LGPL - original licence link has changed is not relivant.
12558 * <script type="text/javascript">
12562 * @class Roo.data.ScriptTagProxy
12563 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12564 * other than the originating domain of the running page.<br><br>
12566 * <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
12567 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12569 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12570 * source code that is used as the source inside a <script> tag.<br><br>
12572 * In order for the browser to process the returned data, the server must wrap the data object
12573 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12574 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12575 * depending on whether the callback name was passed:
12578 boolean scriptTag = false;
12579 String cb = request.getParameter("callback");
12582 response.setContentType("text/javascript");
12584 response.setContentType("application/x-json");
12586 Writer out = response.getWriter();
12588 out.write(cb + "(");
12590 out.print(dataBlock.toJsonString());
12597 * @param {Object} config A configuration object.
12599 Roo.data.ScriptTagProxy = function(config){
12600 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12601 Roo.apply(this, config);
12602 this.head = document.getElementsByTagName("head")[0];
12605 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12607 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12609 * @cfg {String} url The URL from which to request the data object.
12612 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12616 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12617 * the server the name of the callback function set up by the load call to process the returned data object.
12618 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12619 * javascript output which calls this named function passing the data object as its only parameter.
12621 callbackParam : "callback",
12623 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12624 * name to the request.
12629 * Load data from the configured URL, read the data object into
12630 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12631 * process that block using the passed callback.
12632 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12633 * for the request to the remote server.
12634 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12635 * object into a block of Roo.data.Records.
12636 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12637 * The function must be passed <ul>
12638 * <li>The Record block object</li>
12639 * <li>The "arg" argument from the load function</li>
12640 * <li>A boolean success indicator</li>
12642 * @param {Object} scope The scope in which to call the callback
12643 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12645 load : function(params, reader, callback, scope, arg){
12646 if(this.fireEvent("beforeload", this, params) !== false){
12648 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12650 var url = this.url;
12651 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12653 url += "&_dc=" + (new Date().getTime());
12655 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12658 cb : "stcCallback"+transId,
12659 scriptId : "stcScript"+transId,
12663 callback : callback,
12669 window[trans.cb] = function(o){
12670 conn.handleResponse(o, trans);
12673 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12675 if(this.autoAbort !== false){
12679 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12681 var script = document.createElement("script");
12682 script.setAttribute("src", url);
12683 script.setAttribute("type", "text/javascript");
12684 script.setAttribute("id", trans.scriptId);
12685 this.head.appendChild(script);
12687 this.trans = trans;
12689 callback.call(scope||this, null, arg, false);
12694 isLoading : function(){
12695 return this.trans ? true : false;
12699 * Abort the current server request.
12701 abort : function(){
12702 if(this.isLoading()){
12703 this.destroyTrans(this.trans);
12708 destroyTrans : function(trans, isLoaded){
12709 this.head.removeChild(document.getElementById(trans.scriptId));
12710 clearTimeout(trans.timeoutId);
12712 window[trans.cb] = undefined;
12714 delete window[trans.cb];
12717 // if hasn't been loaded, wait for load to remove it to prevent script error
12718 window[trans.cb] = function(){
12719 window[trans.cb] = undefined;
12721 delete window[trans.cb];
12728 handleResponse : function(o, trans){
12729 this.trans = false;
12730 this.destroyTrans(trans, true);
12733 result = trans.reader.readRecords(o);
12735 this.fireEvent("loadexception", this, o, trans.arg, e);
12736 trans.callback.call(trans.scope||window, null, trans.arg, false);
12739 this.fireEvent("load", this, o, trans.arg);
12740 trans.callback.call(trans.scope||window, result, trans.arg, true);
12744 handleFailure : function(trans){
12745 this.trans = false;
12746 this.destroyTrans(trans, false);
12747 this.fireEvent("loadexception", this, null, trans.arg);
12748 trans.callback.call(trans.scope||window, null, trans.arg, false);
12752 * Ext JS Library 1.1.1
12753 * Copyright(c) 2006-2007, Ext JS, LLC.
12755 * Originally Released Under LGPL - original licence link has changed is not relivant.
12758 * <script type="text/javascript">
12762 * @class Roo.data.JsonReader
12763 * @extends Roo.data.DataReader
12764 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12765 * based on mappings in a provided Roo.data.Record constructor.
12767 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12768 * in the reply previously.
12773 var RecordDef = Roo.data.Record.create([
12774 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12775 {name: 'occupation'} // This field will use "occupation" as the mapping.
12777 var myReader = new Roo.data.JsonReader({
12778 totalProperty: "results", // The property which contains the total dataset size (optional)
12779 root: "rows", // The property which contains an Array of row objects
12780 id: "id" // The property within each row object that provides an ID for the record (optional)
12784 * This would consume a JSON file like this:
12786 { 'results': 2, 'rows': [
12787 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12788 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12791 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12792 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12793 * paged from the remote server.
12794 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12795 * @cfg {String} root name of the property which contains the Array of row objects.
12796 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12797 * @cfg {Array} fields Array of field definition objects
12799 * Create a new JsonReader
12800 * @param {Object} meta Metadata configuration options
12801 * @param {Object} recordType Either an Array of field definition objects,
12802 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12804 Roo.data.JsonReader = function(meta, recordType){
12807 // set some defaults:
12808 Roo.applyIf(meta, {
12809 totalProperty: 'total',
12810 successProperty : 'success',
12815 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12817 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12820 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12821 * Used by Store query builder to append _requestMeta to params.
12824 metaFromRemote : false,
12826 * This method is only used by a DataProxy which has retrieved data from a remote server.
12827 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12828 * @return {Object} data A data block which is used by an Roo.data.Store object as
12829 * a cache of Roo.data.Records.
12831 read : function(response){
12832 var json = response.responseText;
12834 var o = /* eval:var:o */ eval("("+json+")");
12836 throw {message: "JsonReader.read: Json object not found"};
12842 this.metaFromRemote = true;
12843 this.meta = o.metaData;
12844 this.recordType = Roo.data.Record.create(o.metaData.fields);
12845 this.onMetaChange(this.meta, this.recordType, o);
12847 return this.readRecords(o);
12850 // private function a store will implement
12851 onMetaChange : function(meta, recordType, o){
12858 simpleAccess: function(obj, subsc) {
12865 getJsonAccessor: function(){
12867 return function(expr) {
12869 return(re.test(expr))
12870 ? new Function("obj", "return obj." + expr)
12875 return Roo.emptyFn;
12880 * Create a data block containing Roo.data.Records from an XML document.
12881 * @param {Object} o An object which contains an Array of row objects in the property specified
12882 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12883 * which contains the total size of the dataset.
12884 * @return {Object} data A data block which is used by an Roo.data.Store object as
12885 * a cache of Roo.data.Records.
12887 readRecords : function(o){
12889 * After any data loads, the raw JSON data is available for further custom processing.
12893 var s = this.meta, Record = this.recordType,
12894 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12896 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12898 if(s.totalProperty) {
12899 this.getTotal = this.getJsonAccessor(s.totalProperty);
12901 if(s.successProperty) {
12902 this.getSuccess = this.getJsonAccessor(s.successProperty);
12904 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12906 var g = this.getJsonAccessor(s.id);
12907 this.getId = function(rec) {
12909 return (r === undefined || r === "") ? null : r;
12912 this.getId = function(){return null;};
12915 for(var jj = 0; jj < fl; jj++){
12917 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12918 this.ef[jj] = this.getJsonAccessor(map);
12922 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12923 if(s.totalProperty){
12924 var vt = parseInt(this.getTotal(o), 10);
12929 if(s.successProperty){
12930 var vs = this.getSuccess(o);
12931 if(vs === false || vs === 'false'){
12936 for(var i = 0; i < c; i++){
12939 var id = this.getId(n);
12940 for(var j = 0; j < fl; j++){
12942 var v = this.ef[j](n);
12944 Roo.log('missing convert for ' + f.name);
12948 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12950 var record = new Record(values, id);
12952 records[i] = record;
12958 totalRecords : totalRecords
12963 * Ext JS Library 1.1.1
12964 * Copyright(c) 2006-2007, Ext JS, LLC.
12966 * Originally Released Under LGPL - original licence link has changed is not relivant.
12969 * <script type="text/javascript">
12973 * @class Roo.data.ArrayReader
12974 * @extends Roo.data.DataReader
12975 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12976 * Each element of that Array represents a row of data fields. The
12977 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12978 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12982 var RecordDef = Roo.data.Record.create([
12983 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12984 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12986 var myReader = new Roo.data.ArrayReader({
12987 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12991 * This would consume an Array like this:
12993 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12995 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12997 * Create a new JsonReader
12998 * @param {Object} meta Metadata configuration options.
12999 * @param {Object} recordType Either an Array of field definition objects
13000 * as specified to {@link Roo.data.Record#create},
13001 * or an {@link Roo.data.Record} object
13002 * created using {@link Roo.data.Record#create}.
13004 Roo.data.ArrayReader = function(meta, recordType){
13005 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
13008 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13010 * Create a data block containing Roo.data.Records from an XML document.
13011 * @param {Object} o An Array of row objects which represents the dataset.
13012 * @return {Object} data A data block which is used by an Roo.data.Store object as
13013 * a cache of Roo.data.Records.
13015 readRecords : function(o){
13016 var sid = this.meta ? this.meta.id : null;
13017 var recordType = this.recordType, fields = recordType.prototype.fields;
13020 for(var i = 0; i < root.length; i++){
13023 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13024 for(var j = 0, jlen = fields.length; j < jlen; j++){
13025 var f = fields.items[j];
13026 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13027 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13029 values[f.name] = v;
13031 var record = new recordType(values, id);
13033 records[records.length] = record;
13037 totalRecords : records.length
13046 * @class Roo.bootstrap.ComboBox
13047 * @extends Roo.bootstrap.TriggerField
13048 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13049 * @cfg {Boolean} append (true|false) default false
13050 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13051 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13052 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13053 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13054 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13055 * @cfg {Boolean} animate default true
13056 * @cfg {Boolean} emptyResultText only for touch device
13057 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13058 * @cfg {String} emptyTitle default ''
13060 * Create a new ComboBox.
13061 * @param {Object} config Configuration options
13063 Roo.bootstrap.ComboBox = function(config){
13064 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13068 * Fires when the dropdown list is expanded
13069 * @param {Roo.bootstrap.ComboBox} combo This combo box
13074 * Fires when the dropdown list is collapsed
13075 * @param {Roo.bootstrap.ComboBox} combo This combo box
13079 * @event beforeselect
13080 * Fires before a list item is selected. Return false to cancel the selection.
13081 * @param {Roo.bootstrap.ComboBox} combo This combo box
13082 * @param {Roo.data.Record} record The data record returned from the underlying store
13083 * @param {Number} index The index of the selected item in the dropdown list
13085 'beforeselect' : true,
13088 * Fires when a list item is selected
13089 * @param {Roo.bootstrap.ComboBox} combo This combo box
13090 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13091 * @param {Number} index The index of the selected item in the dropdown list
13095 * @event beforequery
13096 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13097 * The event object passed has these properties:
13098 * @param {Roo.bootstrap.ComboBox} combo This combo box
13099 * @param {String} query The query
13100 * @param {Boolean} forceAll true to force "all" query
13101 * @param {Boolean} cancel true to cancel the query
13102 * @param {Object} e The query event object
13104 'beforequery': true,
13107 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13108 * @param {Roo.bootstrap.ComboBox} combo This combo box
13113 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13114 * @param {Roo.bootstrap.ComboBox} combo This combo box
13115 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13120 * Fires when the remove value from the combobox array
13121 * @param {Roo.bootstrap.ComboBox} combo This combo box
13125 * @event afterremove
13126 * Fires when the remove value from the combobox array
13127 * @param {Roo.bootstrap.ComboBox} combo This combo box
13129 'afterremove' : true,
13131 * @event specialfilter
13132 * Fires when specialfilter
13133 * @param {Roo.bootstrap.ComboBox} combo This combo box
13135 'specialfilter' : true,
13138 * Fires when tick the element
13139 * @param {Roo.bootstrap.ComboBox} combo This combo box
13143 * @event touchviewdisplay
13144 * Fires when touch view require special display (default is using displayField)
13145 * @param {Roo.bootstrap.ComboBox} combo This combo box
13146 * @param {Object} cfg set html .
13148 'touchviewdisplay' : true
13153 this.tickItems = [];
13155 this.selectedIndex = -1;
13156 if(this.mode == 'local'){
13157 if(config.queryDelay === undefined){
13158 this.queryDelay = 10;
13160 if(config.minChars === undefined){
13166 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13169 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13170 * rendering into an Roo.Editor, defaults to false)
13173 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13174 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13177 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13180 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13181 * the dropdown list (defaults to undefined, with no header element)
13185 * @cfg {String/Roo.Template} tpl The template to use to render the output
13189 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13191 listWidth: undefined,
13193 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13194 * mode = 'remote' or 'text' if mode = 'local')
13196 displayField: undefined,
13199 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13200 * mode = 'remote' or 'value' if mode = 'local').
13201 * Note: use of a valueField requires the user make a selection
13202 * in order for a value to be mapped.
13204 valueField: undefined,
13206 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13211 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13212 * field's data value (defaults to the underlying DOM element's name)
13214 hiddenName: undefined,
13216 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13220 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13222 selectedClass: 'active',
13225 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13229 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13230 * anchor positions (defaults to 'tl-bl')
13232 listAlign: 'tl-bl?',
13234 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13238 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13239 * query specified by the allQuery config option (defaults to 'query')
13241 triggerAction: 'query',
13243 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13244 * (defaults to 4, does not apply if editable = false)
13248 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13249 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13253 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13254 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13258 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13259 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13263 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13264 * when editable = true (defaults to false)
13266 selectOnFocus:false,
13268 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13270 queryParam: 'query',
13272 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13273 * when mode = 'remote' (defaults to 'Loading...')
13275 loadingText: 'Loading...',
13277 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13281 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13285 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13286 * traditional select (defaults to true)
13290 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13294 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13298 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13299 * listWidth has a higher value)
13303 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13304 * allow the user to set arbitrary text into the field (defaults to false)
13306 forceSelection:false,
13308 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13309 * if typeAhead = true (defaults to 250)
13311 typeAheadDelay : 250,
13313 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13314 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13316 valueNotFoundText : undefined,
13318 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13320 blockFocus : false,
13323 * @cfg {Boolean} disableClear Disable showing of clear button.
13325 disableClear : false,
13327 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13329 alwaysQuery : false,
13332 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13337 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13339 invalidClass : "has-warning",
13342 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13344 validClass : "has-success",
13347 * @cfg {Boolean} specialFilter (true|false) special filter default false
13349 specialFilter : false,
13352 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13354 mobileTouchView : true,
13357 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13359 useNativeIOS : false,
13362 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13364 mobile_restrict_height : false,
13366 ios_options : false,
13378 btnPosition : 'right',
13379 triggerList : true,
13380 showToggleBtn : true,
13382 emptyResultText: 'Empty',
13383 triggerText : 'Select',
13386 // element that contains real text value.. (when hidden is used..)
13388 getAutoCreate : function()
13393 * Render classic select for iso
13396 if(Roo.isIOS && this.useNativeIOS){
13397 cfg = this.getAutoCreateNativeIOS();
13405 if(Roo.isTouch && this.mobileTouchView){
13406 cfg = this.getAutoCreateTouchView();
13413 if(!this.tickable){
13414 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13419 * ComboBox with tickable selections
13422 var align = this.labelAlign || this.parentLabelAlign();
13425 cls : 'form-group roo-combobox-tickable' //input-group
13428 var btn_text_select = '';
13429 var btn_text_done = '';
13430 var btn_text_cancel = '';
13432 if (this.btn_text_show) {
13433 btn_text_select = 'Select';
13434 btn_text_done = 'Done';
13435 btn_text_cancel = 'Cancel';
13440 cls : 'tickable-buttons',
13445 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13446 //html : this.triggerText
13447 html: btn_text_select
13453 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13455 html: btn_text_done
13461 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13463 html: btn_text_cancel
13469 buttons.cn.unshift({
13471 cls: 'roo-select2-search-field-input'
13477 Roo.each(buttons.cn, function(c){
13479 c.cls += ' btn-' + _this.size;
13482 if (_this.disabled) {
13489 style : 'display: contents',
13494 cls: 'form-hidden-field'
13498 cls: 'roo-select2-choices',
13502 cls: 'roo-select2-search-field',
13513 cls: 'roo-select2-container input-group roo-select2-container-multi',
13519 // cls: 'typeahead typeahead-long dropdown-menu',
13520 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13525 if(this.hasFeedback && !this.allowBlank){
13529 cls: 'glyphicon form-control-feedback'
13532 combobox.cn.push(feedback);
13537 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13538 tooltip : 'This field is required'
13540 if (Roo.bootstrap.version == 4) {
13543 style : 'display:none'
13546 if (align ==='left' && this.fieldLabel.length) {
13548 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13555 cls : 'control-label col-form-label',
13556 html : this.fieldLabel
13568 var labelCfg = cfg.cn[1];
13569 var contentCfg = cfg.cn[2];
13572 if(this.indicatorpos == 'right'){
13578 cls : 'control-label col-form-label',
13582 html : this.fieldLabel
13598 labelCfg = cfg.cn[0];
13599 contentCfg = cfg.cn[1];
13603 if(this.labelWidth > 12){
13604 labelCfg.style = "width: " + this.labelWidth + 'px';
13607 if(this.labelWidth < 13 && this.labelmd == 0){
13608 this.labelmd = this.labelWidth;
13611 if(this.labellg > 0){
13612 labelCfg.cls += ' col-lg-' + this.labellg;
13613 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13616 if(this.labelmd > 0){
13617 labelCfg.cls += ' col-md-' + this.labelmd;
13618 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13621 if(this.labelsm > 0){
13622 labelCfg.cls += ' col-sm-' + this.labelsm;
13623 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13626 if(this.labelxs > 0){
13627 labelCfg.cls += ' col-xs-' + this.labelxs;
13628 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13632 } else if ( this.fieldLabel.length) {
13633 // Roo.log(" label");
13638 //cls : 'input-group-addon',
13639 html : this.fieldLabel
13644 if(this.indicatorpos == 'right'){
13648 //cls : 'input-group-addon',
13649 html : this.fieldLabel
13659 // Roo.log(" no label && no align");
13666 ['xs','sm','md','lg'].map(function(size){
13667 if (settings[size]) {
13668 cfg.cls += ' col-' + size + '-' + settings[size];
13676 _initEventsCalled : false,
13679 initEvents: function()
13681 if (this._initEventsCalled) { // as we call render... prevent looping...
13684 this._initEventsCalled = true;
13687 throw "can not find store for combo";
13690 this.indicator = this.indicatorEl();
13692 this.store = Roo.factory(this.store, Roo.data);
13693 this.store.parent = this;
13695 // if we are building from html. then this element is so complex, that we can not really
13696 // use the rendered HTML.
13697 // so we have to trash and replace the previous code.
13698 if (Roo.XComponent.build_from_html) {
13699 // remove this element....
13700 var e = this.el.dom, k=0;
13701 while (e ) { e = e.previousSibling; ++k;}
13706 this.rendered = false;
13708 this.render(this.parent().getChildContainer(true), k);
13711 if(Roo.isIOS && this.useNativeIOS){
13712 this.initIOSView();
13720 if(Roo.isTouch && this.mobileTouchView){
13721 this.initTouchView();
13726 this.initTickableEvents();
13730 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13732 if(this.hiddenName){
13734 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13736 this.hiddenField.dom.value =
13737 this.hiddenValue !== undefined ? this.hiddenValue :
13738 this.value !== undefined ? this.value : '';
13740 // prevent input submission
13741 this.el.dom.removeAttribute('name');
13742 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13747 // this.el.dom.setAttribute('autocomplete', 'off');
13750 var cls = 'x-combo-list';
13752 //this.list = new Roo.Layer({
13753 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13759 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13760 _this.list.setWidth(lw);
13763 this.list.on('mouseover', this.onViewOver, this);
13764 this.list.on('mousemove', this.onViewMove, this);
13765 this.list.on('scroll', this.onViewScroll, this);
13768 this.list.swallowEvent('mousewheel');
13769 this.assetHeight = 0;
13772 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13773 this.assetHeight += this.header.getHeight();
13776 this.innerList = this.list.createChild({cls:cls+'-inner'});
13777 this.innerList.on('mouseover', this.onViewOver, this);
13778 this.innerList.on('mousemove', this.onViewMove, this);
13779 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13781 if(this.allowBlank && !this.pageSize && !this.disableClear){
13782 this.footer = this.list.createChild({cls:cls+'-ft'});
13783 this.pageTb = new Roo.Toolbar(this.footer);
13787 this.footer = this.list.createChild({cls:cls+'-ft'});
13788 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13789 {pageSize: this.pageSize});
13793 if (this.pageTb && this.allowBlank && !this.disableClear) {
13795 this.pageTb.add(new Roo.Toolbar.Fill(), {
13796 cls: 'x-btn-icon x-btn-clear',
13798 handler: function()
13801 _this.clearValue();
13802 _this.onSelect(false, -1);
13807 this.assetHeight += this.footer.getHeight();
13812 this.tpl = Roo.bootstrap.version == 4 ?
13813 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13814 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13817 this.view = new Roo.View(this.list, this.tpl, {
13818 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13820 //this.view.wrapEl.setDisplayed(false);
13821 this.view.on('click', this.onViewClick, this);
13824 this.store.on('beforeload', this.onBeforeLoad, this);
13825 this.store.on('load', this.onLoad, this);
13826 this.store.on('loadexception', this.onLoadException, this);
13828 if(this.resizable){
13829 this.resizer = new Roo.Resizable(this.list, {
13830 pinned:true, handles:'se'
13832 this.resizer.on('resize', function(r, w, h){
13833 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13834 this.listWidth = w;
13835 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13836 this.restrictHeight();
13838 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13841 if(!this.editable){
13842 this.editable = true;
13843 this.setEditable(false);
13848 if (typeof(this.events.add.listeners) != 'undefined') {
13850 this.addicon = this.wrap.createChild(
13851 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13853 this.addicon.on('click', function(e) {
13854 this.fireEvent('add', this);
13857 if (typeof(this.events.edit.listeners) != 'undefined') {
13859 this.editicon = this.wrap.createChild(
13860 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13861 if (this.addicon) {
13862 this.editicon.setStyle('margin-left', '40px');
13864 this.editicon.on('click', function(e) {
13866 // we fire even if inothing is selected..
13867 this.fireEvent('edit', this, this.lastData );
13873 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13874 "up" : function(e){
13875 this.inKeyMode = true;
13879 "down" : function(e){
13880 if(!this.isExpanded()){
13881 this.onTriggerClick();
13883 this.inKeyMode = true;
13888 "enter" : function(e){
13889 // this.onViewClick();
13893 if(this.fireEvent("specialkey", this, e)){
13894 this.onViewClick(false);
13900 "esc" : function(e){
13904 "tab" : function(e){
13907 if(this.fireEvent("specialkey", this, e)){
13908 this.onViewClick(false);
13916 doRelay : function(foo, bar, hname){
13917 if(hname == 'down' || this.scope.isExpanded()){
13918 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13927 this.queryDelay = Math.max(this.queryDelay || 10,
13928 this.mode == 'local' ? 10 : 250);
13931 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13933 if(this.typeAhead){
13934 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13936 if(this.editable !== false){
13937 this.inputEl().on("keyup", this.onKeyUp, this);
13939 if(this.forceSelection){
13940 this.inputEl().on('blur', this.doForce, this);
13944 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13945 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13949 initTickableEvents: function()
13953 if(this.hiddenName){
13955 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13957 this.hiddenField.dom.value =
13958 this.hiddenValue !== undefined ? this.hiddenValue :
13959 this.value !== undefined ? this.value : '';
13961 // prevent input submission
13962 this.el.dom.removeAttribute('name');
13963 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13968 // this.list = this.el.select('ul.dropdown-menu',true).first();
13970 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13971 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13972 if(this.triggerList){
13973 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13976 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13977 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13979 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13980 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13982 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13983 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13985 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13986 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13987 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13990 this.cancelBtn.hide();
13995 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13996 _this.list.setWidth(lw);
13999 this.list.on('mouseover', this.onViewOver, this);
14000 this.list.on('mousemove', this.onViewMove, this);
14002 this.list.on('scroll', this.onViewScroll, this);
14005 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14006 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14009 this.view = new Roo.View(this.list, this.tpl, {
14014 selectedClass: this.selectedClass
14017 //this.view.wrapEl.setDisplayed(false);
14018 this.view.on('click', this.onViewClick, this);
14022 this.store.on('beforeload', this.onBeforeLoad, this);
14023 this.store.on('load', this.onLoad, this);
14024 this.store.on('loadexception', this.onLoadException, this);
14027 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14028 "up" : function(e){
14029 this.inKeyMode = true;
14033 "down" : function(e){
14034 this.inKeyMode = true;
14038 "enter" : function(e){
14039 if(this.fireEvent("specialkey", this, e)){
14040 this.onViewClick(false);
14046 "esc" : function(e){
14047 this.onTickableFooterButtonClick(e, false, false);
14050 "tab" : function(e){
14051 this.fireEvent("specialkey", this, e);
14053 this.onTickableFooterButtonClick(e, false, false);
14060 doRelay : function(e, fn, key){
14061 if(this.scope.isExpanded()){
14062 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14071 this.queryDelay = Math.max(this.queryDelay || 10,
14072 this.mode == 'local' ? 10 : 250);
14075 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14077 if(this.typeAhead){
14078 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14081 if(this.editable !== false){
14082 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14085 this.indicator = this.indicatorEl();
14087 if(this.indicator){
14088 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14089 this.indicator.hide();
14094 onDestroy : function(){
14096 this.view.setStore(null);
14097 this.view.el.removeAllListeners();
14098 this.view.el.remove();
14099 this.view.purgeListeners();
14102 this.list.dom.innerHTML = '';
14106 this.store.un('beforeload', this.onBeforeLoad, this);
14107 this.store.un('load', this.onLoad, this);
14108 this.store.un('loadexception', this.onLoadException, this);
14110 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14114 fireKey : function(e){
14115 if(e.isNavKeyPress() && !this.list.isVisible()){
14116 this.fireEvent("specialkey", this, e);
14121 onResize: function(w, h){
14122 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14124 // if(typeof w != 'number'){
14125 // // we do not handle it!?!?
14128 // var tw = this.trigger.getWidth();
14129 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14130 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14132 // this.inputEl().setWidth( this.adjustWidth('input', x));
14134 // //this.trigger.setStyle('left', x+'px');
14136 // if(this.list && this.listWidth === undefined){
14137 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14138 // this.list.setWidth(lw);
14139 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14147 * Allow or prevent the user from directly editing the field text. If false is passed,
14148 * the user will only be able to select from the items defined in the dropdown list. This method
14149 * is the runtime equivalent of setting the 'editable' config option at config time.
14150 * @param {Boolean} value True to allow the user to directly edit the field text
14152 setEditable : function(value){
14153 if(value == this.editable){
14156 this.editable = value;
14158 this.inputEl().dom.setAttribute('readOnly', true);
14159 this.inputEl().on('mousedown', this.onTriggerClick, this);
14160 this.inputEl().addClass('x-combo-noedit');
14162 this.inputEl().dom.setAttribute('readOnly', false);
14163 this.inputEl().un('mousedown', this.onTriggerClick, this);
14164 this.inputEl().removeClass('x-combo-noedit');
14170 onBeforeLoad : function(combo,opts){
14171 if(!this.hasFocus){
14175 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14177 this.restrictHeight();
14178 this.selectedIndex = -1;
14182 onLoad : function(){
14184 this.hasQuery = false;
14186 if(!this.hasFocus){
14190 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14191 this.loading.hide();
14194 if(this.store.getCount() > 0){
14197 this.restrictHeight();
14198 if(this.lastQuery == this.allQuery){
14199 if(this.editable && !this.tickable){
14200 this.inputEl().dom.select();
14204 !this.selectByValue(this.value, true) &&
14207 !this.store.lastOptions ||
14208 typeof(this.store.lastOptions.add) == 'undefined' ||
14209 this.store.lastOptions.add != true
14212 this.select(0, true);
14215 if(this.autoFocus){
14218 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14219 this.taTask.delay(this.typeAheadDelay);
14223 this.onEmptyResults();
14229 onLoadException : function()
14231 this.hasQuery = false;
14233 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14234 this.loading.hide();
14237 if(this.tickable && this.editable){
14242 // only causes errors at present
14243 //Roo.log(this.store.reader.jsonData);
14244 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14246 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14252 onTypeAhead : function(){
14253 if(this.store.getCount() > 0){
14254 var r = this.store.getAt(0);
14255 var newValue = r.data[this.displayField];
14256 var len = newValue.length;
14257 var selStart = this.getRawValue().length;
14259 if(selStart != len){
14260 this.setRawValue(newValue);
14261 this.selectText(selStart, newValue.length);
14267 onSelect : function(record, index){
14269 if(this.fireEvent('beforeselect', this, record, index) !== false){
14271 this.setFromData(index > -1 ? record.data : false);
14274 this.fireEvent('select', this, record, index);
14279 * Returns the currently selected field value or empty string if no value is set.
14280 * @return {String} value The selected value
14282 getValue : function()
14284 if(Roo.isIOS && this.useNativeIOS){
14285 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14289 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14292 if(this.valueField){
14293 return typeof this.value != 'undefined' ? this.value : '';
14295 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14299 getRawValue : function()
14301 if(Roo.isIOS && this.useNativeIOS){
14302 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14305 var v = this.inputEl().getValue();
14311 * Clears any text/value currently set in the field
14313 clearValue : function(){
14315 if(this.hiddenField){
14316 this.hiddenField.dom.value = '';
14319 this.setRawValue('');
14320 this.lastSelectionText = '';
14321 this.lastData = false;
14323 var close = this.closeTriggerEl();
14334 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14335 * will be displayed in the field. If the value does not match the data value of an existing item,
14336 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14337 * Otherwise the field will be blank (although the value will still be set).
14338 * @param {String} value The value to match
14340 setValue : function(v)
14342 if(Roo.isIOS && this.useNativeIOS){
14343 this.setIOSValue(v);
14353 if(this.valueField){
14354 var r = this.findRecord(this.valueField, v);
14356 text = r.data[this.displayField];
14357 }else if(this.valueNotFoundText !== undefined){
14358 text = this.valueNotFoundText;
14361 this.lastSelectionText = text;
14362 if(this.hiddenField){
14363 this.hiddenField.dom.value = v;
14365 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14368 var close = this.closeTriggerEl();
14371 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14377 * @property {Object} the last set data for the element
14382 * Sets the value of the field based on a object which is related to the record format for the store.
14383 * @param {Object} value the value to set as. or false on reset?
14385 setFromData : function(o){
14392 var dv = ''; // display value
14393 var vv = ''; // value value..
14395 if (this.displayField) {
14396 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14398 // this is an error condition!!!
14399 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14402 if(this.valueField){
14403 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14406 var close = this.closeTriggerEl();
14409 if(dv.length || vv * 1 > 0){
14411 this.blockFocus=true;
14417 if(this.hiddenField){
14418 this.hiddenField.dom.value = vv;
14420 this.lastSelectionText = dv;
14421 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14425 // no hidden field.. - we store the value in 'value', but still display
14426 // display field!!!!
14427 this.lastSelectionText = dv;
14428 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14435 reset : function(){
14436 // overridden so that last data is reset..
14443 this.setValue(this.originalValue);
14444 //this.clearInvalid();
14445 this.lastData = false;
14447 this.view.clearSelections();
14453 findRecord : function(prop, value){
14455 if(this.store.getCount() > 0){
14456 this.store.each(function(r){
14457 if(r.data[prop] == value){
14467 getName: function()
14469 // returns hidden if it's set..
14470 if (!this.rendered) {return ''};
14471 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14475 onViewMove : function(e, t){
14476 this.inKeyMode = false;
14480 onViewOver : function(e, t){
14481 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14484 var item = this.view.findItemFromChild(t);
14487 var index = this.view.indexOf(item);
14488 this.select(index, false);
14493 onViewClick : function(view, doFocus, el, e)
14495 var index = this.view.getSelectedIndexes()[0];
14497 var r = this.store.getAt(index);
14501 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14508 Roo.each(this.tickItems, function(v,k){
14510 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14512 _this.tickItems.splice(k, 1);
14514 if(typeof(e) == 'undefined' && view == false){
14515 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14527 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14528 this.tickItems.push(r.data);
14531 if(typeof(e) == 'undefined' && view == false){
14532 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14539 this.onSelect(r, index);
14541 if(doFocus !== false && !this.blockFocus){
14542 this.inputEl().focus();
14547 restrictHeight : function(){
14548 //this.innerList.dom.style.height = '';
14549 //var inner = this.innerList.dom;
14550 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14551 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14552 //this.list.beginUpdate();
14553 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14554 this.list.alignTo(this.inputEl(), this.listAlign);
14555 this.list.alignTo(this.inputEl(), this.listAlign);
14556 //this.list.endUpdate();
14560 onEmptyResults : function(){
14562 if(this.tickable && this.editable){
14563 this.hasFocus = false;
14564 this.restrictHeight();
14572 * Returns true if the dropdown list is expanded, else false.
14574 isExpanded : function(){
14575 return this.list.isVisible();
14579 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14580 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14581 * @param {String} value The data value of the item to select
14582 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14583 * selected item if it is not currently in view (defaults to true)
14584 * @return {Boolean} True if the value matched an item in the list, else false
14586 selectByValue : function(v, scrollIntoView){
14587 if(v !== undefined && v !== null){
14588 var r = this.findRecord(this.valueField || this.displayField, v);
14590 this.select(this.store.indexOf(r), scrollIntoView);
14598 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14599 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14600 * @param {Number} index The zero-based index of the list item to select
14601 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14602 * selected item if it is not currently in view (defaults to true)
14604 select : function(index, scrollIntoView){
14605 this.selectedIndex = index;
14606 this.view.select(index);
14607 if(scrollIntoView !== false){
14608 var el = this.view.getNode(index);
14610 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14613 this.list.scrollChildIntoView(el, false);
14619 selectNext : function(){
14620 var ct = this.store.getCount();
14622 if(this.selectedIndex == -1){
14624 }else if(this.selectedIndex < ct-1){
14625 this.select(this.selectedIndex+1);
14631 selectPrev : function(){
14632 var ct = this.store.getCount();
14634 if(this.selectedIndex == -1){
14636 }else if(this.selectedIndex != 0){
14637 this.select(this.selectedIndex-1);
14643 onKeyUp : function(e){
14644 if(this.editable !== false && !e.isSpecialKey()){
14645 this.lastKey = e.getKey();
14646 this.dqTask.delay(this.queryDelay);
14651 validateBlur : function(){
14652 return !this.list || !this.list.isVisible();
14656 initQuery : function(){
14658 var v = this.getRawValue();
14660 if(this.tickable && this.editable){
14661 v = this.tickableInputEl().getValue();
14668 doForce : function(){
14669 if(this.inputEl().dom.value.length > 0){
14670 this.inputEl().dom.value =
14671 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14677 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14678 * query allowing the query action to be canceled if needed.
14679 * @param {String} query The SQL query to execute
14680 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14681 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14682 * saved in the current store (defaults to false)
14684 doQuery : function(q, forceAll){
14686 if(q === undefined || q === null){
14691 forceAll: forceAll,
14695 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14700 forceAll = qe.forceAll;
14701 if(forceAll === true || (q.length >= this.minChars)){
14703 this.hasQuery = true;
14705 if(this.lastQuery != q || this.alwaysQuery){
14706 this.lastQuery = q;
14707 if(this.mode == 'local'){
14708 this.selectedIndex = -1;
14710 this.store.clearFilter();
14713 if(this.specialFilter){
14714 this.fireEvent('specialfilter', this);
14719 this.store.filter(this.displayField, q);
14722 this.store.fireEvent("datachanged", this.store);
14729 this.store.baseParams[this.queryParam] = q;
14731 var options = {params : this.getParams(q)};
14734 options.add = true;
14735 options.params.start = this.page * this.pageSize;
14738 this.store.load(options);
14741 * this code will make the page width larger, at the beginning, the list not align correctly,
14742 * we should expand the list on onLoad
14743 * so command out it
14748 this.selectedIndex = -1;
14753 this.loadNext = false;
14757 getParams : function(q){
14759 //p[this.queryParam] = q;
14763 p.limit = this.pageSize;
14769 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14771 collapse : function(){
14772 if(!this.isExpanded()){
14778 this.hasFocus = false;
14782 this.cancelBtn.hide();
14783 this.trigger.show();
14786 this.tickableInputEl().dom.value = '';
14787 this.tickableInputEl().blur();
14792 Roo.get(document).un('mousedown', this.collapseIf, this);
14793 Roo.get(document).un('mousewheel', this.collapseIf, this);
14794 if (!this.editable) {
14795 Roo.get(document).un('keydown', this.listKeyPress, this);
14797 this.fireEvent('collapse', this);
14803 collapseIf : function(e){
14804 var in_combo = e.within(this.el);
14805 var in_list = e.within(this.list);
14806 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14808 if (in_combo || in_list || is_list) {
14809 //e.stopPropagation();
14814 this.onTickableFooterButtonClick(e, false, false);
14822 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14824 expand : function(){
14826 if(this.isExpanded() || !this.hasFocus){
14830 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14831 this.list.setWidth(lw);
14837 this.restrictHeight();
14841 this.tickItems = Roo.apply([], this.item);
14844 this.cancelBtn.show();
14845 this.trigger.hide();
14848 this.tickableInputEl().focus();
14853 Roo.get(document).on('mousedown', this.collapseIf, this);
14854 Roo.get(document).on('mousewheel', this.collapseIf, this);
14855 if (!this.editable) {
14856 Roo.get(document).on('keydown', this.listKeyPress, this);
14859 this.fireEvent('expand', this);
14863 // Implements the default empty TriggerField.onTriggerClick function
14864 onTriggerClick : function(e)
14866 Roo.log('trigger click');
14868 if(this.disabled || !this.triggerList){
14873 this.loadNext = false;
14875 if(this.isExpanded()){
14877 if (!this.blockFocus) {
14878 this.inputEl().focus();
14882 this.hasFocus = true;
14883 if(this.triggerAction == 'all') {
14884 this.doQuery(this.allQuery, true);
14886 this.doQuery(this.getRawValue());
14888 if (!this.blockFocus) {
14889 this.inputEl().focus();
14894 onTickableTriggerClick : function(e)
14901 this.loadNext = false;
14902 this.hasFocus = true;
14904 if(this.triggerAction == 'all') {
14905 this.doQuery(this.allQuery, true);
14907 this.doQuery(this.getRawValue());
14911 onSearchFieldClick : function(e)
14913 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14914 this.onTickableFooterButtonClick(e, false, false);
14918 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14923 this.loadNext = false;
14924 this.hasFocus = true;
14926 if(this.triggerAction == 'all') {
14927 this.doQuery(this.allQuery, true);
14929 this.doQuery(this.getRawValue());
14933 listKeyPress : function(e)
14935 //Roo.log('listkeypress');
14936 // scroll to first matching element based on key pres..
14937 if (e.isSpecialKey()) {
14940 var k = String.fromCharCode(e.getKey()).toUpperCase();
14943 var csel = this.view.getSelectedNodes();
14944 var cselitem = false;
14946 var ix = this.view.indexOf(csel[0]);
14947 cselitem = this.store.getAt(ix);
14948 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14954 this.store.each(function(v) {
14956 // start at existing selection.
14957 if (cselitem.id == v.id) {
14963 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14964 match = this.store.indexOf(v);
14970 if (match === false) {
14971 return true; // no more action?
14974 this.view.select(match);
14975 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14976 sn.scrollIntoView(sn.dom.parentNode, false);
14979 onViewScroll : function(e, t){
14981 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){
14985 this.hasQuery = true;
14987 this.loading = this.list.select('.loading', true).first();
14989 if(this.loading === null){
14990 this.list.createChild({
14992 cls: 'loading roo-select2-more-results roo-select2-active',
14993 html: 'Loading more results...'
14996 this.loading = this.list.select('.loading', true).first();
14998 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
15000 this.loading.hide();
15003 this.loading.show();
15008 this.loadNext = true;
15010 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15015 addItem : function(o)
15017 var dv = ''; // display value
15019 if (this.displayField) {
15020 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15022 // this is an error condition!!!
15023 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15030 var choice = this.choices.createChild({
15032 cls: 'roo-select2-search-choice',
15041 cls: 'roo-select2-search-choice-close fa fa-times',
15046 }, this.searchField);
15048 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15050 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15058 this.inputEl().dom.value = '';
15063 onRemoveItem : function(e, _self, o)
15065 e.preventDefault();
15067 this.lastItem = Roo.apply([], this.item);
15069 var index = this.item.indexOf(o.data) * 1;
15072 Roo.log('not this item?!');
15076 this.item.splice(index, 1);
15081 this.fireEvent('remove', this, e);
15087 syncValue : function()
15089 if(!this.item.length){
15096 Roo.each(this.item, function(i){
15097 if(_this.valueField){
15098 value.push(i[_this.valueField]);
15105 this.value = value.join(',');
15107 if(this.hiddenField){
15108 this.hiddenField.dom.value = this.value;
15111 this.store.fireEvent("datachanged", this.store);
15116 clearItem : function()
15118 if(!this.multiple){
15124 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15132 if(this.tickable && !Roo.isTouch){
15133 this.view.refresh();
15137 inputEl: function ()
15139 if(Roo.isIOS && this.useNativeIOS){
15140 return this.el.select('select.roo-ios-select', true).first();
15143 if(Roo.isTouch && this.mobileTouchView){
15144 return this.el.select('input.form-control',true).first();
15148 return this.searchField;
15151 return this.el.select('input.form-control',true).first();
15154 onTickableFooterButtonClick : function(e, btn, el)
15156 e.preventDefault();
15158 this.lastItem = Roo.apply([], this.item);
15160 if(btn && btn.name == 'cancel'){
15161 this.tickItems = Roo.apply([], this.item);
15170 Roo.each(this.tickItems, function(o){
15178 validate : function()
15180 if(this.getVisibilityEl().hasClass('hidden')){
15184 var v = this.getRawValue();
15187 v = this.getValue();
15190 if(this.disabled || this.allowBlank || v.length){
15195 this.markInvalid();
15199 tickableInputEl : function()
15201 if(!this.tickable || !this.editable){
15202 return this.inputEl();
15205 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15209 getAutoCreateTouchView : function()
15214 cls: 'form-group' //input-group
15220 type : this.inputType,
15221 cls : 'form-control x-combo-noedit',
15222 autocomplete: 'new-password',
15223 placeholder : this.placeholder || '',
15228 input.name = this.name;
15232 input.cls += ' input-' + this.size;
15235 if (this.disabled) {
15236 input.disabled = true;
15247 inputblock.cls += ' input-group';
15249 inputblock.cn.unshift({
15251 cls : 'input-group-addon input-group-prepend input-group-text',
15256 if(this.removable && !this.multiple){
15257 inputblock.cls += ' roo-removable';
15259 inputblock.cn.push({
15262 cls : 'roo-combo-removable-btn close'
15266 if(this.hasFeedback && !this.allowBlank){
15268 inputblock.cls += ' has-feedback';
15270 inputblock.cn.push({
15272 cls: 'glyphicon form-control-feedback'
15279 inputblock.cls += (this.before) ? '' : ' input-group';
15281 inputblock.cn.push({
15283 cls : 'input-group-addon input-group-append input-group-text',
15289 var ibwrap = inputblock;
15294 cls: 'roo-select2-choices',
15298 cls: 'roo-select2-search-field',
15311 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15316 cls: 'form-hidden-field'
15322 if(!this.multiple && this.showToggleBtn){
15329 if (this.caret != false) {
15332 cls: 'fa fa-' + this.caret
15339 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15344 cls: 'combobox-clear',
15358 combobox.cls += ' roo-select2-container-multi';
15361 var align = this.labelAlign || this.parentLabelAlign();
15363 if (align ==='left' && this.fieldLabel.length) {
15368 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15369 tooltip : 'This field is required'
15373 cls : 'control-label col-form-label',
15374 html : this.fieldLabel
15385 var labelCfg = cfg.cn[1];
15386 var contentCfg = cfg.cn[2];
15389 if(this.indicatorpos == 'right'){
15394 cls : 'control-label col-form-label',
15398 html : this.fieldLabel
15402 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15403 tooltip : 'This field is required'
15416 labelCfg = cfg.cn[0];
15417 contentCfg = cfg.cn[1];
15422 if(this.labelWidth > 12){
15423 labelCfg.style = "width: " + this.labelWidth + 'px';
15426 if(this.labelWidth < 13 && this.labelmd == 0){
15427 this.labelmd = this.labelWidth;
15430 if(this.labellg > 0){
15431 labelCfg.cls += ' col-lg-' + this.labellg;
15432 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15435 if(this.labelmd > 0){
15436 labelCfg.cls += ' col-md-' + this.labelmd;
15437 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15440 if(this.labelsm > 0){
15441 labelCfg.cls += ' col-sm-' + this.labelsm;
15442 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15445 if(this.labelxs > 0){
15446 labelCfg.cls += ' col-xs-' + this.labelxs;
15447 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15451 } else if ( this.fieldLabel.length) {
15455 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15456 tooltip : 'This field is required'
15460 cls : 'control-label',
15461 html : this.fieldLabel
15472 if(this.indicatorpos == 'right'){
15476 cls : 'control-label',
15477 html : this.fieldLabel,
15481 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15482 tooltip : 'This field is required'
15499 var settings = this;
15501 ['xs','sm','md','lg'].map(function(size){
15502 if (settings[size]) {
15503 cfg.cls += ' col-' + size + '-' + settings[size];
15510 initTouchView : function()
15512 this.renderTouchView();
15514 this.touchViewEl.on('scroll', function(){
15515 this.el.dom.scrollTop = 0;
15518 this.originalValue = this.getValue();
15520 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15522 this.inputEl().on("click", this.showTouchView, this);
15523 if (this.triggerEl) {
15524 this.triggerEl.on("click", this.showTouchView, this);
15528 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15529 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15531 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15533 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15534 this.store.on('load', this.onTouchViewLoad, this);
15535 this.store.on('loadexception', this.onTouchViewLoadException, this);
15537 if(this.hiddenName){
15539 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15541 this.hiddenField.dom.value =
15542 this.hiddenValue !== undefined ? this.hiddenValue :
15543 this.value !== undefined ? this.value : '';
15545 this.el.dom.removeAttribute('name');
15546 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15550 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15551 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15554 if(this.removable && !this.multiple){
15555 var close = this.closeTriggerEl();
15557 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15558 close.on('click', this.removeBtnClick, this, close);
15562 * fix the bug in Safari iOS8
15564 this.inputEl().on("focus", function(e){
15565 document.activeElement.blur();
15568 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15575 renderTouchView : function()
15577 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15578 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15580 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15581 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15583 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15584 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15585 this.touchViewBodyEl.setStyle('overflow', 'auto');
15587 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15588 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15590 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15591 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15595 showTouchView : function()
15601 this.touchViewHeaderEl.hide();
15603 if(this.modalTitle.length){
15604 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15605 this.touchViewHeaderEl.show();
15608 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15609 this.touchViewEl.show();
15611 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15613 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15614 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15616 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15618 if(this.modalTitle.length){
15619 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15622 this.touchViewBodyEl.setHeight(bodyHeight);
15626 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15628 this.touchViewEl.addClass('in');
15631 if(this._touchViewMask){
15632 Roo.get(document.body).addClass("x-body-masked");
15633 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15634 this._touchViewMask.setStyle('z-index', 10000);
15635 this._touchViewMask.addClass('show');
15638 this.doTouchViewQuery();
15642 hideTouchView : function()
15644 this.touchViewEl.removeClass('in');
15648 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15650 this.touchViewEl.setStyle('display', 'none');
15653 if(this._touchViewMask){
15654 this._touchViewMask.removeClass('show');
15655 Roo.get(document.body).removeClass("x-body-masked");
15659 setTouchViewValue : function()
15666 Roo.each(this.tickItems, function(o){
15671 this.hideTouchView();
15674 doTouchViewQuery : function()
15683 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15687 if(!this.alwaysQuery || this.mode == 'local'){
15688 this.onTouchViewLoad();
15695 onTouchViewBeforeLoad : function(combo,opts)
15701 onTouchViewLoad : function()
15703 if(this.store.getCount() < 1){
15704 this.onTouchViewEmptyResults();
15708 this.clearTouchView();
15710 var rawValue = this.getRawValue();
15712 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15714 this.tickItems = [];
15716 this.store.data.each(function(d, rowIndex){
15717 var row = this.touchViewListGroup.createChild(template);
15719 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15720 row.addClass(d.data.cls);
15723 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15726 html : d.data[this.displayField]
15729 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15730 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15733 row.removeClass('selected');
15734 if(!this.multiple && this.valueField &&
15735 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15738 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15739 row.addClass('selected');
15742 if(this.multiple && this.valueField &&
15743 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15747 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15748 this.tickItems.push(d.data);
15751 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15755 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15757 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15759 if(this.modalTitle.length){
15760 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15763 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15765 if(this.mobile_restrict_height && listHeight < bodyHeight){
15766 this.touchViewBodyEl.setHeight(listHeight);
15771 if(firstChecked && listHeight > bodyHeight){
15772 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15777 onTouchViewLoadException : function()
15779 this.hideTouchView();
15782 onTouchViewEmptyResults : function()
15784 this.clearTouchView();
15786 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15788 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15792 clearTouchView : function()
15794 this.touchViewListGroup.dom.innerHTML = '';
15797 onTouchViewClick : function(e, el, o)
15799 e.preventDefault();
15802 var rowIndex = o.rowIndex;
15804 var r = this.store.getAt(rowIndex);
15806 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15808 if(!this.multiple){
15809 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15810 c.dom.removeAttribute('checked');
15813 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15815 this.setFromData(r.data);
15817 var close = this.closeTriggerEl();
15823 this.hideTouchView();
15825 this.fireEvent('select', this, r, rowIndex);
15830 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15831 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15832 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15836 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15837 this.addItem(r.data);
15838 this.tickItems.push(r.data);
15842 getAutoCreateNativeIOS : function()
15845 cls: 'form-group' //input-group,
15850 cls : 'roo-ios-select'
15854 combobox.name = this.name;
15857 if (this.disabled) {
15858 combobox.disabled = true;
15861 var settings = this;
15863 ['xs','sm','md','lg'].map(function(size){
15864 if (settings[size]) {
15865 cfg.cls += ' col-' + size + '-' + settings[size];
15875 initIOSView : function()
15877 this.store.on('load', this.onIOSViewLoad, this);
15882 onIOSViewLoad : function()
15884 if(this.store.getCount() < 1){
15888 this.clearIOSView();
15890 if(this.allowBlank) {
15892 var default_text = '-- SELECT --';
15894 if(this.placeholder.length){
15895 default_text = this.placeholder;
15898 if(this.emptyTitle.length){
15899 default_text += ' - ' + this.emptyTitle + ' -';
15902 var opt = this.inputEl().createChild({
15905 html : default_text
15909 o[this.valueField] = 0;
15910 o[this.displayField] = default_text;
15912 this.ios_options.push({
15919 this.store.data.each(function(d, rowIndex){
15923 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15924 html = d.data[this.displayField];
15929 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15930 value = d.data[this.valueField];
15939 if(this.value == d.data[this.valueField]){
15940 option['selected'] = true;
15943 var opt = this.inputEl().createChild(option);
15945 this.ios_options.push({
15952 this.inputEl().on('change', function(){
15953 this.fireEvent('select', this);
15958 clearIOSView: function()
15960 this.inputEl().dom.innerHTML = '';
15962 this.ios_options = [];
15965 setIOSValue: function(v)
15969 if(!this.ios_options){
15973 Roo.each(this.ios_options, function(opts){
15975 opts.el.dom.removeAttribute('selected');
15977 if(opts.data[this.valueField] != v){
15981 opts.el.dom.setAttribute('selected', true);
15987 * @cfg {Boolean} grow
15991 * @cfg {Number} growMin
15995 * @cfg {Number} growMax
16004 Roo.apply(Roo.bootstrap.ComboBox, {
16008 cls: 'modal-header',
16030 cls: 'list-group-item',
16034 cls: 'roo-combobox-list-group-item-value'
16038 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16052 listItemCheckbox : {
16054 cls: 'list-group-item',
16058 cls: 'roo-combobox-list-group-item-value'
16062 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16078 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16083 cls: 'modal-footer',
16091 cls: 'col-xs-6 text-left',
16094 cls: 'btn btn-danger roo-touch-view-cancel',
16100 cls: 'col-xs-6 text-right',
16103 cls: 'btn btn-success roo-touch-view-ok',
16114 Roo.apply(Roo.bootstrap.ComboBox, {
16116 touchViewTemplate : {
16118 cls: 'modal fade roo-combobox-touch-view',
16122 cls: 'modal-dialog',
16123 style : 'position:fixed', // we have to fix position....
16127 cls: 'modal-content',
16129 Roo.bootstrap.ComboBox.header,
16130 Roo.bootstrap.ComboBox.body,
16131 Roo.bootstrap.ComboBox.footer
16140 * Ext JS Library 1.1.1
16141 * Copyright(c) 2006-2007, Ext JS, LLC.
16143 * Originally Released Under LGPL - original licence link has changed is not relivant.
16146 * <script type="text/javascript">
16151 * @extends Roo.util.Observable
16152 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16153 * This class also supports single and multi selection modes. <br>
16154 * Create a data model bound view:
16156 var store = new Roo.data.Store(...);
16158 var view = new Roo.View({
16160 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16162 singleSelect: true,
16163 selectedClass: "ydataview-selected",
16167 // listen for node click?
16168 view.on("click", function(vw, index, node, e){
16169 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16173 dataModel.load("foobar.xml");
16175 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16177 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16178 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16180 * Note: old style constructor is still suported (container, template, config)
16183 * Create a new View
16184 * @param {Object} config The config object
16187 Roo.View = function(config, depreciated_tpl, depreciated_config){
16189 this.parent = false;
16191 if (typeof(depreciated_tpl) == 'undefined') {
16192 // new way.. - universal constructor.
16193 Roo.apply(this, config);
16194 this.el = Roo.get(this.el);
16197 this.el = Roo.get(config);
16198 this.tpl = depreciated_tpl;
16199 Roo.apply(this, depreciated_config);
16201 this.wrapEl = this.el.wrap().wrap();
16202 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16205 if(typeof(this.tpl) == "string"){
16206 this.tpl = new Roo.Template(this.tpl);
16208 // support xtype ctors..
16209 this.tpl = new Roo.factory(this.tpl, Roo);
16213 this.tpl.compile();
16218 * @event beforeclick
16219 * Fires before a click is processed. Returns false to cancel the default action.
16220 * @param {Roo.View} this
16221 * @param {Number} index The index of the target node
16222 * @param {HTMLElement} node The target node
16223 * @param {Roo.EventObject} e The raw event object
16225 "beforeclick" : true,
16228 * Fires when a template node is clicked.
16229 * @param {Roo.View} this
16230 * @param {Number} index The index of the target node
16231 * @param {HTMLElement} node The target node
16232 * @param {Roo.EventObject} e The raw event object
16237 * Fires when a template node is double clicked.
16238 * @param {Roo.View} this
16239 * @param {Number} index The index of the target node
16240 * @param {HTMLElement} node The target node
16241 * @param {Roo.EventObject} e The raw event object
16245 * @event contextmenu
16246 * Fires when a template node is right clicked.
16247 * @param {Roo.View} this
16248 * @param {Number} index The index of the target node
16249 * @param {HTMLElement} node The target node
16250 * @param {Roo.EventObject} e The raw event object
16252 "contextmenu" : true,
16254 * @event selectionchange
16255 * Fires when the selected nodes change.
16256 * @param {Roo.View} this
16257 * @param {Array} selections Array of the selected nodes
16259 "selectionchange" : true,
16262 * @event beforeselect
16263 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16264 * @param {Roo.View} this
16265 * @param {HTMLElement} node The node to be selected
16266 * @param {Array} selections Array of currently selected nodes
16268 "beforeselect" : true,
16270 * @event preparedata
16271 * Fires on every row to render, to allow you to change the data.
16272 * @param {Roo.View} this
16273 * @param {Object} data to be rendered (change this)
16275 "preparedata" : true
16283 "click": this.onClick,
16284 "dblclick": this.onDblClick,
16285 "contextmenu": this.onContextMenu,
16289 this.selections = [];
16291 this.cmp = new Roo.CompositeElementLite([]);
16293 this.store = Roo.factory(this.store, Roo.data);
16294 this.setStore(this.store, true);
16297 if ( this.footer && this.footer.xtype) {
16299 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16301 this.footer.dataSource = this.store;
16302 this.footer.container = fctr;
16303 this.footer = Roo.factory(this.footer, Roo);
16304 fctr.insertFirst(this.el);
16306 // this is a bit insane - as the paging toolbar seems to detach the el..
16307 // dom.parentNode.parentNode.parentNode
16308 // they get detached?
16312 Roo.View.superclass.constructor.call(this);
16317 Roo.extend(Roo.View, Roo.util.Observable, {
16320 * @cfg {Roo.data.Store} store Data store to load data from.
16325 * @cfg {String|Roo.Element} el The container element.
16330 * @cfg {String|Roo.Template} tpl The template used by this View
16334 * @cfg {String} dataName the named area of the template to use as the data area
16335 * Works with domtemplates roo-name="name"
16339 * @cfg {String} selectedClass The css class to add to selected nodes
16341 selectedClass : "x-view-selected",
16343 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16348 * @cfg {String} text to display on mask (default Loading)
16352 * @cfg {Boolean} multiSelect Allow multiple selection
16354 multiSelect : false,
16356 * @cfg {Boolean} singleSelect Allow single selection
16358 singleSelect: false,
16361 * @cfg {Boolean} toggleSelect - selecting
16363 toggleSelect : false,
16366 * @cfg {Boolean} tickable - selecting
16371 * Returns the element this view is bound to.
16372 * @return {Roo.Element}
16374 getEl : function(){
16375 return this.wrapEl;
16381 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16383 refresh : function(){
16384 //Roo.log('refresh');
16387 // if we are using something like 'domtemplate', then
16388 // the what gets used is:
16389 // t.applySubtemplate(NAME, data, wrapping data..)
16390 // the outer template then get' applied with
16391 // the store 'extra data'
16392 // and the body get's added to the
16393 // roo-name="data" node?
16394 // <span class='roo-tpl-{name}'></span> ?????
16398 this.clearSelections();
16399 this.el.update("");
16401 var records = this.store.getRange();
16402 if(records.length < 1) {
16404 // is this valid?? = should it render a template??
16406 this.el.update(this.emptyText);
16410 if (this.dataName) {
16411 this.el.update(t.apply(this.store.meta)); //????
16412 el = this.el.child('.roo-tpl-' + this.dataName);
16415 for(var i = 0, len = records.length; i < len; i++){
16416 var data = this.prepareData(records[i].data, i, records[i]);
16417 this.fireEvent("preparedata", this, data, i, records[i]);
16419 var d = Roo.apply({}, data);
16422 Roo.apply(d, {'roo-id' : Roo.id()});
16426 Roo.each(this.parent.item, function(item){
16427 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16430 Roo.apply(d, {'roo-data-checked' : 'checked'});
16434 html[html.length] = Roo.util.Format.trim(
16436 t.applySubtemplate(this.dataName, d, this.store.meta) :
16443 el.update(html.join(""));
16444 this.nodes = el.dom.childNodes;
16445 this.updateIndexes(0);
16450 * Function to override to reformat the data that is sent to
16451 * the template for each node.
16452 * DEPRICATED - use the preparedata event handler.
16453 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16454 * a JSON object for an UpdateManager bound view).
16456 prepareData : function(data, index, record)
16458 this.fireEvent("preparedata", this, data, index, record);
16462 onUpdate : function(ds, record){
16463 // Roo.log('on update');
16464 this.clearSelections();
16465 var index = this.store.indexOf(record);
16466 var n = this.nodes[index];
16467 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16468 n.parentNode.removeChild(n);
16469 this.updateIndexes(index, index);
16475 onAdd : function(ds, records, index)
16477 //Roo.log(['on Add', ds, records, index] );
16478 this.clearSelections();
16479 if(this.nodes.length == 0){
16483 var n = this.nodes[index];
16484 for(var i = 0, len = records.length; i < len; i++){
16485 var d = this.prepareData(records[i].data, i, records[i]);
16487 this.tpl.insertBefore(n, d);
16490 this.tpl.append(this.el, d);
16493 this.updateIndexes(index);
16496 onRemove : function(ds, record, index){
16497 // Roo.log('onRemove');
16498 this.clearSelections();
16499 var el = this.dataName ?
16500 this.el.child('.roo-tpl-' + this.dataName) :
16503 el.dom.removeChild(this.nodes[index]);
16504 this.updateIndexes(index);
16508 * Refresh an individual node.
16509 * @param {Number} index
16511 refreshNode : function(index){
16512 this.onUpdate(this.store, this.store.getAt(index));
16515 updateIndexes : function(startIndex, endIndex){
16516 var ns = this.nodes;
16517 startIndex = startIndex || 0;
16518 endIndex = endIndex || ns.length - 1;
16519 for(var i = startIndex; i <= endIndex; i++){
16520 ns[i].nodeIndex = i;
16525 * Changes the data store this view uses and refresh the view.
16526 * @param {Store} store
16528 setStore : function(store, initial){
16529 if(!initial && this.store){
16530 this.store.un("datachanged", this.refresh);
16531 this.store.un("add", this.onAdd);
16532 this.store.un("remove", this.onRemove);
16533 this.store.un("update", this.onUpdate);
16534 this.store.un("clear", this.refresh);
16535 this.store.un("beforeload", this.onBeforeLoad);
16536 this.store.un("load", this.onLoad);
16537 this.store.un("loadexception", this.onLoad);
16541 store.on("datachanged", this.refresh, this);
16542 store.on("add", this.onAdd, this);
16543 store.on("remove", this.onRemove, this);
16544 store.on("update", this.onUpdate, this);
16545 store.on("clear", this.refresh, this);
16546 store.on("beforeload", this.onBeforeLoad, this);
16547 store.on("load", this.onLoad, this);
16548 store.on("loadexception", this.onLoad, this);
16556 * onbeforeLoad - masks the loading area.
16559 onBeforeLoad : function(store,opts)
16561 //Roo.log('onBeforeLoad');
16563 this.el.update("");
16565 this.el.mask(this.mask ? this.mask : "Loading" );
16567 onLoad : function ()
16574 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16575 * @param {HTMLElement} node
16576 * @return {HTMLElement} The template node
16578 findItemFromChild : function(node){
16579 var el = this.dataName ?
16580 this.el.child('.roo-tpl-' + this.dataName,true) :
16583 if(!node || node.parentNode == el){
16586 var p = node.parentNode;
16587 while(p && p != el){
16588 if(p.parentNode == el){
16597 onClick : function(e){
16598 var item = this.findItemFromChild(e.getTarget());
16600 var index = this.indexOf(item);
16601 if(this.onItemClick(item, index, e) !== false){
16602 this.fireEvent("click", this, index, item, e);
16605 this.clearSelections();
16610 onContextMenu : function(e){
16611 var item = this.findItemFromChild(e.getTarget());
16613 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16618 onDblClick : function(e){
16619 var item = this.findItemFromChild(e.getTarget());
16621 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16625 onItemClick : function(item, index, e)
16627 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16630 if (this.toggleSelect) {
16631 var m = this.isSelected(item) ? 'unselect' : 'select';
16634 _t[m](item, true, false);
16637 if(this.multiSelect || this.singleSelect){
16638 if(this.multiSelect && e.shiftKey && this.lastSelection){
16639 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16641 this.select(item, this.multiSelect && e.ctrlKey);
16642 this.lastSelection = item;
16645 if(!this.tickable){
16646 e.preventDefault();
16654 * Get the number of selected nodes.
16657 getSelectionCount : function(){
16658 return this.selections.length;
16662 * Get the currently selected nodes.
16663 * @return {Array} An array of HTMLElements
16665 getSelectedNodes : function(){
16666 return this.selections;
16670 * Get the indexes of the selected nodes.
16673 getSelectedIndexes : function(){
16674 var indexes = [], s = this.selections;
16675 for(var i = 0, len = s.length; i < len; i++){
16676 indexes.push(s[i].nodeIndex);
16682 * Clear all selections
16683 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16685 clearSelections : function(suppressEvent){
16686 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16687 this.cmp.elements = this.selections;
16688 this.cmp.removeClass(this.selectedClass);
16689 this.selections = [];
16690 if(!suppressEvent){
16691 this.fireEvent("selectionchange", this, this.selections);
16697 * Returns true if the passed node is selected
16698 * @param {HTMLElement/Number} node The node or node index
16699 * @return {Boolean}
16701 isSelected : function(node){
16702 var s = this.selections;
16706 node = this.getNode(node);
16707 return s.indexOf(node) !== -1;
16712 * @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
16713 * @param {Boolean} keepExisting (optional) true to keep existing selections
16714 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16716 select : function(nodeInfo, keepExisting, suppressEvent){
16717 if(nodeInfo instanceof Array){
16719 this.clearSelections(true);
16721 for(var i = 0, len = nodeInfo.length; i < len; i++){
16722 this.select(nodeInfo[i], true, true);
16726 var node = this.getNode(nodeInfo);
16727 if(!node || this.isSelected(node)){
16728 return; // already selected.
16731 this.clearSelections(true);
16734 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16735 Roo.fly(node).addClass(this.selectedClass);
16736 this.selections.push(node);
16737 if(!suppressEvent){
16738 this.fireEvent("selectionchange", this, this.selections);
16746 * @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
16747 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16748 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16750 unselect : function(nodeInfo, keepExisting, suppressEvent)
16752 if(nodeInfo instanceof Array){
16753 Roo.each(this.selections, function(s) {
16754 this.unselect(s, nodeInfo);
16758 var node = this.getNode(nodeInfo);
16759 if(!node || !this.isSelected(node)){
16760 //Roo.log("not selected");
16761 return; // not selected.
16765 Roo.each(this.selections, function(s) {
16767 Roo.fly(node).removeClass(this.selectedClass);
16774 this.selections= ns;
16775 this.fireEvent("selectionchange", this, this.selections);
16779 * Gets a template node.
16780 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16781 * @return {HTMLElement} The node or null if it wasn't found
16783 getNode : function(nodeInfo){
16784 if(typeof nodeInfo == "string"){
16785 return document.getElementById(nodeInfo);
16786 }else if(typeof nodeInfo == "number"){
16787 return this.nodes[nodeInfo];
16793 * Gets a range template nodes.
16794 * @param {Number} startIndex
16795 * @param {Number} endIndex
16796 * @return {Array} An array of nodes
16798 getNodes : function(start, end){
16799 var ns = this.nodes;
16800 start = start || 0;
16801 end = typeof end == "undefined" ? ns.length - 1 : end;
16804 for(var i = start; i <= end; i++){
16808 for(var i = start; i >= end; i--){
16816 * Finds the index of the passed node
16817 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16818 * @return {Number} The index of the node or -1
16820 indexOf : function(node){
16821 node = this.getNode(node);
16822 if(typeof node.nodeIndex == "number"){
16823 return node.nodeIndex;
16825 var ns = this.nodes;
16826 for(var i = 0, len = ns.length; i < len; i++){
16837 * based on jquery fullcalendar
16841 Roo.bootstrap = Roo.bootstrap || {};
16843 * @class Roo.bootstrap.Calendar
16844 * @extends Roo.bootstrap.Component
16845 * Bootstrap Calendar class
16846 * @cfg {Boolean} loadMask (true|false) default false
16847 * @cfg {Object} header generate the user specific header of the calendar, default false
16850 * Create a new Container
16851 * @param {Object} config The config object
16856 Roo.bootstrap.Calendar = function(config){
16857 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16861 * Fires when a date is selected
16862 * @param {DatePicker} this
16863 * @param {Date} date The selected date
16867 * @event monthchange
16868 * Fires when the displayed month changes
16869 * @param {DatePicker} this
16870 * @param {Date} date The selected month
16872 'monthchange': true,
16874 * @event evententer
16875 * Fires when mouse over an event
16876 * @param {Calendar} this
16877 * @param {event} Event
16879 'evententer': true,
16881 * @event eventleave
16882 * Fires when the mouse leaves an
16883 * @param {Calendar} this
16886 'eventleave': true,
16888 * @event eventclick
16889 * Fires when the mouse click an
16890 * @param {Calendar} this
16899 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16902 * @cfg {Number} startDay
16903 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16911 getAutoCreate : function(){
16914 var fc_button = function(name, corner, style, content ) {
16915 return Roo.apply({},{
16917 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16919 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16922 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16933 style : 'width:100%',
16940 cls : 'fc-header-left',
16942 fc_button('prev', 'left', 'arrow', '‹' ),
16943 fc_button('next', 'right', 'arrow', '›' ),
16944 { tag: 'span', cls: 'fc-header-space' },
16945 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16953 cls : 'fc-header-center',
16957 cls: 'fc-header-title',
16960 html : 'month / year'
16968 cls : 'fc-header-right',
16970 /* fc_button('month', 'left', '', 'month' ),
16971 fc_button('week', '', '', 'week' ),
16972 fc_button('day', 'right', '', 'day' )
16984 header = this.header;
16987 var cal_heads = function() {
16989 // fixme - handle this.
16991 for (var i =0; i < Date.dayNames.length; i++) {
16992 var d = Date.dayNames[i];
16995 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16996 html : d.substring(0,3)
17000 ret[0].cls += ' fc-first';
17001 ret[6].cls += ' fc-last';
17004 var cal_cell = function(n) {
17007 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17012 cls: 'fc-day-number',
17016 cls: 'fc-day-content',
17020 style: 'position: relative;' // height: 17px;
17032 var cal_rows = function() {
17035 for (var r = 0; r < 6; r++) {
17042 for (var i =0; i < Date.dayNames.length; i++) {
17043 var d = Date.dayNames[i];
17044 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17047 row.cn[0].cls+=' fc-first';
17048 row.cn[0].cn[0].style = 'min-height:90px';
17049 row.cn[6].cls+=' fc-last';
17053 ret[0].cls += ' fc-first';
17054 ret[4].cls += ' fc-prev-last';
17055 ret[5].cls += ' fc-last';
17062 cls: 'fc-border-separate',
17063 style : 'width:100%',
17071 cls : 'fc-first fc-last',
17089 cls : 'fc-content',
17090 style : "position: relative;",
17093 cls : 'fc-view fc-view-month fc-grid',
17094 style : 'position: relative',
17095 unselectable : 'on',
17098 cls : 'fc-event-container',
17099 style : 'position:absolute;z-index:8;top:0;left:0;'
17117 initEvents : function()
17120 throw "can not find store for calendar";
17126 style: "text-align:center",
17130 style: "background-color:white;width:50%;margin:250 auto",
17134 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17145 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17147 var size = this.el.select('.fc-content', true).first().getSize();
17148 this.maskEl.setSize(size.width, size.height);
17149 this.maskEl.enableDisplayMode("block");
17150 if(!this.loadMask){
17151 this.maskEl.hide();
17154 this.store = Roo.factory(this.store, Roo.data);
17155 this.store.on('load', this.onLoad, this);
17156 this.store.on('beforeload', this.onBeforeLoad, this);
17160 this.cells = this.el.select('.fc-day',true);
17161 //Roo.log(this.cells);
17162 this.textNodes = this.el.query('.fc-day-number');
17163 this.cells.addClassOnOver('fc-state-hover');
17165 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17166 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17167 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17168 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17170 this.on('monthchange', this.onMonthChange, this);
17172 this.update(new Date().clearTime());
17175 resize : function() {
17176 var sz = this.el.getSize();
17178 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17179 this.el.select('.fc-day-content div',true).setHeight(34);
17184 showPrevMonth : function(e){
17185 this.update(this.activeDate.add("mo", -1));
17187 showToday : function(e){
17188 this.update(new Date().clearTime());
17191 showNextMonth : function(e){
17192 this.update(this.activeDate.add("mo", 1));
17196 showPrevYear : function(){
17197 this.update(this.activeDate.add("y", -1));
17201 showNextYear : function(){
17202 this.update(this.activeDate.add("y", 1));
17207 update : function(date)
17209 var vd = this.activeDate;
17210 this.activeDate = date;
17211 // if(vd && this.el){
17212 // var t = date.getTime();
17213 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17214 // Roo.log('using add remove');
17216 // this.fireEvent('monthchange', this, date);
17218 // this.cells.removeClass("fc-state-highlight");
17219 // this.cells.each(function(c){
17220 // if(c.dateValue == t){
17221 // c.addClass("fc-state-highlight");
17222 // setTimeout(function(){
17223 // try{c.dom.firstChild.focus();}catch(e){}
17233 var days = date.getDaysInMonth();
17235 var firstOfMonth = date.getFirstDateOfMonth();
17236 var startingPos = firstOfMonth.getDay()-this.startDay;
17238 if(startingPos < this.startDay){
17242 var pm = date.add(Date.MONTH, -1);
17243 var prevStart = pm.getDaysInMonth()-startingPos;
17245 this.cells = this.el.select('.fc-day',true);
17246 this.textNodes = this.el.query('.fc-day-number');
17247 this.cells.addClassOnOver('fc-state-hover');
17249 var cells = this.cells.elements;
17250 var textEls = this.textNodes;
17252 Roo.each(cells, function(cell){
17253 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17256 days += startingPos;
17258 // convert everything to numbers so it's fast
17259 var day = 86400000;
17260 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17263 //Roo.log(prevStart);
17265 var today = new Date().clearTime().getTime();
17266 var sel = date.clearTime().getTime();
17267 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17268 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17269 var ddMatch = this.disabledDatesRE;
17270 var ddText = this.disabledDatesText;
17271 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17272 var ddaysText = this.disabledDaysText;
17273 var format = this.format;
17275 var setCellClass = function(cal, cell){
17279 //Roo.log('set Cell Class');
17281 var t = d.getTime();
17285 cell.dateValue = t;
17287 cell.className += " fc-today";
17288 cell.className += " fc-state-highlight";
17289 cell.title = cal.todayText;
17292 // disable highlight in other month..
17293 //cell.className += " fc-state-highlight";
17298 cell.className = " fc-state-disabled";
17299 cell.title = cal.minText;
17303 cell.className = " fc-state-disabled";
17304 cell.title = cal.maxText;
17308 if(ddays.indexOf(d.getDay()) != -1){
17309 cell.title = ddaysText;
17310 cell.className = " fc-state-disabled";
17313 if(ddMatch && format){
17314 var fvalue = d.dateFormat(format);
17315 if(ddMatch.test(fvalue)){
17316 cell.title = ddText.replace("%0", fvalue);
17317 cell.className = " fc-state-disabled";
17321 if (!cell.initialClassName) {
17322 cell.initialClassName = cell.dom.className;
17325 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17330 for(; i < startingPos; i++) {
17331 textEls[i].innerHTML = (++prevStart);
17332 d.setDate(d.getDate()+1);
17334 cells[i].className = "fc-past fc-other-month";
17335 setCellClass(this, cells[i]);
17340 for(; i < days; i++){
17341 intDay = i - startingPos + 1;
17342 textEls[i].innerHTML = (intDay);
17343 d.setDate(d.getDate()+1);
17345 cells[i].className = ''; // "x-date-active";
17346 setCellClass(this, cells[i]);
17350 for(; i < 42; i++) {
17351 textEls[i].innerHTML = (++extraDays);
17352 d.setDate(d.getDate()+1);
17354 cells[i].className = "fc-future fc-other-month";
17355 setCellClass(this, cells[i]);
17358 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17360 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17362 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17363 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17365 if(totalRows != 6){
17366 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17367 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17370 this.fireEvent('monthchange', this, date);
17374 if(!this.internalRender){
17375 var main = this.el.dom.firstChild;
17376 var w = main.offsetWidth;
17377 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17378 Roo.fly(main).setWidth(w);
17379 this.internalRender = true;
17380 // opera does not respect the auto grow header center column
17381 // then, after it gets a width opera refuses to recalculate
17382 // without a second pass
17383 if(Roo.isOpera && !this.secondPass){
17384 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17385 this.secondPass = true;
17386 this.update.defer(10, this, [date]);
17393 findCell : function(dt) {
17394 dt = dt.clearTime().getTime();
17396 this.cells.each(function(c){
17397 //Roo.log("check " +c.dateValue + '?=' + dt);
17398 if(c.dateValue == dt){
17408 findCells : function(ev) {
17409 var s = ev.start.clone().clearTime().getTime();
17411 var e= ev.end.clone().clearTime().getTime();
17414 this.cells.each(function(c){
17415 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17417 if(c.dateValue > e){
17420 if(c.dateValue < s){
17429 // findBestRow: function(cells)
17433 // for (var i =0 ; i < cells.length;i++) {
17434 // ret = Math.max(cells[i].rows || 0,ret);
17441 addItem : function(ev)
17443 // look for vertical location slot in
17444 var cells = this.findCells(ev);
17446 // ev.row = this.findBestRow(cells);
17448 // work out the location.
17452 for(var i =0; i < cells.length; i++) {
17454 cells[i].row = cells[0].row;
17457 cells[i].row = cells[i].row + 1;
17467 if (crow.start.getY() == cells[i].getY()) {
17469 crow.end = cells[i];
17486 cells[0].events.push(ev);
17488 this.calevents.push(ev);
17491 clearEvents: function() {
17493 if(!this.calevents){
17497 Roo.each(this.cells.elements, function(c){
17503 Roo.each(this.calevents, function(e) {
17504 Roo.each(e.els, function(el) {
17505 el.un('mouseenter' ,this.onEventEnter, this);
17506 el.un('mouseleave' ,this.onEventLeave, this);
17511 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17517 renderEvents: function()
17521 this.cells.each(function(c) {
17530 if(c.row != c.events.length){
17531 r = 4 - (4 - (c.row - c.events.length));
17534 c.events = ev.slice(0, r);
17535 c.more = ev.slice(r);
17537 if(c.more.length && c.more.length == 1){
17538 c.events.push(c.more.pop());
17541 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17545 this.cells.each(function(c) {
17547 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17550 for (var e = 0; e < c.events.length; e++){
17551 var ev = c.events[e];
17552 var rows = ev.rows;
17554 for(var i = 0; i < rows.length; i++) {
17556 // how many rows should it span..
17559 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17560 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17562 unselectable : "on",
17565 cls: 'fc-event-inner',
17569 // cls: 'fc-event-time',
17570 // html : cells.length > 1 ? '' : ev.time
17574 cls: 'fc-event-title',
17575 html : String.format('{0}', ev.title)
17582 cls: 'ui-resizable-handle ui-resizable-e',
17583 html : '  '
17590 cfg.cls += ' fc-event-start';
17592 if ((i+1) == rows.length) {
17593 cfg.cls += ' fc-event-end';
17596 var ctr = _this.el.select('.fc-event-container',true).first();
17597 var cg = ctr.createChild(cfg);
17599 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17600 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17602 var r = (c.more.length) ? 1 : 0;
17603 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17604 cg.setWidth(ebox.right - sbox.x -2);
17606 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17607 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17608 cg.on('click', _this.onEventClick, _this, ev);
17619 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17620 style : 'position: absolute',
17621 unselectable : "on",
17624 cls: 'fc-event-inner',
17628 cls: 'fc-event-title',
17636 cls: 'ui-resizable-handle ui-resizable-e',
17637 html : '  '
17643 var ctr = _this.el.select('.fc-event-container',true).first();
17644 var cg = ctr.createChild(cfg);
17646 var sbox = c.select('.fc-day-content',true).first().getBox();
17647 var ebox = c.select('.fc-day-content',true).first().getBox();
17649 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17650 cg.setWidth(ebox.right - sbox.x -2);
17652 cg.on('click', _this.onMoreEventClick, _this, c.more);
17662 onEventEnter: function (e, el,event,d) {
17663 this.fireEvent('evententer', this, el, event);
17666 onEventLeave: function (e, el,event,d) {
17667 this.fireEvent('eventleave', this, el, event);
17670 onEventClick: function (e, el,event,d) {
17671 this.fireEvent('eventclick', this, el, event);
17674 onMonthChange: function () {
17678 onMoreEventClick: function(e, el, more)
17682 this.calpopover.placement = 'right';
17683 this.calpopover.setTitle('More');
17685 this.calpopover.setContent('');
17687 var ctr = this.calpopover.el.select('.popover-content', true).first();
17689 Roo.each(more, function(m){
17691 cls : 'fc-event-hori fc-event-draggable',
17694 var cg = ctr.createChild(cfg);
17696 cg.on('click', _this.onEventClick, _this, m);
17699 this.calpopover.show(el);
17704 onLoad: function ()
17706 this.calevents = [];
17709 if(this.store.getCount() > 0){
17710 this.store.data.each(function(d){
17713 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17714 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17715 time : d.data.start_time,
17716 title : d.data.title,
17717 description : d.data.description,
17718 venue : d.data.venue
17723 this.renderEvents();
17725 if(this.calevents.length && this.loadMask){
17726 this.maskEl.hide();
17730 onBeforeLoad: function()
17732 this.clearEvents();
17734 this.maskEl.show();
17748 * @class Roo.bootstrap.Popover
17749 * @extends Roo.bootstrap.Component
17750 * Bootstrap Popover class
17751 * @cfg {String} html contents of the popover (or false to use children..)
17752 * @cfg {String} title of popover (or false to hide)
17753 * @cfg {String} placement how it is placed
17754 * @cfg {String} trigger click || hover (or false to trigger manually)
17755 * @cfg {String} over what (parent or false to trigger manually.)
17756 * @cfg {Number} delay - delay before showing
17759 * Create a new Popover
17760 * @param {Object} config The config object
17763 Roo.bootstrap.Popover = function(config){
17764 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17770 * After the popover show
17772 * @param {Roo.bootstrap.Popover} this
17777 * After the popover hide
17779 * @param {Roo.bootstrap.Popover} this
17785 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17787 title: 'Fill in a title',
17790 placement : 'right',
17791 trigger : 'hover', // hover
17797 can_build_overlaid : false,
17799 getChildContainer : function()
17801 return this.el.select('.popover-content',true).first();
17804 getAutoCreate : function(){
17807 cls : 'popover roo-dynamic',
17808 style: 'display:block',
17814 cls : 'popover-inner',
17818 cls: 'popover-title popover-header',
17822 cls : 'popover-content popover-body',
17833 setTitle: function(str)
17836 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17838 setContent: function(str)
17841 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17843 // as it get's added to the bottom of the page.
17844 onRender : function(ct, position)
17846 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17848 var cfg = Roo.apply({}, this.getAutoCreate());
17852 cfg.cls += ' ' + this.cls;
17855 cfg.style = this.style;
17857 //Roo.log("adding to ");
17858 this.el = Roo.get(document.body).createChild(cfg, position);
17859 // Roo.log(this.el);
17864 initEvents : function()
17866 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17867 this.el.enableDisplayMode('block');
17869 if (this.over === false) {
17872 if (this.triggers === false) {
17875 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17876 var triggers = this.trigger ? this.trigger.split(' ') : [];
17877 Roo.each(triggers, function(trigger) {
17879 if (trigger == 'click') {
17880 on_el.on('click', this.toggle, this);
17881 } else if (trigger != 'manual') {
17882 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17883 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17885 on_el.on(eventIn ,this.enter, this);
17886 on_el.on(eventOut, this.leave, this);
17897 toggle : function () {
17898 this.hoverState == 'in' ? this.leave() : this.enter();
17901 enter : function () {
17903 clearTimeout(this.timeout);
17905 this.hoverState = 'in';
17907 if (!this.delay || !this.delay.show) {
17912 this.timeout = setTimeout(function () {
17913 if (_t.hoverState == 'in') {
17916 }, this.delay.show)
17919 leave : function() {
17920 clearTimeout(this.timeout);
17922 this.hoverState = 'out';
17924 if (!this.delay || !this.delay.hide) {
17929 this.timeout = setTimeout(function () {
17930 if (_t.hoverState == 'out') {
17933 }, this.delay.hide)
17936 show : function (on_el)
17939 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17943 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17944 if (this.html !== false) {
17945 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17947 this.el.removeClass([
17948 'fade','top','bottom', 'left', 'right','in',
17949 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17951 if (!this.title.length) {
17952 this.el.select('.popover-title',true).hide();
17955 var placement = typeof this.placement == 'function' ?
17956 this.placement.call(this, this.el, on_el) :
17959 var autoToken = /\s?auto?\s?/i;
17960 var autoPlace = autoToken.test(placement);
17962 placement = placement.replace(autoToken, '') || 'top';
17966 //this.el.setXY([0,0]);
17968 this.el.dom.style.display='block';
17969 this.el.addClass(placement);
17971 //this.el.appendTo(on_el);
17973 var p = this.getPosition();
17974 var box = this.el.getBox();
17979 var align = Roo.bootstrap.Popover.alignment[placement];
17982 this.el.alignTo(on_el, align[0],align[1]);
17983 //var arrow = this.el.select('.arrow',true).first();
17984 //arrow.set(align[2],
17986 this.el.addClass('in');
17989 if (this.el.hasClass('fade')) {
17993 this.hoverState = 'in';
17995 this.fireEvent('show', this);
18000 this.el.setXY([0,0]);
18001 this.el.removeClass('in');
18003 this.hoverState = null;
18005 this.fireEvent('hide', this);
18010 Roo.bootstrap.Popover.alignment = {
18011 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18012 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18013 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18014 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18025 * @class Roo.bootstrap.Progress
18026 * @extends Roo.bootstrap.Component
18027 * Bootstrap Progress class
18028 * @cfg {Boolean} striped striped of the progress bar
18029 * @cfg {Boolean} active animated of the progress bar
18033 * Create a new Progress
18034 * @param {Object} config The config object
18037 Roo.bootstrap.Progress = function(config){
18038 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18041 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18046 getAutoCreate : function(){
18054 cfg.cls += ' progress-striped';
18058 cfg.cls += ' active';
18077 * @class Roo.bootstrap.ProgressBar
18078 * @extends Roo.bootstrap.Component
18079 * Bootstrap ProgressBar class
18080 * @cfg {Number} aria_valuenow aria-value now
18081 * @cfg {Number} aria_valuemin aria-value min
18082 * @cfg {Number} aria_valuemax aria-value max
18083 * @cfg {String} label label for the progress bar
18084 * @cfg {String} panel (success | info | warning | danger )
18085 * @cfg {String} role role of the progress bar
18086 * @cfg {String} sr_only text
18090 * Create a new ProgressBar
18091 * @param {Object} config The config object
18094 Roo.bootstrap.ProgressBar = function(config){
18095 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18098 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18102 aria_valuemax : 100,
18108 getAutoCreate : function()
18113 cls: 'progress-bar',
18114 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18126 cfg.role = this.role;
18129 if(this.aria_valuenow){
18130 cfg['aria-valuenow'] = this.aria_valuenow;
18133 if(this.aria_valuemin){
18134 cfg['aria-valuemin'] = this.aria_valuemin;
18137 if(this.aria_valuemax){
18138 cfg['aria-valuemax'] = this.aria_valuemax;
18141 if(this.label && !this.sr_only){
18142 cfg.html = this.label;
18146 cfg.cls += ' progress-bar-' + this.panel;
18152 update : function(aria_valuenow)
18154 this.aria_valuenow = aria_valuenow;
18156 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18171 * @class Roo.bootstrap.TabGroup
18172 * @extends Roo.bootstrap.Column
18173 * Bootstrap Column class
18174 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18175 * @cfg {Boolean} carousel true to make the group behave like a carousel
18176 * @cfg {Boolean} bullets show bullets for the panels
18177 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18178 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18179 * @cfg {Boolean} showarrow (true|false) show arrow default true
18182 * Create a new TabGroup
18183 * @param {Object} config The config object
18186 Roo.bootstrap.TabGroup = function(config){
18187 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18189 this.navId = Roo.id();
18192 Roo.bootstrap.TabGroup.register(this);
18196 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18199 transition : false,
18204 slideOnTouch : false,
18207 getAutoCreate : function()
18209 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18211 cfg.cls += ' tab-content';
18213 if (this.carousel) {
18214 cfg.cls += ' carousel slide';
18217 cls : 'carousel-inner',
18221 if(this.bullets && !Roo.isTouch){
18224 cls : 'carousel-bullets',
18228 if(this.bullets_cls){
18229 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18236 cfg.cn[0].cn.push(bullets);
18239 if(this.showarrow){
18240 cfg.cn[0].cn.push({
18242 class : 'carousel-arrow',
18246 class : 'carousel-prev',
18250 class : 'fa fa-chevron-left'
18256 class : 'carousel-next',
18260 class : 'fa fa-chevron-right'
18273 initEvents: function()
18275 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18276 // this.el.on("touchstart", this.onTouchStart, this);
18279 if(this.autoslide){
18282 this.slideFn = window.setInterval(function() {
18283 _this.showPanelNext();
18287 if(this.showarrow){
18288 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18289 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18295 // onTouchStart : function(e, el, o)
18297 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18301 // this.showPanelNext();
18305 getChildContainer : function()
18307 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18311 * register a Navigation item
18312 * @param {Roo.bootstrap.NavItem} the navitem to add
18314 register : function(item)
18316 this.tabs.push( item);
18317 item.navId = this.navId; // not really needed..
18322 getActivePanel : function()
18325 Roo.each(this.tabs, function(t) {
18335 getPanelByName : function(n)
18338 Roo.each(this.tabs, function(t) {
18339 if (t.tabId == n) {
18347 indexOfPanel : function(p)
18350 Roo.each(this.tabs, function(t,i) {
18351 if (t.tabId == p.tabId) {
18360 * show a specific panel
18361 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18362 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18364 showPanel : function (pan)
18366 if(this.transition || typeof(pan) == 'undefined'){
18367 Roo.log("waiting for the transitionend");
18371 if (typeof(pan) == 'number') {
18372 pan = this.tabs[pan];
18375 if (typeof(pan) == 'string') {
18376 pan = this.getPanelByName(pan);
18379 var cur = this.getActivePanel();
18382 Roo.log('pan or acitve pan is undefined');
18386 if (pan.tabId == this.getActivePanel().tabId) {
18390 if (false === cur.fireEvent('beforedeactivate')) {
18394 if(this.bullets > 0 && !Roo.isTouch){
18395 this.setActiveBullet(this.indexOfPanel(pan));
18398 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18400 //class="carousel-item carousel-item-next carousel-item-left"
18402 this.transition = true;
18403 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18404 var lr = dir == 'next' ? 'left' : 'right';
18405 pan.el.addClass(dir); // or prev
18406 pan.el.addClass('carousel-item-' + dir); // or prev
18407 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18408 cur.el.addClass(lr); // or right
18409 pan.el.addClass(lr);
18410 cur.el.addClass('carousel-item-' +lr); // or right
18411 pan.el.addClass('carousel-item-' +lr);
18415 cur.el.on('transitionend', function() {
18416 Roo.log("trans end?");
18418 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18419 pan.setActive(true);
18421 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18422 cur.setActive(false);
18424 _this.transition = false;
18426 }, this, { single: true } );
18431 cur.setActive(false);
18432 pan.setActive(true);
18437 showPanelNext : function()
18439 var i = this.indexOfPanel(this.getActivePanel());
18441 if (i >= this.tabs.length - 1 && !this.autoslide) {
18445 if (i >= this.tabs.length - 1 && this.autoslide) {
18449 this.showPanel(this.tabs[i+1]);
18452 showPanelPrev : function()
18454 var i = this.indexOfPanel(this.getActivePanel());
18456 if (i < 1 && !this.autoslide) {
18460 if (i < 1 && this.autoslide) {
18461 i = this.tabs.length;
18464 this.showPanel(this.tabs[i-1]);
18468 addBullet: function()
18470 if(!this.bullets || Roo.isTouch){
18473 var ctr = this.el.select('.carousel-bullets',true).first();
18474 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18475 var bullet = ctr.createChild({
18476 cls : 'bullet bullet-' + i
18477 },ctr.dom.lastChild);
18482 bullet.on('click', (function(e, el, o, ii, t){
18484 e.preventDefault();
18486 this.showPanel(ii);
18488 if(this.autoslide && this.slideFn){
18489 clearInterval(this.slideFn);
18490 this.slideFn = window.setInterval(function() {
18491 _this.showPanelNext();
18495 }).createDelegate(this, [i, bullet], true));
18500 setActiveBullet : function(i)
18506 Roo.each(this.el.select('.bullet', true).elements, function(el){
18507 el.removeClass('selected');
18510 var bullet = this.el.select('.bullet-' + i, true).first();
18516 bullet.addClass('selected');
18527 Roo.apply(Roo.bootstrap.TabGroup, {
18531 * register a Navigation Group
18532 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18534 register : function(navgrp)
18536 this.groups[navgrp.navId] = navgrp;
18540 * fetch a Navigation Group based on the navigation ID
18541 * if one does not exist , it will get created.
18542 * @param {string} the navgroup to add
18543 * @returns {Roo.bootstrap.NavGroup} the navgroup
18545 get: function(navId) {
18546 if (typeof(this.groups[navId]) == 'undefined') {
18547 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18549 return this.groups[navId] ;
18564 * @class Roo.bootstrap.TabPanel
18565 * @extends Roo.bootstrap.Component
18566 * Bootstrap TabPanel class
18567 * @cfg {Boolean} active panel active
18568 * @cfg {String} html panel content
18569 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18570 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18571 * @cfg {String} href click to link..
18575 * Create a new TabPanel
18576 * @param {Object} config The config object
18579 Roo.bootstrap.TabPanel = function(config){
18580 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18584 * Fires when the active status changes
18585 * @param {Roo.bootstrap.TabPanel} this
18586 * @param {Boolean} state the new state
18591 * @event beforedeactivate
18592 * Fires before a tab is de-activated - can be used to do validation on a form.
18593 * @param {Roo.bootstrap.TabPanel} this
18594 * @return {Boolean} false if there is an error
18597 'beforedeactivate': true
18600 this.tabId = this.tabId || Roo.id();
18604 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18612 getAutoCreate : function(){
18617 // item is needed for carousel - not sure if it has any effect otherwise
18618 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18619 html: this.html || ''
18623 cfg.cls += ' active';
18627 cfg.tabId = this.tabId;
18635 initEvents: function()
18637 var p = this.parent();
18639 this.navId = this.navId || p.navId;
18641 if (typeof(this.navId) != 'undefined') {
18642 // not really needed.. but just in case.. parent should be a NavGroup.
18643 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18647 var i = tg.tabs.length - 1;
18649 if(this.active && tg.bullets > 0 && i < tg.bullets){
18650 tg.setActiveBullet(i);
18654 this.el.on('click', this.onClick, this);
18657 this.el.on("touchstart", this.onTouchStart, this);
18658 this.el.on("touchmove", this.onTouchMove, this);
18659 this.el.on("touchend", this.onTouchEnd, this);
18664 onRender : function(ct, position)
18666 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18669 setActive : function(state)
18671 Roo.log("panel - set active " + this.tabId + "=" + state);
18673 this.active = state;
18675 this.el.removeClass('active');
18677 } else if (!this.el.hasClass('active')) {
18678 this.el.addClass('active');
18681 this.fireEvent('changed', this, state);
18684 onClick : function(e)
18686 e.preventDefault();
18688 if(!this.href.length){
18692 window.location.href = this.href;
18701 onTouchStart : function(e)
18703 this.swiping = false;
18705 this.startX = e.browserEvent.touches[0].clientX;
18706 this.startY = e.browserEvent.touches[0].clientY;
18709 onTouchMove : function(e)
18711 this.swiping = true;
18713 this.endX = e.browserEvent.touches[0].clientX;
18714 this.endY = e.browserEvent.touches[0].clientY;
18717 onTouchEnd : function(e)
18724 var tabGroup = this.parent();
18726 if(this.endX > this.startX){ // swiping right
18727 tabGroup.showPanelPrev();
18731 if(this.startX > this.endX){ // swiping left
18732 tabGroup.showPanelNext();
18751 * @class Roo.bootstrap.DateField
18752 * @extends Roo.bootstrap.Input
18753 * Bootstrap DateField class
18754 * @cfg {Number} weekStart default 0
18755 * @cfg {String} viewMode default empty, (months|years)
18756 * @cfg {String} minViewMode default empty, (months|years)
18757 * @cfg {Number} startDate default -Infinity
18758 * @cfg {Number} endDate default Infinity
18759 * @cfg {Boolean} todayHighlight default false
18760 * @cfg {Boolean} todayBtn default false
18761 * @cfg {Boolean} calendarWeeks default false
18762 * @cfg {Object} daysOfWeekDisabled default empty
18763 * @cfg {Boolean} singleMode default false (true | false)
18765 * @cfg {Boolean} keyboardNavigation default true
18766 * @cfg {String} language default en
18769 * Create a new DateField
18770 * @param {Object} config The config object
18773 Roo.bootstrap.DateField = function(config){
18774 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18778 * Fires when this field show.
18779 * @param {Roo.bootstrap.DateField} this
18780 * @param {Mixed} date The date value
18785 * Fires when this field hide.
18786 * @param {Roo.bootstrap.DateField} this
18787 * @param {Mixed} date The date value
18792 * Fires when select a date.
18793 * @param {Roo.bootstrap.DateField} this
18794 * @param {Mixed} date The date value
18798 * @event beforeselect
18799 * Fires when before select a date.
18800 * @param {Roo.bootstrap.DateField} this
18801 * @param {Mixed} date The date value
18803 beforeselect : true
18807 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18810 * @cfg {String} format
18811 * The default date format string which can be overriden for localization support. The format must be
18812 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18816 * @cfg {String} altFormats
18817 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18818 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18820 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18828 todayHighlight : false,
18834 keyboardNavigation: true,
18836 calendarWeeks: false,
18838 startDate: -Infinity,
18842 daysOfWeekDisabled: [],
18846 singleMode : false,
18848 UTCDate: function()
18850 return new Date(Date.UTC.apply(Date, arguments));
18853 UTCToday: function()
18855 var today = new Date();
18856 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18859 getDate: function() {
18860 var d = this.getUTCDate();
18861 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18864 getUTCDate: function() {
18868 setDate: function(d) {
18869 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18872 setUTCDate: function(d) {
18874 this.setValue(this.formatDate(this.date));
18877 onRender: function(ct, position)
18880 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18882 this.language = this.language || 'en';
18883 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18884 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18886 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18887 this.format = this.format || 'm/d/y';
18888 this.isInline = false;
18889 this.isInput = true;
18890 this.component = this.el.select('.add-on', true).first() || false;
18891 this.component = (this.component && this.component.length === 0) ? false : this.component;
18892 this.hasInput = this.component && this.inputEl().length;
18894 if (typeof(this.minViewMode === 'string')) {
18895 switch (this.minViewMode) {
18897 this.minViewMode = 1;
18900 this.minViewMode = 2;
18903 this.minViewMode = 0;
18908 if (typeof(this.viewMode === 'string')) {
18909 switch (this.viewMode) {
18922 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18924 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18926 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18928 this.picker().on('mousedown', this.onMousedown, this);
18929 this.picker().on('click', this.onClick, this);
18931 this.picker().addClass('datepicker-dropdown');
18933 this.startViewMode = this.viewMode;
18935 if(this.singleMode){
18936 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18937 v.setVisibilityMode(Roo.Element.DISPLAY);
18941 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18942 v.setStyle('width', '189px');
18946 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18947 if(!this.calendarWeeks){
18952 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18953 v.attr('colspan', function(i, val){
18954 return parseInt(val) + 1;
18959 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18961 this.setStartDate(this.startDate);
18962 this.setEndDate(this.endDate);
18964 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18971 if(this.isInline) {
18976 picker : function()
18978 return this.pickerEl;
18979 // return this.el.select('.datepicker', true).first();
18982 fillDow: function()
18984 var dowCnt = this.weekStart;
18993 if(this.calendarWeeks){
19001 while (dowCnt < this.weekStart + 7) {
19005 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19009 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19012 fillMonths: function()
19015 var months = this.picker().select('>.datepicker-months td', true).first();
19017 months.dom.innerHTML = '';
19023 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19026 months.createChild(month);
19033 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;
19035 if (this.date < this.startDate) {
19036 this.viewDate = new Date(this.startDate);
19037 } else if (this.date > this.endDate) {
19038 this.viewDate = new Date(this.endDate);
19040 this.viewDate = new Date(this.date);
19048 var d = new Date(this.viewDate),
19049 year = d.getUTCFullYear(),
19050 month = d.getUTCMonth(),
19051 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19052 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19053 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19054 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19055 currentDate = this.date && this.date.valueOf(),
19056 today = this.UTCToday();
19058 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19060 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19062 // this.picker.select('>tfoot th.today').
19063 // .text(dates[this.language].today)
19064 // .toggle(this.todayBtn !== false);
19066 this.updateNavArrows();
19069 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19071 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19073 prevMonth.setUTCDate(day);
19075 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19077 var nextMonth = new Date(prevMonth);
19079 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19081 nextMonth = nextMonth.valueOf();
19083 var fillMonths = false;
19085 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19087 while(prevMonth.valueOf() <= nextMonth) {
19090 if (prevMonth.getUTCDay() === this.weekStart) {
19092 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19100 if(this.calendarWeeks){
19101 // ISO 8601: First week contains first thursday.
19102 // ISO also states week starts on Monday, but we can be more abstract here.
19104 // Start of current week: based on weekstart/current date
19105 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19106 // Thursday of this week
19107 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19108 // First Thursday of year, year from thursday
19109 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19110 // Calendar week: ms between thursdays, div ms per day, div 7 days
19111 calWeek = (th - yth) / 864e5 / 7 + 1;
19113 fillMonths.cn.push({
19121 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19123 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19126 if (this.todayHighlight &&
19127 prevMonth.getUTCFullYear() == today.getFullYear() &&
19128 prevMonth.getUTCMonth() == today.getMonth() &&
19129 prevMonth.getUTCDate() == today.getDate()) {
19130 clsName += ' today';
19133 if (currentDate && prevMonth.valueOf() === currentDate) {
19134 clsName += ' active';
19137 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19138 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19139 clsName += ' disabled';
19142 fillMonths.cn.push({
19144 cls: 'day ' + clsName,
19145 html: prevMonth.getDate()
19148 prevMonth.setDate(prevMonth.getDate()+1);
19151 var currentYear = this.date && this.date.getUTCFullYear();
19152 var currentMonth = this.date && this.date.getUTCMonth();
19154 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19156 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19157 v.removeClass('active');
19159 if(currentYear === year && k === currentMonth){
19160 v.addClass('active');
19163 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19164 v.addClass('disabled');
19170 year = parseInt(year/10, 10) * 10;
19172 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19174 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19177 for (var i = -1; i < 11; i++) {
19178 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19180 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19188 showMode: function(dir)
19191 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19194 Roo.each(this.picker().select('>div',true).elements, function(v){
19195 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19198 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19203 if(this.isInline) {
19207 this.picker().removeClass(['bottom', 'top']);
19209 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19211 * place to the top of element!
19215 this.picker().addClass('top');
19216 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19221 this.picker().addClass('bottom');
19223 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19226 parseDate : function(value)
19228 if(!value || value instanceof Date){
19231 var v = Date.parseDate(value, this.format);
19232 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19233 v = Date.parseDate(value, 'Y-m-d');
19235 if(!v && this.altFormats){
19236 if(!this.altFormatsArray){
19237 this.altFormatsArray = this.altFormats.split("|");
19239 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19240 v = Date.parseDate(value, this.altFormatsArray[i]);
19246 formatDate : function(date, fmt)
19248 return (!date || !(date instanceof Date)) ?
19249 date : date.dateFormat(fmt || this.format);
19252 onFocus : function()
19254 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19258 onBlur : function()
19260 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19262 var d = this.inputEl().getValue();
19269 showPopup : function()
19271 this.picker().show();
19275 this.fireEvent('showpopup', this, this.date);
19278 hidePopup : function()
19280 if(this.isInline) {
19283 this.picker().hide();
19284 this.viewMode = this.startViewMode;
19287 this.fireEvent('hidepopup', this, this.date);
19291 onMousedown: function(e)
19293 e.stopPropagation();
19294 e.preventDefault();
19299 Roo.bootstrap.DateField.superclass.keyup.call(this);
19303 setValue: function(v)
19305 if(this.fireEvent('beforeselect', this, v) !== false){
19306 var d = new Date(this.parseDate(v) ).clearTime();
19308 if(isNaN(d.getTime())){
19309 this.date = this.viewDate = '';
19310 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19314 v = this.formatDate(d);
19316 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19318 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19322 this.fireEvent('select', this, this.date);
19326 getValue: function()
19328 return this.formatDate(this.date);
19331 fireKey: function(e)
19333 if (!this.picker().isVisible()){
19334 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19340 var dateChanged = false,
19342 newDate, newViewDate;
19347 e.preventDefault();
19351 if (!this.keyboardNavigation) {
19354 dir = e.keyCode == 37 ? -1 : 1;
19357 newDate = this.moveYear(this.date, dir);
19358 newViewDate = this.moveYear(this.viewDate, dir);
19359 } else if (e.shiftKey){
19360 newDate = this.moveMonth(this.date, dir);
19361 newViewDate = this.moveMonth(this.viewDate, dir);
19363 newDate = new Date(this.date);
19364 newDate.setUTCDate(this.date.getUTCDate() + dir);
19365 newViewDate = new Date(this.viewDate);
19366 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19368 if (this.dateWithinRange(newDate)){
19369 this.date = newDate;
19370 this.viewDate = newViewDate;
19371 this.setValue(this.formatDate(this.date));
19373 e.preventDefault();
19374 dateChanged = true;
19379 if (!this.keyboardNavigation) {
19382 dir = e.keyCode == 38 ? -1 : 1;
19384 newDate = this.moveYear(this.date, dir);
19385 newViewDate = this.moveYear(this.viewDate, dir);
19386 } else if (e.shiftKey){
19387 newDate = this.moveMonth(this.date, dir);
19388 newViewDate = this.moveMonth(this.viewDate, dir);
19390 newDate = new Date(this.date);
19391 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19392 newViewDate = new Date(this.viewDate);
19393 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19395 if (this.dateWithinRange(newDate)){
19396 this.date = newDate;
19397 this.viewDate = newViewDate;
19398 this.setValue(this.formatDate(this.date));
19400 e.preventDefault();
19401 dateChanged = true;
19405 this.setValue(this.formatDate(this.date));
19407 e.preventDefault();
19410 this.setValue(this.formatDate(this.date));
19424 onClick: function(e)
19426 e.stopPropagation();
19427 e.preventDefault();
19429 var target = e.getTarget();
19431 if(target.nodeName.toLowerCase() === 'i'){
19432 target = Roo.get(target).dom.parentNode;
19435 var nodeName = target.nodeName;
19436 var className = target.className;
19437 var html = target.innerHTML;
19438 //Roo.log(nodeName);
19440 switch(nodeName.toLowerCase()) {
19442 switch(className) {
19448 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19449 switch(this.viewMode){
19451 this.viewDate = this.moveMonth(this.viewDate, dir);
19455 this.viewDate = this.moveYear(this.viewDate, dir);
19461 var date = new Date();
19462 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19464 this.setValue(this.formatDate(this.date));
19471 if (className.indexOf('disabled') < 0) {
19472 this.viewDate.setUTCDate(1);
19473 if (className.indexOf('month') > -1) {
19474 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19476 var year = parseInt(html, 10) || 0;
19477 this.viewDate.setUTCFullYear(year);
19481 if(this.singleMode){
19482 this.setValue(this.formatDate(this.viewDate));
19493 //Roo.log(className);
19494 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19495 var day = parseInt(html, 10) || 1;
19496 var year = this.viewDate.getUTCFullYear(),
19497 month = this.viewDate.getUTCMonth();
19499 if (className.indexOf('old') > -1) {
19506 } else if (className.indexOf('new') > -1) {
19514 //Roo.log([year,month,day]);
19515 this.date = this.UTCDate(year, month, day,0,0,0,0);
19516 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19518 //Roo.log(this.formatDate(this.date));
19519 this.setValue(this.formatDate(this.date));
19526 setStartDate: function(startDate)
19528 this.startDate = startDate || -Infinity;
19529 if (this.startDate !== -Infinity) {
19530 this.startDate = this.parseDate(this.startDate);
19533 this.updateNavArrows();
19536 setEndDate: function(endDate)
19538 this.endDate = endDate || Infinity;
19539 if (this.endDate !== Infinity) {
19540 this.endDate = this.parseDate(this.endDate);
19543 this.updateNavArrows();
19546 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19548 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19549 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19550 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19552 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19553 return parseInt(d, 10);
19556 this.updateNavArrows();
19559 updateNavArrows: function()
19561 if(this.singleMode){
19565 var d = new Date(this.viewDate),
19566 year = d.getUTCFullYear(),
19567 month = d.getUTCMonth();
19569 Roo.each(this.picker().select('.prev', true).elements, function(v){
19571 switch (this.viewMode) {
19574 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19580 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19587 Roo.each(this.picker().select('.next', true).elements, function(v){
19589 switch (this.viewMode) {
19592 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19598 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19606 moveMonth: function(date, dir)
19611 var new_date = new Date(date.valueOf()),
19612 day = new_date.getUTCDate(),
19613 month = new_date.getUTCMonth(),
19614 mag = Math.abs(dir),
19616 dir = dir > 0 ? 1 : -1;
19619 // If going back one month, make sure month is not current month
19620 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19622 return new_date.getUTCMonth() == month;
19624 // If going forward one month, make sure month is as expected
19625 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19627 return new_date.getUTCMonth() != new_month;
19629 new_month = month + dir;
19630 new_date.setUTCMonth(new_month);
19631 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19632 if (new_month < 0 || new_month > 11) {
19633 new_month = (new_month + 12) % 12;
19636 // For magnitudes >1, move one month at a time...
19637 for (var i=0; i<mag; i++) {
19638 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19639 new_date = this.moveMonth(new_date, dir);
19641 // ...then reset the day, keeping it in the new month
19642 new_month = new_date.getUTCMonth();
19643 new_date.setUTCDate(day);
19645 return new_month != new_date.getUTCMonth();
19648 // Common date-resetting loop -- if date is beyond end of month, make it
19651 new_date.setUTCDate(--day);
19652 new_date.setUTCMonth(new_month);
19657 moveYear: function(date, dir)
19659 return this.moveMonth(date, dir*12);
19662 dateWithinRange: function(date)
19664 return date >= this.startDate && date <= this.endDate;
19670 this.picker().remove();
19673 validateValue : function(value)
19675 if(this.getVisibilityEl().hasClass('hidden')){
19679 if(value.length < 1) {
19680 if(this.allowBlank){
19686 if(value.length < this.minLength){
19689 if(value.length > this.maxLength){
19693 var vt = Roo.form.VTypes;
19694 if(!vt[this.vtype](value, this)){
19698 if(typeof this.validator == "function"){
19699 var msg = this.validator(value);
19705 if(this.regex && !this.regex.test(value)){
19709 if(typeof(this.parseDate(value)) == 'undefined'){
19713 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19717 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19727 this.date = this.viewDate = '';
19729 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19734 Roo.apply(Roo.bootstrap.DateField, {
19745 html: '<i class="fa fa-arrow-left"/>'
19755 html: '<i class="fa fa-arrow-right"/>'
19797 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19798 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19799 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19800 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19801 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19814 navFnc: 'FullYear',
19819 navFnc: 'FullYear',
19824 Roo.apply(Roo.bootstrap.DateField, {
19828 cls: 'datepicker dropdown-menu roo-dynamic',
19832 cls: 'datepicker-days',
19836 cls: 'table-condensed',
19838 Roo.bootstrap.DateField.head,
19842 Roo.bootstrap.DateField.footer
19849 cls: 'datepicker-months',
19853 cls: 'table-condensed',
19855 Roo.bootstrap.DateField.head,
19856 Roo.bootstrap.DateField.content,
19857 Roo.bootstrap.DateField.footer
19864 cls: 'datepicker-years',
19868 cls: 'table-condensed',
19870 Roo.bootstrap.DateField.head,
19871 Roo.bootstrap.DateField.content,
19872 Roo.bootstrap.DateField.footer
19891 * @class Roo.bootstrap.TimeField
19892 * @extends Roo.bootstrap.Input
19893 * Bootstrap DateField class
19897 * Create a new TimeField
19898 * @param {Object} config The config object
19901 Roo.bootstrap.TimeField = function(config){
19902 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19906 * Fires when this field show.
19907 * @param {Roo.bootstrap.DateField} thisthis
19908 * @param {Mixed} date The date value
19913 * Fires when this field hide.
19914 * @param {Roo.bootstrap.DateField} this
19915 * @param {Mixed} date The date value
19920 * Fires when select a date.
19921 * @param {Roo.bootstrap.DateField} this
19922 * @param {Mixed} date The date value
19928 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19931 * @cfg {String} format
19932 * The default time format string which can be overriden for localization support. The format must be
19933 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19937 onRender: function(ct, position)
19940 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19942 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19944 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19946 this.pop = this.picker().select('>.datepicker-time',true).first();
19947 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19949 this.picker().on('mousedown', this.onMousedown, this);
19950 this.picker().on('click', this.onClick, this);
19952 this.picker().addClass('datepicker-dropdown');
19957 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19958 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19959 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19960 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19961 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19962 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19966 fireKey: function(e){
19967 if (!this.picker().isVisible()){
19968 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19974 e.preventDefault();
19982 this.onTogglePeriod();
19985 this.onIncrementMinutes();
19988 this.onDecrementMinutes();
19997 onClick: function(e) {
19998 e.stopPropagation();
19999 e.preventDefault();
20002 picker : function()
20004 return this.el.select('.datepicker', true).first();
20007 fillTime: function()
20009 var time = this.pop.select('tbody', true).first();
20011 time.dom.innerHTML = '';
20026 cls: 'hours-up glyphicon glyphicon-chevron-up'
20046 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20067 cls: 'timepicker-hour',
20082 cls: 'timepicker-minute',
20097 cls: 'btn btn-primary period',
20119 cls: 'hours-down glyphicon glyphicon-chevron-down'
20139 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20157 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20164 var hours = this.time.getHours();
20165 var minutes = this.time.getMinutes();
20178 hours = hours - 12;
20182 hours = '0' + hours;
20186 minutes = '0' + minutes;
20189 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20190 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20191 this.pop.select('button', true).first().dom.innerHTML = period;
20197 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20199 var cls = ['bottom'];
20201 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20208 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20213 this.picker().addClass(cls.join('-'));
20217 Roo.each(cls, function(c){
20219 _this.picker().setTop(_this.inputEl().getHeight());
20223 _this.picker().setTop(0 - _this.picker().getHeight());
20228 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20232 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20239 onFocus : function()
20241 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20245 onBlur : function()
20247 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20253 this.picker().show();
20258 this.fireEvent('show', this, this.date);
20263 this.picker().hide();
20266 this.fireEvent('hide', this, this.date);
20269 setTime : function()
20272 this.setValue(this.time.format(this.format));
20274 this.fireEvent('select', this, this.date);
20279 onMousedown: function(e){
20280 e.stopPropagation();
20281 e.preventDefault();
20284 onIncrementHours: function()
20286 Roo.log('onIncrementHours');
20287 this.time = this.time.add(Date.HOUR, 1);
20292 onDecrementHours: function()
20294 Roo.log('onDecrementHours');
20295 this.time = this.time.add(Date.HOUR, -1);
20299 onIncrementMinutes: function()
20301 Roo.log('onIncrementMinutes');
20302 this.time = this.time.add(Date.MINUTE, 1);
20306 onDecrementMinutes: function()
20308 Roo.log('onDecrementMinutes');
20309 this.time = this.time.add(Date.MINUTE, -1);
20313 onTogglePeriod: function()
20315 Roo.log('onTogglePeriod');
20316 this.time = this.time.add(Date.HOUR, 12);
20323 Roo.apply(Roo.bootstrap.TimeField, {
20353 cls: 'btn btn-info ok',
20365 Roo.apply(Roo.bootstrap.TimeField, {
20369 cls: 'datepicker dropdown-menu',
20373 cls: 'datepicker-time',
20377 cls: 'table-condensed',
20379 Roo.bootstrap.TimeField.content,
20380 Roo.bootstrap.TimeField.footer
20399 * @class Roo.bootstrap.MonthField
20400 * @extends Roo.bootstrap.Input
20401 * Bootstrap MonthField class
20403 * @cfg {String} language default en
20406 * Create a new MonthField
20407 * @param {Object} config The config object
20410 Roo.bootstrap.MonthField = function(config){
20411 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20416 * Fires when this field show.
20417 * @param {Roo.bootstrap.MonthField} this
20418 * @param {Mixed} date The date value
20423 * Fires when this field hide.
20424 * @param {Roo.bootstrap.MonthField} this
20425 * @param {Mixed} date The date value
20430 * Fires when select a date.
20431 * @param {Roo.bootstrap.MonthField} this
20432 * @param {String} oldvalue The old value
20433 * @param {String} newvalue The new value
20439 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20441 onRender: function(ct, position)
20444 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20446 this.language = this.language || 'en';
20447 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20448 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20450 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20451 this.isInline = false;
20452 this.isInput = true;
20453 this.component = this.el.select('.add-on', true).first() || false;
20454 this.component = (this.component && this.component.length === 0) ? false : this.component;
20455 this.hasInput = this.component && this.inputEL().length;
20457 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20459 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20461 this.picker().on('mousedown', this.onMousedown, this);
20462 this.picker().on('click', this.onClick, this);
20464 this.picker().addClass('datepicker-dropdown');
20466 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20467 v.setStyle('width', '189px');
20474 if(this.isInline) {
20480 setValue: function(v, suppressEvent)
20482 var o = this.getValue();
20484 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20488 if(suppressEvent !== true){
20489 this.fireEvent('select', this, o, v);
20494 getValue: function()
20499 onClick: function(e)
20501 e.stopPropagation();
20502 e.preventDefault();
20504 var target = e.getTarget();
20506 if(target.nodeName.toLowerCase() === 'i'){
20507 target = Roo.get(target).dom.parentNode;
20510 var nodeName = target.nodeName;
20511 var className = target.className;
20512 var html = target.innerHTML;
20514 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20518 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20520 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20526 picker : function()
20528 return this.pickerEl;
20531 fillMonths: function()
20534 var months = this.picker().select('>.datepicker-months td', true).first();
20536 months.dom.innerHTML = '';
20542 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20545 months.createChild(month);
20554 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20555 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20558 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20559 e.removeClass('active');
20561 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20562 e.addClass('active');
20569 if(this.isInline) {
20573 this.picker().removeClass(['bottom', 'top']);
20575 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20577 * place to the top of element!
20581 this.picker().addClass('top');
20582 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20587 this.picker().addClass('bottom');
20589 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20592 onFocus : function()
20594 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20598 onBlur : function()
20600 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20602 var d = this.inputEl().getValue();
20611 this.picker().show();
20612 this.picker().select('>.datepicker-months', true).first().show();
20616 this.fireEvent('show', this, this.date);
20621 if(this.isInline) {
20624 this.picker().hide();
20625 this.fireEvent('hide', this, this.date);
20629 onMousedown: function(e)
20631 e.stopPropagation();
20632 e.preventDefault();
20637 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20641 fireKey: function(e)
20643 if (!this.picker().isVisible()){
20644 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20655 e.preventDefault();
20659 dir = e.keyCode == 37 ? -1 : 1;
20661 this.vIndex = this.vIndex + dir;
20663 if(this.vIndex < 0){
20667 if(this.vIndex > 11){
20671 if(isNaN(this.vIndex)){
20675 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20681 dir = e.keyCode == 38 ? -1 : 1;
20683 this.vIndex = this.vIndex + dir * 4;
20685 if(this.vIndex < 0){
20689 if(this.vIndex > 11){
20693 if(isNaN(this.vIndex)){
20697 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20702 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20703 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20707 e.preventDefault();
20710 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20711 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20727 this.picker().remove();
20732 Roo.apply(Roo.bootstrap.MonthField, {
20751 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20752 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20757 Roo.apply(Roo.bootstrap.MonthField, {
20761 cls: 'datepicker dropdown-menu roo-dynamic',
20765 cls: 'datepicker-months',
20769 cls: 'table-condensed',
20771 Roo.bootstrap.DateField.content
20791 * @class Roo.bootstrap.CheckBox
20792 * @extends Roo.bootstrap.Input
20793 * Bootstrap CheckBox class
20795 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20796 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20797 * @cfg {String} boxLabel The text that appears beside the checkbox
20798 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20799 * @cfg {Boolean} checked initnal the element
20800 * @cfg {Boolean} inline inline the element (default false)
20801 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20802 * @cfg {String} tooltip label tooltip
20805 * Create a new CheckBox
20806 * @param {Object} config The config object
20809 Roo.bootstrap.CheckBox = function(config){
20810 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20815 * Fires when the element is checked or unchecked.
20816 * @param {Roo.bootstrap.CheckBox} this This input
20817 * @param {Boolean} checked The new checked value
20822 * Fires when the element is click.
20823 * @param {Roo.bootstrap.CheckBox} this This input
20830 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20832 inputType: 'checkbox',
20841 getAutoCreate : function()
20843 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20849 cfg.cls = 'form-group ' + this.inputType; //input-group
20852 cfg.cls += ' ' + this.inputType + '-inline';
20858 type : this.inputType,
20859 value : this.inputValue,
20860 cls : 'roo-' + this.inputType, //'form-box',
20861 placeholder : this.placeholder || ''
20865 if(this.inputType != 'radio'){
20869 cls : 'roo-hidden-value',
20870 value : this.checked ? this.inputValue : this.valueOff
20875 if (this.weight) { // Validity check?
20876 cfg.cls += " " + this.inputType + "-" + this.weight;
20879 if (this.disabled) {
20880 input.disabled=true;
20884 input.checked = this.checked;
20889 input.name = this.name;
20891 if(this.inputType != 'radio'){
20892 hidden.name = this.name;
20893 input.name = '_hidden_' + this.name;
20898 input.cls += ' input-' + this.size;
20903 ['xs','sm','md','lg'].map(function(size){
20904 if (settings[size]) {
20905 cfg.cls += ' col-' + size + '-' + settings[size];
20909 var inputblock = input;
20911 if (this.before || this.after) {
20914 cls : 'input-group',
20919 inputblock.cn.push({
20921 cls : 'input-group-addon',
20926 inputblock.cn.push(input);
20928 if(this.inputType != 'radio'){
20929 inputblock.cn.push(hidden);
20933 inputblock.cn.push({
20935 cls : 'input-group-addon',
20942 if (align ==='left' && this.fieldLabel.length) {
20943 // Roo.log("left and has label");
20948 cls : 'control-label',
20949 html : this.fieldLabel
20959 if(this.labelWidth > 12){
20960 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20963 if(this.labelWidth < 13 && this.labelmd == 0){
20964 this.labelmd = this.labelWidth;
20967 if(this.labellg > 0){
20968 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20969 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20972 if(this.labelmd > 0){
20973 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20974 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20977 if(this.labelsm > 0){
20978 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20979 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20982 if(this.labelxs > 0){
20983 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20984 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20987 } else if ( this.fieldLabel.length) {
20988 // Roo.log(" label");
20992 tag: this.boxLabel ? 'span' : 'label',
20994 cls: 'control-label box-input-label',
20995 //cls : 'input-group-addon',
20996 html : this.fieldLabel
21005 // Roo.log(" no label && no align");
21006 cfg.cn = [ inputblock ] ;
21012 var boxLabelCfg = {
21014 //'for': id, // box label is handled by onclick - so no for...
21016 html: this.boxLabel
21020 boxLabelCfg.tooltip = this.tooltip;
21023 cfg.cn.push(boxLabelCfg);
21026 if(this.inputType != 'radio'){
21027 cfg.cn.push(hidden);
21035 * return the real input element.
21037 inputEl: function ()
21039 return this.el.select('input.roo-' + this.inputType,true).first();
21041 hiddenEl: function ()
21043 return this.el.select('input.roo-hidden-value',true).first();
21046 labelEl: function()
21048 return this.el.select('label.control-label',true).first();
21050 /* depricated... */
21054 return this.labelEl();
21057 boxLabelEl: function()
21059 return this.el.select('label.box-label',true).first();
21062 initEvents : function()
21064 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21066 this.inputEl().on('click', this.onClick, this);
21068 if (this.boxLabel) {
21069 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21072 this.startValue = this.getValue();
21075 Roo.bootstrap.CheckBox.register(this);
21079 onClick : function(e)
21081 if(this.fireEvent('click', this, e) !== false){
21082 this.setChecked(!this.checked);
21087 setChecked : function(state,suppressEvent)
21089 this.startValue = this.getValue();
21091 if(this.inputType == 'radio'){
21093 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21094 e.dom.checked = false;
21097 this.inputEl().dom.checked = true;
21099 this.inputEl().dom.value = this.inputValue;
21101 if(suppressEvent !== true){
21102 this.fireEvent('check', this, true);
21110 this.checked = state;
21112 this.inputEl().dom.checked = state;
21115 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21117 if(suppressEvent !== true){
21118 this.fireEvent('check', this, state);
21124 getValue : function()
21126 if(this.inputType == 'radio'){
21127 return this.getGroupValue();
21130 return this.hiddenEl().dom.value;
21134 getGroupValue : function()
21136 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21140 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21143 setValue : function(v,suppressEvent)
21145 if(this.inputType == 'radio'){
21146 this.setGroupValue(v, suppressEvent);
21150 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21155 setGroupValue : function(v, suppressEvent)
21157 this.startValue = this.getValue();
21159 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21160 e.dom.checked = false;
21162 if(e.dom.value == v){
21163 e.dom.checked = true;
21167 if(suppressEvent !== true){
21168 this.fireEvent('check', this, true);
21176 validate : function()
21178 if(this.getVisibilityEl().hasClass('hidden')){
21184 (this.inputType == 'radio' && this.validateRadio()) ||
21185 (this.inputType == 'checkbox' && this.validateCheckbox())
21191 this.markInvalid();
21195 validateRadio : function()
21197 if(this.getVisibilityEl().hasClass('hidden')){
21201 if(this.allowBlank){
21207 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21208 if(!e.dom.checked){
21220 validateCheckbox : function()
21223 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21224 //return (this.getValue() == this.inputValue) ? true : false;
21227 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21235 for(var i in group){
21236 if(group[i].el.isVisible(true)){
21244 for(var i in group){
21249 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21256 * Mark this field as valid
21258 markValid : function()
21262 this.fireEvent('valid', this);
21264 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21267 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21274 if(this.inputType == 'radio'){
21275 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21276 var fg = e.findParent('.form-group', false, true);
21277 if (Roo.bootstrap.version == 3) {
21278 fg.removeClass([_this.invalidClass, _this.validClass]);
21279 fg.addClass(_this.validClass);
21281 fg.removeClass(['is-valid', 'is-invalid']);
21282 fg.addClass('is-valid');
21290 var fg = this.el.findParent('.form-group', false, true);
21291 if (Roo.bootstrap.version == 3) {
21292 fg.removeClass([this.invalidClass, this.validClass]);
21293 fg.addClass(this.validClass);
21295 fg.removeClass(['is-valid', 'is-invalid']);
21296 fg.addClass('is-valid');
21301 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21307 for(var i in group){
21308 var fg = group[i].el.findParent('.form-group', false, true);
21309 if (Roo.bootstrap.version == 3) {
21310 fg.removeClass([this.invalidClass, this.validClass]);
21311 fg.addClass(this.validClass);
21313 fg.removeClass(['is-valid', 'is-invalid']);
21314 fg.addClass('is-valid');
21320 * Mark this field as invalid
21321 * @param {String} msg The validation message
21323 markInvalid : function(msg)
21325 if(this.allowBlank){
21331 this.fireEvent('invalid', this, msg);
21333 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21336 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21340 label.markInvalid();
21343 if(this.inputType == 'radio'){
21345 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21346 var fg = e.findParent('.form-group', false, true);
21347 if (Roo.bootstrap.version == 3) {
21348 fg.removeClass([_this.invalidClass, _this.validClass]);
21349 fg.addClass(_this.invalidClass);
21351 fg.removeClass(['is-invalid', 'is-valid']);
21352 fg.addClass('is-invalid');
21360 var fg = this.el.findParent('.form-group', false, true);
21361 if (Roo.bootstrap.version == 3) {
21362 fg.removeClass([_this.invalidClass, _this.validClass]);
21363 fg.addClass(_this.invalidClass);
21365 fg.removeClass(['is-invalid', 'is-valid']);
21366 fg.addClass('is-invalid');
21371 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21377 for(var i in group){
21378 var fg = group[i].el.findParent('.form-group', false, true);
21379 if (Roo.bootstrap.version == 3) {
21380 fg.removeClass([_this.invalidClass, _this.validClass]);
21381 fg.addClass(_this.invalidClass);
21383 fg.removeClass(['is-invalid', 'is-valid']);
21384 fg.addClass('is-invalid');
21390 clearInvalid : function()
21392 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21394 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21396 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21398 if (label && label.iconEl) {
21399 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21400 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21404 disable : function()
21406 if(this.inputType != 'radio'){
21407 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21414 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21415 _this.getActionEl().addClass(this.disabledClass);
21416 e.dom.disabled = true;
21420 this.disabled = true;
21421 this.fireEvent("disable", this);
21425 enable : function()
21427 if(this.inputType != 'radio'){
21428 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21435 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21436 _this.getActionEl().removeClass(this.disabledClass);
21437 e.dom.disabled = false;
21441 this.disabled = false;
21442 this.fireEvent("enable", this);
21446 setBoxLabel : function(v)
21451 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21457 Roo.apply(Roo.bootstrap.CheckBox, {
21462 * register a CheckBox Group
21463 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21465 register : function(checkbox)
21467 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21468 this.groups[checkbox.groupId] = {};
21471 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21475 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21479 * fetch a CheckBox Group based on the group ID
21480 * @param {string} the group ID
21481 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21483 get: function(groupId) {
21484 if (typeof(this.groups[groupId]) == 'undefined') {
21488 return this.groups[groupId] ;
21501 * @class Roo.bootstrap.Radio
21502 * @extends Roo.bootstrap.Component
21503 * Bootstrap Radio class
21504 * @cfg {String} boxLabel - the label associated
21505 * @cfg {String} value - the value of radio
21508 * Create a new Radio
21509 * @param {Object} config The config object
21511 Roo.bootstrap.Radio = function(config){
21512 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21516 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21522 getAutoCreate : function()
21526 cls : 'form-group radio',
21531 html : this.boxLabel
21539 initEvents : function()
21541 this.parent().register(this);
21543 this.el.on('click', this.onClick, this);
21547 onClick : function(e)
21549 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21550 this.setChecked(true);
21554 setChecked : function(state, suppressEvent)
21556 this.parent().setValue(this.value, suppressEvent);
21560 setBoxLabel : function(v)
21565 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21580 * @class Roo.bootstrap.SecurePass
21581 * @extends Roo.bootstrap.Input
21582 * Bootstrap SecurePass class
21586 * Create a new SecurePass
21587 * @param {Object} config The config object
21590 Roo.bootstrap.SecurePass = function (config) {
21591 // these go here, so the translation tool can replace them..
21593 PwdEmpty: "Please type a password, and then retype it to confirm.",
21594 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21595 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21596 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21597 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21598 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21599 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21600 TooWeak: "Your password is Too Weak."
21602 this.meterLabel = "Password strength:";
21603 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21604 this.meterClass = [
21605 "roo-password-meter-tooweak",
21606 "roo-password-meter-weak",
21607 "roo-password-meter-medium",
21608 "roo-password-meter-strong",
21609 "roo-password-meter-grey"
21614 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21617 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21619 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21621 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21622 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21623 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21624 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21625 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21626 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21627 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21637 * @cfg {String/Object} Label for the strength meter (defaults to
21638 * 'Password strength:')
21643 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21644 * ['Weak', 'Medium', 'Strong'])
21647 pwdStrengths: false,
21660 initEvents: function ()
21662 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21664 if (this.el.is('input[type=password]') && Roo.isSafari) {
21665 this.el.on('keydown', this.SafariOnKeyDown, this);
21668 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21671 onRender: function (ct, position)
21673 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21674 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21675 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21677 this.trigger.createChild({
21682 cls: 'roo-password-meter-grey col-xs-12',
21685 //width: this.meterWidth + 'px'
21689 cls: 'roo-password-meter-text'
21695 if (this.hideTrigger) {
21696 this.trigger.setDisplayed(false);
21698 this.setSize(this.width || '', this.height || '');
21701 onDestroy: function ()
21703 if (this.trigger) {
21704 this.trigger.removeAllListeners();
21705 this.trigger.remove();
21708 this.wrap.remove();
21710 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21713 checkStrength: function ()
21715 var pwd = this.inputEl().getValue();
21716 if (pwd == this._lastPwd) {
21721 if (this.ClientSideStrongPassword(pwd)) {
21723 } else if (this.ClientSideMediumPassword(pwd)) {
21725 } else if (this.ClientSideWeakPassword(pwd)) {
21731 Roo.log('strength1: ' + strength);
21733 //var pm = this.trigger.child('div/div/div').dom;
21734 var pm = this.trigger.child('div/div');
21735 pm.removeClass(this.meterClass);
21736 pm.addClass(this.meterClass[strength]);
21739 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21741 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21743 this._lastPwd = pwd;
21747 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21749 this._lastPwd = '';
21751 var pm = this.trigger.child('div/div');
21752 pm.removeClass(this.meterClass);
21753 pm.addClass('roo-password-meter-grey');
21756 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21759 this.inputEl().dom.type='password';
21762 validateValue: function (value)
21765 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21768 if (value.length == 0) {
21769 if (this.allowBlank) {
21770 this.clearInvalid();
21774 this.markInvalid(this.errors.PwdEmpty);
21775 this.errorMsg = this.errors.PwdEmpty;
21783 if ('[\x21-\x7e]*'.match(value)) {
21784 this.markInvalid(this.errors.PwdBadChar);
21785 this.errorMsg = this.errors.PwdBadChar;
21788 if (value.length < 6) {
21789 this.markInvalid(this.errors.PwdShort);
21790 this.errorMsg = this.errors.PwdShort;
21793 if (value.length > 16) {
21794 this.markInvalid(this.errors.PwdLong);
21795 this.errorMsg = this.errors.PwdLong;
21799 if (this.ClientSideStrongPassword(value)) {
21801 } else if (this.ClientSideMediumPassword(value)) {
21803 } else if (this.ClientSideWeakPassword(value)) {
21810 if (strength < 2) {
21811 //this.markInvalid(this.errors.TooWeak);
21812 this.errorMsg = this.errors.TooWeak;
21817 console.log('strength2: ' + strength);
21819 //var pm = this.trigger.child('div/div/div').dom;
21821 var pm = this.trigger.child('div/div');
21822 pm.removeClass(this.meterClass);
21823 pm.addClass(this.meterClass[strength]);
21825 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21827 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21829 this.errorMsg = '';
21833 CharacterSetChecks: function (type)
21836 this.fResult = false;
21839 isctype: function (character, type)
21842 case this.kCapitalLetter:
21843 if (character >= 'A' && character <= 'Z') {
21848 case this.kSmallLetter:
21849 if (character >= 'a' && character <= 'z') {
21855 if (character >= '0' && character <= '9') {
21860 case this.kPunctuation:
21861 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21872 IsLongEnough: function (pwd, size)
21874 return !(pwd == null || isNaN(size) || pwd.length < size);
21877 SpansEnoughCharacterSets: function (word, nb)
21879 if (!this.IsLongEnough(word, nb))
21884 var characterSetChecks = new Array(
21885 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21886 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21889 for (var index = 0; index < word.length; ++index) {
21890 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21891 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21892 characterSetChecks[nCharSet].fResult = true;
21899 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21900 if (characterSetChecks[nCharSet].fResult) {
21905 if (nCharSets < nb) {
21911 ClientSideStrongPassword: function (pwd)
21913 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21916 ClientSideMediumPassword: function (pwd)
21918 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21921 ClientSideWeakPassword: function (pwd)
21923 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21926 })//<script type="text/javascript">
21929 * Based Ext JS Library 1.1.1
21930 * Copyright(c) 2006-2007, Ext JS, LLC.
21936 * @class Roo.HtmlEditorCore
21937 * @extends Roo.Component
21938 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21940 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21943 Roo.HtmlEditorCore = function(config){
21946 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21951 * @event initialize
21952 * Fires when the editor is fully initialized (including the iframe)
21953 * @param {Roo.HtmlEditorCore} this
21958 * Fires when the editor is first receives the focus. Any insertion must wait
21959 * until after this event.
21960 * @param {Roo.HtmlEditorCore} this
21964 * @event beforesync
21965 * Fires before the textarea is updated with content from the editor iframe. Return false
21966 * to cancel the sync.
21967 * @param {Roo.HtmlEditorCore} this
21968 * @param {String} html
21972 * @event beforepush
21973 * Fires before the iframe editor is updated with content from the textarea. Return false
21974 * to cancel the push.
21975 * @param {Roo.HtmlEditorCore} this
21976 * @param {String} html
21981 * Fires when the textarea is updated with content from the editor iframe.
21982 * @param {Roo.HtmlEditorCore} this
21983 * @param {String} html
21988 * Fires when the iframe editor is updated with content from the textarea.
21989 * @param {Roo.HtmlEditorCore} this
21990 * @param {String} html
21995 * @event editorevent
21996 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21997 * @param {Roo.HtmlEditorCore} this
22003 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22005 // defaults : white / black...
22006 this.applyBlacklists();
22013 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22017 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22023 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22028 * @cfg {Number} height (in pixels)
22032 * @cfg {Number} width (in pixels)
22037 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22040 stylesheets: false,
22045 // private properties
22046 validationEvent : false,
22048 initialized : false,
22050 sourceEditMode : false,
22051 onFocus : Roo.emptyFn,
22053 hideMode:'offsets',
22057 // blacklist + whitelisted elements..
22064 * Protected method that will not generally be called directly. It
22065 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22066 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22068 getDocMarkup : function(){
22072 // inherit styels from page...??
22073 if (this.stylesheets === false) {
22075 Roo.get(document.head).select('style').each(function(node) {
22076 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22079 Roo.get(document.head).select('link').each(function(node) {
22080 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22083 } else if (!this.stylesheets.length) {
22085 st = '<style type="text/css">' +
22086 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22089 st = '<style type="text/css">' +
22094 st += '<style type="text/css">' +
22095 'IMG { cursor: pointer } ' +
22098 var cls = 'roo-htmleditor-body';
22100 if(this.bodyCls.length){
22101 cls += ' ' + this.bodyCls;
22104 return '<html><head>' + st +
22105 //<style type="text/css">' +
22106 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22108 ' </head><body class="' + cls + '"></body></html>';
22112 onRender : function(ct, position)
22115 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22116 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22119 this.el.dom.style.border = '0 none';
22120 this.el.dom.setAttribute('tabIndex', -1);
22121 this.el.addClass('x-hidden hide');
22125 if(Roo.isIE){ // fix IE 1px bogus margin
22126 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22130 this.frameId = Roo.id();
22134 var iframe = this.owner.wrap.createChild({
22136 cls: 'form-control', // bootstrap..
22138 name: this.frameId,
22139 frameBorder : 'no',
22140 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22145 this.iframe = iframe.dom;
22147 this.assignDocWin();
22149 this.doc.designMode = 'on';
22152 this.doc.write(this.getDocMarkup());
22156 var task = { // must defer to wait for browser to be ready
22158 //console.log("run task?" + this.doc.readyState);
22159 this.assignDocWin();
22160 if(this.doc.body || this.doc.readyState == 'complete'){
22162 this.doc.designMode="on";
22166 Roo.TaskMgr.stop(task);
22167 this.initEditor.defer(10, this);
22174 Roo.TaskMgr.start(task);
22179 onResize : function(w, h)
22181 Roo.log('resize: ' +w + ',' + h );
22182 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22186 if(typeof w == 'number'){
22188 this.iframe.style.width = w + 'px';
22190 if(typeof h == 'number'){
22192 this.iframe.style.height = h + 'px';
22194 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22201 * Toggles the editor between standard and source edit mode.
22202 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22204 toggleSourceEdit : function(sourceEditMode){
22206 this.sourceEditMode = sourceEditMode === true;
22208 if(this.sourceEditMode){
22210 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22213 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22214 //this.iframe.className = '';
22217 //this.setSize(this.owner.wrap.getSize());
22218 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22225 * Protected method that will not generally be called directly. If you need/want
22226 * custom HTML cleanup, this is the method you should override.
22227 * @param {String} html The HTML to be cleaned
22228 * return {String} The cleaned HTML
22230 cleanHtml : function(html){
22231 html = String(html);
22232 if(html.length > 5){
22233 if(Roo.isSafari){ // strip safari nonsense
22234 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22237 if(html == ' '){
22244 * HTML Editor -> Textarea
22245 * Protected method that will not generally be called directly. Syncs the contents
22246 * of the editor iframe with the textarea.
22248 syncValue : function(){
22249 if(this.initialized){
22250 var bd = (this.doc.body || this.doc.documentElement);
22251 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22252 var html = bd.innerHTML;
22254 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22255 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22257 html = '<div style="'+m[0]+'">' + html + '</div>';
22260 html = this.cleanHtml(html);
22261 // fix up the special chars.. normaly like back quotes in word...
22262 // however we do not want to do this with chinese..
22263 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22264 var cc = b.charCodeAt();
22266 (cc >= 0x4E00 && cc < 0xA000 ) ||
22267 (cc >= 0x3400 && cc < 0x4E00 ) ||
22268 (cc >= 0xf900 && cc < 0xfb00 )
22274 if(this.owner.fireEvent('beforesync', this, html) !== false){
22275 this.el.dom.value = html;
22276 this.owner.fireEvent('sync', this, html);
22282 * Protected method that will not generally be called directly. Pushes the value of the textarea
22283 * into the iframe editor.
22285 pushValue : function(){
22286 if(this.initialized){
22287 var v = this.el.dom.value.trim();
22289 // if(v.length < 1){
22293 if(this.owner.fireEvent('beforepush', this, v) !== false){
22294 var d = (this.doc.body || this.doc.documentElement);
22296 this.cleanUpPaste();
22297 this.el.dom.value = d.innerHTML;
22298 this.owner.fireEvent('push', this, v);
22304 deferFocus : function(){
22305 this.focus.defer(10, this);
22309 focus : function(){
22310 if(this.win && !this.sourceEditMode){
22317 assignDocWin: function()
22319 var iframe = this.iframe;
22322 this.doc = iframe.contentWindow.document;
22323 this.win = iframe.contentWindow;
22325 // if (!Roo.get(this.frameId)) {
22328 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22329 // this.win = Roo.get(this.frameId).dom.contentWindow;
22331 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22335 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22336 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22341 initEditor : function(){
22342 //console.log("INIT EDITOR");
22343 this.assignDocWin();
22347 this.doc.designMode="on";
22349 this.doc.write(this.getDocMarkup());
22352 var dbody = (this.doc.body || this.doc.documentElement);
22353 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22354 // this copies styles from the containing element into thsi one..
22355 // not sure why we need all of this..
22356 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22358 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22359 //ss['background-attachment'] = 'fixed'; // w3c
22360 dbody.bgProperties = 'fixed'; // ie
22361 //Roo.DomHelper.applyStyles(dbody, ss);
22362 Roo.EventManager.on(this.doc, {
22363 //'mousedown': this.onEditorEvent,
22364 'mouseup': this.onEditorEvent,
22365 'dblclick': this.onEditorEvent,
22366 'click': this.onEditorEvent,
22367 'keyup': this.onEditorEvent,
22372 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22374 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22375 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22377 this.initialized = true;
22379 this.owner.fireEvent('initialize', this);
22384 onDestroy : function(){
22390 //for (var i =0; i < this.toolbars.length;i++) {
22391 // // fixme - ask toolbars for heights?
22392 // this.toolbars[i].onDestroy();
22395 //this.wrap.dom.innerHTML = '';
22396 //this.wrap.remove();
22401 onFirstFocus : function(){
22403 this.assignDocWin();
22406 this.activated = true;
22409 if(Roo.isGecko){ // prevent silly gecko errors
22411 var s = this.win.getSelection();
22412 if(!s.focusNode || s.focusNode.nodeType != 3){
22413 var r = s.getRangeAt(0);
22414 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22419 this.execCmd('useCSS', true);
22420 this.execCmd('styleWithCSS', false);
22423 this.owner.fireEvent('activate', this);
22427 adjustFont: function(btn){
22428 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22429 //if(Roo.isSafari){ // safari
22432 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22433 if(Roo.isSafari){ // safari
22434 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22435 v = (v < 10) ? 10 : v;
22436 v = (v > 48) ? 48 : v;
22437 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22442 v = Math.max(1, v+adjust);
22444 this.execCmd('FontSize', v );
22447 onEditorEvent : function(e)
22449 this.owner.fireEvent('editorevent', this, e);
22450 // this.updateToolbar();
22451 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22454 insertTag : function(tg)
22456 // could be a bit smarter... -> wrap the current selected tRoo..
22457 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22459 range = this.createRange(this.getSelection());
22460 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22461 wrappingNode.appendChild(range.extractContents());
22462 range.insertNode(wrappingNode);
22469 this.execCmd("formatblock", tg);
22473 insertText : function(txt)
22477 var range = this.createRange();
22478 range.deleteContents();
22479 //alert(Sender.getAttribute('label'));
22481 range.insertNode(this.doc.createTextNode(txt));
22487 * Executes a Midas editor command on the editor document and performs necessary focus and
22488 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22489 * @param {String} cmd The Midas command
22490 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22492 relayCmd : function(cmd, value){
22494 this.execCmd(cmd, value);
22495 this.owner.fireEvent('editorevent', this);
22496 //this.updateToolbar();
22497 this.owner.deferFocus();
22501 * Executes a Midas editor command directly on the editor document.
22502 * For visual commands, you should use {@link #relayCmd} instead.
22503 * <b>This should only be called after the editor is initialized.</b>
22504 * @param {String} cmd The Midas command
22505 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22507 execCmd : function(cmd, value){
22508 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22515 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22517 * @param {String} text | dom node..
22519 insertAtCursor : function(text)
22522 if(!this.activated){
22528 var r = this.doc.selection.createRange();
22539 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22543 // from jquery ui (MIT licenced)
22545 var win = this.win;
22547 if (win.getSelection && win.getSelection().getRangeAt) {
22548 range = win.getSelection().getRangeAt(0);
22549 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22550 range.insertNode(node);
22551 } else if (win.document.selection && win.document.selection.createRange) {
22552 // no firefox support
22553 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22554 win.document.selection.createRange().pasteHTML(txt);
22556 // no firefox support
22557 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22558 this.execCmd('InsertHTML', txt);
22567 mozKeyPress : function(e){
22569 var c = e.getCharCode(), cmd;
22572 c = String.fromCharCode(c).toLowerCase();
22586 this.cleanUpPaste.defer(100, this);
22594 e.preventDefault();
22602 fixKeys : function(){ // load time branching for fastest keydown performance
22604 return function(e){
22605 var k = e.getKey(), r;
22608 r = this.doc.selection.createRange();
22611 r.pasteHTML('    ');
22618 r = this.doc.selection.createRange();
22620 var target = r.parentElement();
22621 if(!target || target.tagName.toLowerCase() != 'li'){
22623 r.pasteHTML('<br />');
22629 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22630 this.cleanUpPaste.defer(100, this);
22636 }else if(Roo.isOpera){
22637 return function(e){
22638 var k = e.getKey();
22642 this.execCmd('InsertHTML','    ');
22645 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22646 this.cleanUpPaste.defer(100, this);
22651 }else if(Roo.isSafari){
22652 return function(e){
22653 var k = e.getKey();
22657 this.execCmd('InsertText','\t');
22661 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22662 this.cleanUpPaste.defer(100, this);
22670 getAllAncestors: function()
22672 var p = this.getSelectedNode();
22675 a.push(p); // push blank onto stack..
22676 p = this.getParentElement();
22680 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22684 a.push(this.doc.body);
22688 lastSelNode : false,
22691 getSelection : function()
22693 this.assignDocWin();
22694 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22697 getSelectedNode: function()
22699 // this may only work on Gecko!!!
22701 // should we cache this!!!!
22706 var range = this.createRange(this.getSelection()).cloneRange();
22709 var parent = range.parentElement();
22711 var testRange = range.duplicate();
22712 testRange.moveToElementText(parent);
22713 if (testRange.inRange(range)) {
22716 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22719 parent = parent.parentElement;
22724 // is ancestor a text element.
22725 var ac = range.commonAncestorContainer;
22726 if (ac.nodeType == 3) {
22727 ac = ac.parentNode;
22730 var ar = ac.childNodes;
22733 var other_nodes = [];
22734 var has_other_nodes = false;
22735 for (var i=0;i<ar.length;i++) {
22736 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22739 // fullly contained node.
22741 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22746 // probably selected..
22747 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22748 other_nodes.push(ar[i]);
22752 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22757 has_other_nodes = true;
22759 if (!nodes.length && other_nodes.length) {
22760 nodes= other_nodes;
22762 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22768 createRange: function(sel)
22770 // this has strange effects when using with
22771 // top toolbar - not sure if it's a great idea.
22772 //this.editor.contentWindow.focus();
22773 if (typeof sel != "undefined") {
22775 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22777 return this.doc.createRange();
22780 return this.doc.createRange();
22783 getParentElement: function()
22786 this.assignDocWin();
22787 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22789 var range = this.createRange(sel);
22792 var p = range.commonAncestorContainer;
22793 while (p.nodeType == 3) { // text node
22804 * Range intersection.. the hard stuff...
22808 * [ -- selected range --- ]
22812 * if end is before start or hits it. fail.
22813 * if start is after end or hits it fail.
22815 * if either hits (but other is outside. - then it's not
22821 // @see http://www.thismuchiknow.co.uk/?p=64.
22822 rangeIntersectsNode : function(range, node)
22824 var nodeRange = node.ownerDocument.createRange();
22826 nodeRange.selectNode(node);
22828 nodeRange.selectNodeContents(node);
22831 var rangeStartRange = range.cloneRange();
22832 rangeStartRange.collapse(true);
22834 var rangeEndRange = range.cloneRange();
22835 rangeEndRange.collapse(false);
22837 var nodeStartRange = nodeRange.cloneRange();
22838 nodeStartRange.collapse(true);
22840 var nodeEndRange = nodeRange.cloneRange();
22841 nodeEndRange.collapse(false);
22843 return rangeStartRange.compareBoundaryPoints(
22844 Range.START_TO_START, nodeEndRange) == -1 &&
22845 rangeEndRange.compareBoundaryPoints(
22846 Range.START_TO_START, nodeStartRange) == 1;
22850 rangeCompareNode : function(range, node)
22852 var nodeRange = node.ownerDocument.createRange();
22854 nodeRange.selectNode(node);
22856 nodeRange.selectNodeContents(node);
22860 range.collapse(true);
22862 nodeRange.collapse(true);
22864 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22865 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22867 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22869 var nodeIsBefore = ss == 1;
22870 var nodeIsAfter = ee == -1;
22872 if (nodeIsBefore && nodeIsAfter) {
22875 if (!nodeIsBefore && nodeIsAfter) {
22876 return 1; //right trailed.
22879 if (nodeIsBefore && !nodeIsAfter) {
22880 return 2; // left trailed.
22886 // private? - in a new class?
22887 cleanUpPaste : function()
22889 // cleans up the whole document..
22890 Roo.log('cleanuppaste');
22892 this.cleanUpChildren(this.doc.body);
22893 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22894 if (clean != this.doc.body.innerHTML) {
22895 this.doc.body.innerHTML = clean;
22900 cleanWordChars : function(input) {// change the chars to hex code
22901 var he = Roo.HtmlEditorCore;
22903 var output = input;
22904 Roo.each(he.swapCodes, function(sw) {
22905 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22907 output = output.replace(swapper, sw[1]);
22914 cleanUpChildren : function (n)
22916 if (!n.childNodes.length) {
22919 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22920 this.cleanUpChild(n.childNodes[i]);
22927 cleanUpChild : function (node)
22930 //console.log(node);
22931 if (node.nodeName == "#text") {
22932 // clean up silly Windows -- stuff?
22935 if (node.nodeName == "#comment") {
22936 node.parentNode.removeChild(node);
22937 // clean up silly Windows -- stuff?
22940 var lcname = node.tagName.toLowerCase();
22941 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22942 // whitelist of tags..
22944 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22946 node.parentNode.removeChild(node);
22951 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22953 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22954 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22956 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22957 // remove_keep_children = true;
22960 if (remove_keep_children) {
22961 this.cleanUpChildren(node);
22962 // inserts everything just before this node...
22963 while (node.childNodes.length) {
22964 var cn = node.childNodes[0];
22965 node.removeChild(cn);
22966 node.parentNode.insertBefore(cn, node);
22968 node.parentNode.removeChild(node);
22972 if (!node.attributes || !node.attributes.length) {
22973 this.cleanUpChildren(node);
22977 function cleanAttr(n,v)
22980 if (v.match(/^\./) || v.match(/^\//)) {
22983 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22986 if (v.match(/^#/)) {
22989 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22990 node.removeAttribute(n);
22994 var cwhite = this.cwhite;
22995 var cblack = this.cblack;
22997 function cleanStyle(n,v)
22999 if (v.match(/expression/)) { //XSS?? should we even bother..
23000 node.removeAttribute(n);
23004 var parts = v.split(/;/);
23007 Roo.each(parts, function(p) {
23008 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23012 var l = p.split(':').shift().replace(/\s+/g,'');
23013 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23015 if ( cwhite.length && cblack.indexOf(l) > -1) {
23016 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23017 //node.removeAttribute(n);
23021 // only allow 'c whitelisted system attributes'
23022 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23023 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23024 //node.removeAttribute(n);
23034 if (clean.length) {
23035 node.setAttribute(n, clean.join(';'));
23037 node.removeAttribute(n);
23043 for (var i = node.attributes.length-1; i > -1 ; i--) {
23044 var a = node.attributes[i];
23047 if (a.name.toLowerCase().substr(0,2)=='on') {
23048 node.removeAttribute(a.name);
23051 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23052 node.removeAttribute(a.name);
23055 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23056 cleanAttr(a.name,a.value); // fixme..
23059 if (a.name == 'style') {
23060 cleanStyle(a.name,a.value);
23063 /// clean up MS crap..
23064 // tecnically this should be a list of valid class'es..
23067 if (a.name == 'class') {
23068 if (a.value.match(/^Mso/)) {
23069 node.className = '';
23072 if (a.value.match(/^body$/)) {
23073 node.className = '';
23084 this.cleanUpChildren(node);
23090 * Clean up MS wordisms...
23092 cleanWord : function(node)
23097 this.cleanWord(this.doc.body);
23100 if (node.nodeName == "#text") {
23101 // clean up silly Windows -- stuff?
23104 if (node.nodeName == "#comment") {
23105 node.parentNode.removeChild(node);
23106 // clean up silly Windows -- stuff?
23110 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23111 node.parentNode.removeChild(node);
23115 // remove - but keep children..
23116 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23117 while (node.childNodes.length) {
23118 var cn = node.childNodes[0];
23119 node.removeChild(cn);
23120 node.parentNode.insertBefore(cn, node);
23122 node.parentNode.removeChild(node);
23123 this.iterateChildren(node, this.cleanWord);
23127 if (node.className.length) {
23129 var cn = node.className.split(/\W+/);
23131 Roo.each(cn, function(cls) {
23132 if (cls.match(/Mso[a-zA-Z]+/)) {
23137 node.className = cna.length ? cna.join(' ') : '';
23139 node.removeAttribute("class");
23143 if (node.hasAttribute("lang")) {
23144 node.removeAttribute("lang");
23147 if (node.hasAttribute("style")) {
23149 var styles = node.getAttribute("style").split(";");
23151 Roo.each(styles, function(s) {
23152 if (!s.match(/:/)) {
23155 var kv = s.split(":");
23156 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23159 // what ever is left... we allow.
23162 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23163 if (!nstyle.length) {
23164 node.removeAttribute('style');
23167 this.iterateChildren(node, this.cleanWord);
23173 * iterateChildren of a Node, calling fn each time, using this as the scole..
23174 * @param {DomNode} node node to iterate children of.
23175 * @param {Function} fn method of this class to call on each item.
23177 iterateChildren : function(node, fn)
23179 if (!node.childNodes.length) {
23182 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23183 fn.call(this, node.childNodes[i])
23189 * cleanTableWidths.
23191 * Quite often pasting from word etc.. results in tables with column and widths.
23192 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23195 cleanTableWidths : function(node)
23200 this.cleanTableWidths(this.doc.body);
23205 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23208 Roo.log(node.tagName);
23209 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23210 this.iterateChildren(node, this.cleanTableWidths);
23213 if (node.hasAttribute('width')) {
23214 node.removeAttribute('width');
23218 if (node.hasAttribute("style")) {
23221 var styles = node.getAttribute("style").split(";");
23223 Roo.each(styles, function(s) {
23224 if (!s.match(/:/)) {
23227 var kv = s.split(":");
23228 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23231 // what ever is left... we allow.
23234 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23235 if (!nstyle.length) {
23236 node.removeAttribute('style');
23240 this.iterateChildren(node, this.cleanTableWidths);
23248 domToHTML : function(currentElement, depth, nopadtext) {
23250 depth = depth || 0;
23251 nopadtext = nopadtext || false;
23253 if (!currentElement) {
23254 return this.domToHTML(this.doc.body);
23257 //Roo.log(currentElement);
23259 var allText = false;
23260 var nodeName = currentElement.nodeName;
23261 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23263 if (nodeName == '#text') {
23265 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23270 if (nodeName != 'BODY') {
23273 // Prints the node tagName, such as <A>, <IMG>, etc
23276 for(i = 0; i < currentElement.attributes.length;i++) {
23278 var aname = currentElement.attributes.item(i).name;
23279 if (!currentElement.attributes.item(i).value.length) {
23282 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23285 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23294 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23297 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23302 // Traverse the tree
23304 var currentElementChild = currentElement.childNodes.item(i);
23305 var allText = true;
23306 var innerHTML = '';
23308 while (currentElementChild) {
23309 // Formatting code (indent the tree so it looks nice on the screen)
23310 var nopad = nopadtext;
23311 if (lastnode == 'SPAN') {
23315 if (currentElementChild.nodeName == '#text') {
23316 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23317 toadd = nopadtext ? toadd : toadd.trim();
23318 if (!nopad && toadd.length > 80) {
23319 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23321 innerHTML += toadd;
23324 currentElementChild = currentElement.childNodes.item(i);
23330 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23332 // Recursively traverse the tree structure of the child node
23333 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23334 lastnode = currentElementChild.nodeName;
23336 currentElementChild=currentElement.childNodes.item(i);
23342 // The remaining code is mostly for formatting the tree
23343 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23348 ret+= "</"+tagName+">";
23354 applyBlacklists : function()
23356 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23357 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23361 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23362 if (b.indexOf(tag) > -1) {
23365 this.white.push(tag);
23369 Roo.each(w, function(tag) {
23370 if (b.indexOf(tag) > -1) {
23373 if (this.white.indexOf(tag) > -1) {
23376 this.white.push(tag);
23381 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23382 if (w.indexOf(tag) > -1) {
23385 this.black.push(tag);
23389 Roo.each(b, function(tag) {
23390 if (w.indexOf(tag) > -1) {
23393 if (this.black.indexOf(tag) > -1) {
23396 this.black.push(tag);
23401 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23402 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23406 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23407 if (b.indexOf(tag) > -1) {
23410 this.cwhite.push(tag);
23414 Roo.each(w, function(tag) {
23415 if (b.indexOf(tag) > -1) {
23418 if (this.cwhite.indexOf(tag) > -1) {
23421 this.cwhite.push(tag);
23426 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23427 if (w.indexOf(tag) > -1) {
23430 this.cblack.push(tag);
23434 Roo.each(b, function(tag) {
23435 if (w.indexOf(tag) > -1) {
23438 if (this.cblack.indexOf(tag) > -1) {
23441 this.cblack.push(tag);
23446 setStylesheets : function(stylesheets)
23448 if(typeof(stylesheets) == 'string'){
23449 Roo.get(this.iframe.contentDocument.head).createChild({
23451 rel : 'stylesheet',
23460 Roo.each(stylesheets, function(s) {
23465 Roo.get(_this.iframe.contentDocument.head).createChild({
23467 rel : 'stylesheet',
23476 removeStylesheets : function()
23480 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23485 setStyle : function(style)
23487 Roo.get(this.iframe.contentDocument.head).createChild({
23496 // hide stuff that is not compatible
23510 * @event specialkey
23514 * @cfg {String} fieldClass @hide
23517 * @cfg {String} focusClass @hide
23520 * @cfg {String} autoCreate @hide
23523 * @cfg {String} inputType @hide
23526 * @cfg {String} invalidClass @hide
23529 * @cfg {String} invalidText @hide
23532 * @cfg {String} msgFx @hide
23535 * @cfg {String} validateOnBlur @hide
23539 Roo.HtmlEditorCore.white = [
23540 'area', 'br', 'img', 'input', 'hr', 'wbr',
23542 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23543 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23544 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23545 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23546 'table', 'ul', 'xmp',
23548 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23551 'dir', 'menu', 'ol', 'ul', 'dl',
23557 Roo.HtmlEditorCore.black = [
23558 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23560 'base', 'basefont', 'bgsound', 'blink', 'body',
23561 'frame', 'frameset', 'head', 'html', 'ilayer',
23562 'iframe', 'layer', 'link', 'meta', 'object',
23563 'script', 'style' ,'title', 'xml' // clean later..
23565 Roo.HtmlEditorCore.clean = [
23566 'script', 'style', 'title', 'xml'
23568 Roo.HtmlEditorCore.remove = [
23573 Roo.HtmlEditorCore.ablack = [
23577 Roo.HtmlEditorCore.aclean = [
23578 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23582 Roo.HtmlEditorCore.pwhite= [
23583 'http', 'https', 'mailto'
23586 // white listed style attributes.
23587 Roo.HtmlEditorCore.cwhite= [
23588 // 'text-align', /// default is to allow most things..
23594 // black listed style attributes.
23595 Roo.HtmlEditorCore.cblack= [
23596 // 'font-size' -- this can be set by the project
23600 Roo.HtmlEditorCore.swapCodes =[
23619 * @class Roo.bootstrap.HtmlEditor
23620 * @extends Roo.bootstrap.TextArea
23621 * Bootstrap HtmlEditor class
23624 * Create a new HtmlEditor
23625 * @param {Object} config The config object
23628 Roo.bootstrap.HtmlEditor = function(config){
23629 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23630 if (!this.toolbars) {
23631 this.toolbars = [];
23634 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23637 * @event initialize
23638 * Fires when the editor is fully initialized (including the iframe)
23639 * @param {HtmlEditor} this
23644 * Fires when the editor is first receives the focus. Any insertion must wait
23645 * until after this event.
23646 * @param {HtmlEditor} this
23650 * @event beforesync
23651 * Fires before the textarea is updated with content from the editor iframe. Return false
23652 * to cancel the sync.
23653 * @param {HtmlEditor} this
23654 * @param {String} html
23658 * @event beforepush
23659 * Fires before the iframe editor is updated with content from the textarea. Return false
23660 * to cancel the push.
23661 * @param {HtmlEditor} this
23662 * @param {String} html
23667 * Fires when the textarea is updated with content from the editor iframe.
23668 * @param {HtmlEditor} this
23669 * @param {String} html
23674 * Fires when the iframe editor is updated with content from the textarea.
23675 * @param {HtmlEditor} this
23676 * @param {String} html
23680 * @event editmodechange
23681 * Fires when the editor switches edit modes
23682 * @param {HtmlEditor} this
23683 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23685 editmodechange: true,
23687 * @event editorevent
23688 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23689 * @param {HtmlEditor} this
23693 * @event firstfocus
23694 * Fires when on first focus - needed by toolbars..
23695 * @param {HtmlEditor} this
23700 * Auto save the htmlEditor value as a file into Events
23701 * @param {HtmlEditor} this
23705 * @event savedpreview
23706 * preview the saved version of htmlEditor
23707 * @param {HtmlEditor} this
23714 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23718 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23723 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23728 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23733 * @cfg {Number} height (in pixels)
23737 * @cfg {Number} width (in pixels)
23742 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23745 stylesheets: false,
23750 // private properties
23751 validationEvent : false,
23753 initialized : false,
23756 onFocus : Roo.emptyFn,
23758 hideMode:'offsets',
23760 tbContainer : false,
23764 toolbarContainer :function() {
23765 return this.wrap.select('.x-html-editor-tb',true).first();
23769 * Protected method that will not generally be called directly. It
23770 * is called when the editor creates its toolbar. Override this method if you need to
23771 * add custom toolbar buttons.
23772 * @param {HtmlEditor} editor
23774 createToolbar : function(){
23775 Roo.log('renewing');
23776 Roo.log("create toolbars");
23778 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23779 this.toolbars[0].render(this.toolbarContainer());
23783 // if (!editor.toolbars || !editor.toolbars.length) {
23784 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23787 // for (var i =0 ; i < editor.toolbars.length;i++) {
23788 // editor.toolbars[i] = Roo.factory(
23789 // typeof(editor.toolbars[i]) == 'string' ?
23790 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23791 // Roo.bootstrap.HtmlEditor);
23792 // editor.toolbars[i].init(editor);
23798 onRender : function(ct, position)
23800 // Roo.log("Call onRender: " + this.xtype);
23802 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23804 this.wrap = this.inputEl().wrap({
23805 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23808 this.editorcore.onRender(ct, position);
23810 if (this.resizable) {
23811 this.resizeEl = new Roo.Resizable(this.wrap, {
23815 minHeight : this.height,
23816 height: this.height,
23817 handles : this.resizable,
23820 resize : function(r, w, h) {
23821 _t.onResize(w,h); // -something
23827 this.createToolbar(this);
23830 if(!this.width && this.resizable){
23831 this.setSize(this.wrap.getSize());
23833 if (this.resizeEl) {
23834 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23835 // should trigger onReize..
23841 onResize : function(w, h)
23843 Roo.log('resize: ' +w + ',' + h );
23844 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23848 if(this.inputEl() ){
23849 if(typeof w == 'number'){
23850 var aw = w - this.wrap.getFrameWidth('lr');
23851 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23854 if(typeof h == 'number'){
23855 var tbh = -11; // fixme it needs to tool bar size!
23856 for (var i =0; i < this.toolbars.length;i++) {
23857 // fixme - ask toolbars for heights?
23858 tbh += this.toolbars[i].el.getHeight();
23859 //if (this.toolbars[i].footer) {
23860 // tbh += this.toolbars[i].footer.el.getHeight();
23868 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23869 ah -= 5; // knock a few pixes off for look..
23870 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23874 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23875 this.editorcore.onResize(ew,eh);
23880 * Toggles the editor between standard and source edit mode.
23881 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23883 toggleSourceEdit : function(sourceEditMode)
23885 this.editorcore.toggleSourceEdit(sourceEditMode);
23887 if(this.editorcore.sourceEditMode){
23888 Roo.log('editor - showing textarea');
23891 // Roo.log(this.syncValue());
23893 this.inputEl().removeClass(['hide', 'x-hidden']);
23894 this.inputEl().dom.removeAttribute('tabIndex');
23895 this.inputEl().focus();
23897 Roo.log('editor - hiding textarea');
23899 // Roo.log(this.pushValue());
23902 this.inputEl().addClass(['hide', 'x-hidden']);
23903 this.inputEl().dom.setAttribute('tabIndex', -1);
23904 //this.deferFocus();
23907 if(this.resizable){
23908 this.setSize(this.wrap.getSize());
23911 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23914 // private (for BoxComponent)
23915 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23917 // private (for BoxComponent)
23918 getResizeEl : function(){
23922 // private (for BoxComponent)
23923 getPositionEl : function(){
23928 initEvents : function(){
23929 this.originalValue = this.getValue();
23933 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23936 // markInvalid : Roo.emptyFn,
23938 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23941 // clearInvalid : Roo.emptyFn,
23943 setValue : function(v){
23944 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23945 this.editorcore.pushValue();
23950 deferFocus : function(){
23951 this.focus.defer(10, this);
23955 focus : function(){
23956 this.editorcore.focus();
23962 onDestroy : function(){
23968 for (var i =0; i < this.toolbars.length;i++) {
23969 // fixme - ask toolbars for heights?
23970 this.toolbars[i].onDestroy();
23973 this.wrap.dom.innerHTML = '';
23974 this.wrap.remove();
23979 onFirstFocus : function(){
23980 //Roo.log("onFirstFocus");
23981 this.editorcore.onFirstFocus();
23982 for (var i =0; i < this.toolbars.length;i++) {
23983 this.toolbars[i].onFirstFocus();
23989 syncValue : function()
23991 this.editorcore.syncValue();
23994 pushValue : function()
23996 this.editorcore.pushValue();
24000 // hide stuff that is not compatible
24014 * @event specialkey
24018 * @cfg {String} fieldClass @hide
24021 * @cfg {String} focusClass @hide
24024 * @cfg {String} autoCreate @hide
24027 * @cfg {String} inputType @hide
24031 * @cfg {String} invalidText @hide
24034 * @cfg {String} msgFx @hide
24037 * @cfg {String} validateOnBlur @hide
24046 Roo.namespace('Roo.bootstrap.htmleditor');
24048 * @class Roo.bootstrap.HtmlEditorToolbar1
24053 new Roo.bootstrap.HtmlEditor({
24056 new Roo.bootstrap.HtmlEditorToolbar1({
24057 disable : { fonts: 1 , format: 1, ..., ... , ...],
24063 * @cfg {Object} disable List of elements to disable..
24064 * @cfg {Array} btns List of additional buttons.
24068 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24071 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24074 Roo.apply(this, config);
24076 // default disabled, based on 'good practice'..
24077 this.disable = this.disable || {};
24078 Roo.applyIf(this.disable, {
24081 specialElements : true
24083 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24085 this.editor = config.editor;
24086 this.editorcore = config.editor.editorcore;
24088 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24090 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24091 // dont call parent... till later.
24093 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24098 editorcore : false,
24103 "h1","h2","h3","h4","h5","h6",
24105 "abbr", "acronym", "address", "cite", "samp", "var",
24109 onRender : function(ct, position)
24111 // Roo.log("Call onRender: " + this.xtype);
24113 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24115 this.el.dom.style.marginBottom = '0';
24117 var editorcore = this.editorcore;
24118 var editor= this.editor;
24121 var btn = function(id,cmd , toggle, handler, html){
24123 var event = toggle ? 'toggle' : 'click';
24128 xns: Roo.bootstrap,
24132 enableToggle:toggle !== false,
24134 pressed : toggle ? false : null,
24137 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24138 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24144 // var cb_box = function...
24149 xns: Roo.bootstrap,
24154 xns: Roo.bootstrap,
24158 Roo.each(this.formats, function(f) {
24159 style.menu.items.push({
24161 xns: Roo.bootstrap,
24162 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24167 editorcore.insertTag(this.tagname);
24174 children.push(style);
24176 btn('bold',false,true);
24177 btn('italic',false,true);
24178 btn('align-left', 'justifyleft',true);
24179 btn('align-center', 'justifycenter',true);
24180 btn('align-right' , 'justifyright',true);
24181 btn('link', false, false, function(btn) {
24182 //Roo.log("create link?");
24183 var url = prompt(this.createLinkText, this.defaultLinkValue);
24184 if(url && url != 'http:/'+'/'){
24185 this.editorcore.relayCmd('createlink', url);
24188 btn('list','insertunorderedlist',true);
24189 btn('pencil', false,true, function(btn){
24191 this.toggleSourceEdit(btn.pressed);
24194 if (this.editor.btns.length > 0) {
24195 for (var i = 0; i<this.editor.btns.length; i++) {
24196 children.push(this.editor.btns[i]);
24204 xns: Roo.bootstrap,
24209 xns: Roo.bootstrap,
24214 cog.menu.items.push({
24216 xns: Roo.bootstrap,
24217 html : Clean styles,
24222 editorcore.insertTag(this.tagname);
24231 this.xtype = 'NavSimplebar';
24233 for(var i=0;i< children.length;i++) {
24235 this.buttons.add(this.addxtypeChild(children[i]));
24239 editor.on('editorevent', this.updateToolbar, this);
24241 onBtnClick : function(id)
24243 this.editorcore.relayCmd(id);
24244 this.editorcore.focus();
24248 * Protected method that will not generally be called directly. It triggers
24249 * a toolbar update by reading the markup state of the current selection in the editor.
24251 updateToolbar: function(){
24253 if(!this.editorcore.activated){
24254 this.editor.onFirstFocus(); // is this neeed?
24258 var btns = this.buttons;
24259 var doc = this.editorcore.doc;
24260 btns.get('bold').setActive(doc.queryCommandState('bold'));
24261 btns.get('italic').setActive(doc.queryCommandState('italic'));
24262 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24264 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24265 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24266 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24268 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24269 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24272 var ans = this.editorcore.getAllAncestors();
24273 if (this.formatCombo) {
24276 var store = this.formatCombo.store;
24277 this.formatCombo.setValue("");
24278 for (var i =0; i < ans.length;i++) {
24279 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24281 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24289 // hides menus... - so this cant be on a menu...
24290 Roo.bootstrap.MenuMgr.hideAll();
24292 Roo.bootstrap.MenuMgr.hideAll();
24293 //this.editorsyncValue();
24295 onFirstFocus: function() {
24296 this.buttons.each(function(item){
24300 toggleSourceEdit : function(sourceEditMode){
24303 if(sourceEditMode){
24304 Roo.log("disabling buttons");
24305 this.buttons.each( function(item){
24306 if(item.cmd != 'pencil'){
24312 Roo.log("enabling buttons");
24313 if(this.editorcore.initialized){
24314 this.buttons.each( function(item){
24320 Roo.log("calling toggole on editor");
24321 // tell the editor that it's been pressed..
24322 this.editor.toggleSourceEdit(sourceEditMode);
24332 * @class Roo.bootstrap.Table.AbstractSelectionModel
24333 * @extends Roo.util.Observable
24334 * Abstract base class for grid SelectionModels. It provides the interface that should be
24335 * implemented by descendant classes. This class should not be directly instantiated.
24338 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24339 this.locked = false;
24340 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24344 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24345 /** @ignore Called by the grid automatically. Do not call directly. */
24346 init : function(grid){
24352 * Locks the selections.
24355 this.locked = true;
24359 * Unlocks the selections.
24361 unlock : function(){
24362 this.locked = false;
24366 * Returns true if the selections are locked.
24367 * @return {Boolean}
24369 isLocked : function(){
24370 return this.locked;
24374 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24375 * @class Roo.bootstrap.Table.RowSelectionModel
24376 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24377 * It supports multiple selections and keyboard selection/navigation.
24379 * @param {Object} config
24382 Roo.bootstrap.Table.RowSelectionModel = function(config){
24383 Roo.apply(this, config);
24384 this.selections = new Roo.util.MixedCollection(false, function(o){
24389 this.lastActive = false;
24393 * @event selectionchange
24394 * Fires when the selection changes
24395 * @param {SelectionModel} this
24397 "selectionchange" : true,
24399 * @event afterselectionchange
24400 * Fires after the selection changes (eg. by key press or clicking)
24401 * @param {SelectionModel} this
24403 "afterselectionchange" : true,
24405 * @event beforerowselect
24406 * Fires when a row is selected being selected, return false to cancel.
24407 * @param {SelectionModel} this
24408 * @param {Number} rowIndex The selected index
24409 * @param {Boolean} keepExisting False if other selections will be cleared
24411 "beforerowselect" : true,
24414 * Fires when a row is selected.
24415 * @param {SelectionModel} this
24416 * @param {Number} rowIndex The selected index
24417 * @param {Roo.data.Record} r The record
24419 "rowselect" : true,
24421 * @event rowdeselect
24422 * Fires when a row is deselected.
24423 * @param {SelectionModel} this
24424 * @param {Number} rowIndex The selected index
24426 "rowdeselect" : true
24428 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24429 this.locked = false;
24432 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24434 * @cfg {Boolean} singleSelect
24435 * True to allow selection of only one row at a time (defaults to false)
24437 singleSelect : false,
24440 initEvents : function()
24443 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24444 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24445 //}else{ // allow click to work like normal
24446 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24448 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24449 this.grid.on("rowclick", this.handleMouseDown, this);
24451 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24452 "up" : function(e){
24454 this.selectPrevious(e.shiftKey);
24455 }else if(this.last !== false && this.lastActive !== false){
24456 var last = this.last;
24457 this.selectRange(this.last, this.lastActive-1);
24458 this.grid.getView().focusRow(this.lastActive);
24459 if(last !== false){
24463 this.selectFirstRow();
24465 this.fireEvent("afterselectionchange", this);
24467 "down" : function(e){
24469 this.selectNext(e.shiftKey);
24470 }else if(this.last !== false && this.lastActive !== false){
24471 var last = this.last;
24472 this.selectRange(this.last, this.lastActive+1);
24473 this.grid.getView().focusRow(this.lastActive);
24474 if(last !== false){
24478 this.selectFirstRow();
24480 this.fireEvent("afterselectionchange", this);
24484 this.grid.store.on('load', function(){
24485 this.selections.clear();
24488 var view = this.grid.view;
24489 view.on("refresh", this.onRefresh, this);
24490 view.on("rowupdated", this.onRowUpdated, this);
24491 view.on("rowremoved", this.onRemove, this);
24496 onRefresh : function()
24498 var ds = this.grid.store, i, v = this.grid.view;
24499 var s = this.selections;
24500 s.each(function(r){
24501 if((i = ds.indexOfId(r.id)) != -1){
24510 onRemove : function(v, index, r){
24511 this.selections.remove(r);
24515 onRowUpdated : function(v, index, r){
24516 if(this.isSelected(r)){
24517 v.onRowSelect(index);
24523 * @param {Array} records The records to select
24524 * @param {Boolean} keepExisting (optional) True to keep existing selections
24526 selectRecords : function(records, keepExisting)
24529 this.clearSelections();
24531 var ds = this.grid.store;
24532 for(var i = 0, len = records.length; i < len; i++){
24533 this.selectRow(ds.indexOf(records[i]), true);
24538 * Gets the number of selected rows.
24541 getCount : function(){
24542 return this.selections.length;
24546 * Selects the first row in the grid.
24548 selectFirstRow : function(){
24553 * Select the last row.
24554 * @param {Boolean} keepExisting (optional) True to keep existing selections
24556 selectLastRow : function(keepExisting){
24557 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24558 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24562 * Selects the row immediately following the last selected row.
24563 * @param {Boolean} keepExisting (optional) True to keep existing selections
24565 selectNext : function(keepExisting)
24567 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24568 this.selectRow(this.last+1, keepExisting);
24569 this.grid.getView().focusRow(this.last);
24574 * Selects the row that precedes the last selected row.
24575 * @param {Boolean} keepExisting (optional) True to keep existing selections
24577 selectPrevious : function(keepExisting){
24579 this.selectRow(this.last-1, keepExisting);
24580 this.grid.getView().focusRow(this.last);
24585 * Returns the selected records
24586 * @return {Array} Array of selected records
24588 getSelections : function(){
24589 return [].concat(this.selections.items);
24593 * Returns the first selected record.
24596 getSelected : function(){
24597 return this.selections.itemAt(0);
24602 * Clears all selections.
24604 clearSelections : function(fast)
24610 var ds = this.grid.store;
24611 var s = this.selections;
24612 s.each(function(r){
24613 this.deselectRow(ds.indexOfId(r.id));
24617 this.selections.clear();
24624 * Selects all rows.
24626 selectAll : function(){
24630 this.selections.clear();
24631 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24632 this.selectRow(i, true);
24637 * Returns True if there is a selection.
24638 * @return {Boolean}
24640 hasSelection : function(){
24641 return this.selections.length > 0;
24645 * Returns True if the specified row is selected.
24646 * @param {Number/Record} record The record or index of the record to check
24647 * @return {Boolean}
24649 isSelected : function(index){
24650 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24651 return (r && this.selections.key(r.id) ? true : false);
24655 * Returns True if the specified record id is selected.
24656 * @param {String} id The id of record to check
24657 * @return {Boolean}
24659 isIdSelected : function(id){
24660 return (this.selections.key(id) ? true : false);
24665 handleMouseDBClick : function(e, t){
24669 handleMouseDown : function(e, t)
24671 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24672 if(this.isLocked() || rowIndex < 0 ){
24675 if(e.shiftKey && this.last !== false){
24676 var last = this.last;
24677 this.selectRange(last, rowIndex, e.ctrlKey);
24678 this.last = last; // reset the last
24682 var isSelected = this.isSelected(rowIndex);
24683 //Roo.log("select row:" + rowIndex);
24685 this.deselectRow(rowIndex);
24687 this.selectRow(rowIndex, true);
24691 if(e.button !== 0 && isSelected){
24692 alert('rowIndex 2: ' + rowIndex);
24693 view.focusRow(rowIndex);
24694 }else if(e.ctrlKey && isSelected){
24695 this.deselectRow(rowIndex);
24696 }else if(!isSelected){
24697 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24698 view.focusRow(rowIndex);
24702 this.fireEvent("afterselectionchange", this);
24705 handleDragableRowClick : function(grid, rowIndex, e)
24707 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24708 this.selectRow(rowIndex, false);
24709 grid.view.focusRow(rowIndex);
24710 this.fireEvent("afterselectionchange", this);
24715 * Selects multiple rows.
24716 * @param {Array} rows Array of the indexes of the row to select
24717 * @param {Boolean} keepExisting (optional) True to keep existing selections
24719 selectRows : function(rows, keepExisting){
24721 this.clearSelections();
24723 for(var i = 0, len = rows.length; i < len; i++){
24724 this.selectRow(rows[i], true);
24729 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24730 * @param {Number} startRow The index of the first row in the range
24731 * @param {Number} endRow The index of the last row in the range
24732 * @param {Boolean} keepExisting (optional) True to retain existing selections
24734 selectRange : function(startRow, endRow, keepExisting){
24739 this.clearSelections();
24741 if(startRow <= endRow){
24742 for(var i = startRow; i <= endRow; i++){
24743 this.selectRow(i, true);
24746 for(var i = startRow; i >= endRow; i--){
24747 this.selectRow(i, true);
24753 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24754 * @param {Number} startRow The index of the first row in the range
24755 * @param {Number} endRow The index of the last row in the range
24757 deselectRange : function(startRow, endRow, preventViewNotify){
24761 for(var i = startRow; i <= endRow; i++){
24762 this.deselectRow(i, preventViewNotify);
24768 * @param {Number} row The index of the row to select
24769 * @param {Boolean} keepExisting (optional) True to keep existing selections
24771 selectRow : function(index, keepExisting, preventViewNotify)
24773 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24776 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24777 if(!keepExisting || this.singleSelect){
24778 this.clearSelections();
24781 var r = this.grid.store.getAt(index);
24782 //console.log('selectRow - record id :' + r.id);
24784 this.selections.add(r);
24785 this.last = this.lastActive = index;
24786 if(!preventViewNotify){
24787 var proxy = new Roo.Element(
24788 this.grid.getRowDom(index)
24790 proxy.addClass('bg-info info');
24792 this.fireEvent("rowselect", this, index, r);
24793 this.fireEvent("selectionchange", this);
24799 * @param {Number} row The index of the row to deselect
24801 deselectRow : function(index, preventViewNotify)
24806 if(this.last == index){
24809 if(this.lastActive == index){
24810 this.lastActive = false;
24813 var r = this.grid.store.getAt(index);
24818 this.selections.remove(r);
24819 //.console.log('deselectRow - record id :' + r.id);
24820 if(!preventViewNotify){
24822 var proxy = new Roo.Element(
24823 this.grid.getRowDom(index)
24825 proxy.removeClass('bg-info info');
24827 this.fireEvent("rowdeselect", this, index);
24828 this.fireEvent("selectionchange", this);
24832 restoreLast : function(){
24834 this.last = this._last;
24839 acceptsNav : function(row, col, cm){
24840 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24844 onEditorKey : function(field, e){
24845 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24850 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24852 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24854 }else if(k == e.ENTER && !e.ctrlKey){
24858 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24860 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24862 }else if(k == e.ESC){
24866 g.startEditing(newCell[0], newCell[1]);
24872 * Ext JS Library 1.1.1
24873 * Copyright(c) 2006-2007, Ext JS, LLC.
24875 * Originally Released Under LGPL - original licence link has changed is not relivant.
24878 * <script type="text/javascript">
24882 * @class Roo.bootstrap.PagingToolbar
24883 * @extends Roo.bootstrap.NavSimplebar
24884 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24886 * Create a new PagingToolbar
24887 * @param {Object} config The config object
24888 * @param {Roo.data.Store} store
24890 Roo.bootstrap.PagingToolbar = function(config)
24892 // old args format still supported... - xtype is prefered..
24893 // created from xtype...
24895 this.ds = config.dataSource;
24897 if (config.store && !this.ds) {
24898 this.store= Roo.factory(config.store, Roo.data);
24899 this.ds = this.store;
24900 this.ds.xmodule = this.xmodule || false;
24903 this.toolbarItems = [];
24904 if (config.items) {
24905 this.toolbarItems = config.items;
24908 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24913 this.bind(this.ds);
24916 if (Roo.bootstrap.version == 4) {
24917 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24919 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24924 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24926 * @cfg {Roo.data.Store} dataSource
24927 * The underlying data store providing the paged data
24930 * @cfg {String/HTMLElement/Element} container
24931 * container The id or element that will contain the toolbar
24934 * @cfg {Boolean} displayInfo
24935 * True to display the displayMsg (defaults to false)
24938 * @cfg {Number} pageSize
24939 * The number of records to display per page (defaults to 20)
24943 * @cfg {String} displayMsg
24944 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24946 displayMsg : 'Displaying {0} - {1} of {2}',
24948 * @cfg {String} emptyMsg
24949 * The message to display when no records are found (defaults to "No data to display")
24951 emptyMsg : 'No data to display',
24953 * Customizable piece of the default paging text (defaults to "Page")
24956 beforePageText : "Page",
24958 * Customizable piece of the default paging text (defaults to "of %0")
24961 afterPageText : "of {0}",
24963 * Customizable piece of the default paging text (defaults to "First Page")
24966 firstText : "First Page",
24968 * Customizable piece of the default paging text (defaults to "Previous Page")
24971 prevText : "Previous Page",
24973 * Customizable piece of the default paging text (defaults to "Next Page")
24976 nextText : "Next Page",
24978 * Customizable piece of the default paging text (defaults to "Last Page")
24981 lastText : "Last Page",
24983 * Customizable piece of the default paging text (defaults to "Refresh")
24986 refreshText : "Refresh",
24990 onRender : function(ct, position)
24992 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24993 this.navgroup.parentId = this.id;
24994 this.navgroup.onRender(this.el, null);
24995 // add the buttons to the navgroup
24997 if(this.displayInfo){
24998 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24999 this.displayEl = this.el.select('.x-paging-info', true).first();
25000 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
25001 // this.displayEl = navel.el.select('span',true).first();
25007 Roo.each(_this.buttons, function(e){ // this might need to use render????
25008 Roo.factory(e).render(_this.el);
25012 Roo.each(_this.toolbarItems, function(e) {
25013 _this.navgroup.addItem(e);
25017 this.first = this.navgroup.addItem({
25018 tooltip: this.firstText,
25019 cls: "prev btn-outline-secondary",
25020 html : ' <i class="fa fa-step-backward"></i>',
25022 preventDefault: true,
25023 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25026 this.prev = this.navgroup.addItem({
25027 tooltip: this.prevText,
25028 cls: "prev btn-outline-secondary",
25029 html : ' <i class="fa fa-backward"></i>',
25031 preventDefault: true,
25032 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25034 //this.addSeparator();
25037 var field = this.navgroup.addItem( {
25039 cls : 'x-paging-position btn-outline-secondary',
25041 html : this.beforePageText +
25042 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25043 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25046 this.field = field.el.select('input', true).first();
25047 this.field.on("keydown", this.onPagingKeydown, this);
25048 this.field.on("focus", function(){this.dom.select();});
25051 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25052 //this.field.setHeight(18);
25053 //this.addSeparator();
25054 this.next = this.navgroup.addItem({
25055 tooltip: this.nextText,
25056 cls: "next btn-outline-secondary",
25057 html : ' <i class="fa fa-forward"></i>',
25059 preventDefault: true,
25060 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25062 this.last = this.navgroup.addItem({
25063 tooltip: this.lastText,
25064 html : ' <i class="fa fa-step-forward"></i>',
25065 cls: "next btn-outline-secondary",
25067 preventDefault: true,
25068 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25070 //this.addSeparator();
25071 this.loading = this.navgroup.addItem({
25072 tooltip: this.refreshText,
25073 cls: "btn-outline-secondary",
25074 html : ' <i class="fa fa-refresh"></i>',
25075 preventDefault: true,
25076 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25082 updateInfo : function(){
25083 if(this.displayEl){
25084 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25085 var msg = count == 0 ?
25089 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25091 this.displayEl.update(msg);
25096 onLoad : function(ds, r, o)
25098 this.cursor = o.params.start ? o.params.start : 0;
25100 var d = this.getPageData(),
25105 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25106 this.field.dom.value = ap;
25107 this.first.setDisabled(ap == 1);
25108 this.prev.setDisabled(ap == 1);
25109 this.next.setDisabled(ap == ps);
25110 this.last.setDisabled(ap == ps);
25111 this.loading.enable();
25116 getPageData : function(){
25117 var total = this.ds.getTotalCount();
25120 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25121 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25126 onLoadError : function(){
25127 this.loading.enable();
25131 onPagingKeydown : function(e){
25132 var k = e.getKey();
25133 var d = this.getPageData();
25135 var v = this.field.dom.value, pageNum;
25136 if(!v || isNaN(pageNum = parseInt(v, 10))){
25137 this.field.dom.value = d.activePage;
25140 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25141 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25144 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))
25146 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25147 this.field.dom.value = pageNum;
25148 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25151 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25153 var v = this.field.dom.value, pageNum;
25154 var increment = (e.shiftKey) ? 10 : 1;
25155 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25158 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25159 this.field.dom.value = d.activePage;
25162 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25164 this.field.dom.value = parseInt(v, 10) + increment;
25165 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25166 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25173 beforeLoad : function(){
25175 this.loading.disable();
25180 onClick : function(which){
25189 ds.load({params:{start: 0, limit: this.pageSize}});
25192 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25195 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25198 var total = ds.getTotalCount();
25199 var extra = total % this.pageSize;
25200 var lastStart = extra ? (total - extra) : total-this.pageSize;
25201 ds.load({params:{start: lastStart, limit: this.pageSize}});
25204 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25210 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25211 * @param {Roo.data.Store} store The data store to unbind
25213 unbind : function(ds){
25214 ds.un("beforeload", this.beforeLoad, this);
25215 ds.un("load", this.onLoad, this);
25216 ds.un("loadexception", this.onLoadError, this);
25217 ds.un("remove", this.updateInfo, this);
25218 ds.un("add", this.updateInfo, this);
25219 this.ds = undefined;
25223 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25224 * @param {Roo.data.Store} store The data store to bind
25226 bind : function(ds){
25227 ds.on("beforeload", this.beforeLoad, this);
25228 ds.on("load", this.onLoad, this);
25229 ds.on("loadexception", this.onLoadError, this);
25230 ds.on("remove", this.updateInfo, this);
25231 ds.on("add", this.updateInfo, this);
25242 * @class Roo.bootstrap.MessageBar
25243 * @extends Roo.bootstrap.Component
25244 * Bootstrap MessageBar class
25245 * @cfg {String} html contents of the MessageBar
25246 * @cfg {String} weight (info | success | warning | danger) default info
25247 * @cfg {String} beforeClass insert the bar before the given class
25248 * @cfg {Boolean} closable (true | false) default false
25249 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25252 * Create a new Element
25253 * @param {Object} config The config object
25256 Roo.bootstrap.MessageBar = function(config){
25257 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25260 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25266 beforeClass: 'bootstrap-sticky-wrap',
25268 getAutoCreate : function(){
25272 cls: 'alert alert-dismissable alert-' + this.weight,
25277 html: this.html || ''
25283 cfg.cls += ' alert-messages-fixed';
25297 onRender : function(ct, position)
25299 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25302 var cfg = Roo.apply({}, this.getAutoCreate());
25306 cfg.cls += ' ' + this.cls;
25309 cfg.style = this.style;
25311 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25313 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25316 this.el.select('>button.close').on('click', this.hide, this);
25322 if (!this.rendered) {
25328 this.fireEvent('show', this);
25334 if (!this.rendered) {
25340 this.fireEvent('hide', this);
25343 update : function()
25345 // var e = this.el.dom.firstChild;
25347 // if(this.closable){
25348 // e = e.nextSibling;
25351 // e.data = this.html || '';
25353 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25369 * @class Roo.bootstrap.Graph
25370 * @extends Roo.bootstrap.Component
25371 * Bootstrap Graph class
25375 @cfg {String} graphtype bar | vbar | pie
25376 @cfg {number} g_x coodinator | centre x (pie)
25377 @cfg {number} g_y coodinator | centre y (pie)
25378 @cfg {number} g_r radius (pie)
25379 @cfg {number} g_height height of the chart (respected by all elements in the set)
25380 @cfg {number} g_width width of the chart (respected by all elements in the set)
25381 @cfg {Object} title The title of the chart
25384 -opts (object) options for the chart
25386 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25387 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25389 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.
25390 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25392 o stretch (boolean)
25394 -opts (object) options for the pie
25397 o startAngle (number)
25398 o endAngle (number)
25402 * Create a new Input
25403 * @param {Object} config The config object
25406 Roo.bootstrap.Graph = function(config){
25407 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25413 * The img click event for the img.
25414 * @param {Roo.EventObject} e
25420 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25431 //g_colors: this.colors,
25438 getAutoCreate : function(){
25449 onRender : function(ct,position){
25452 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25454 if (typeof(Raphael) == 'undefined') {
25455 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25459 this.raphael = Raphael(this.el.dom);
25461 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25462 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25463 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25464 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25466 r.text(160, 10, "Single Series Chart").attr(txtattr);
25467 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25468 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25469 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25471 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25472 r.barchart(330, 10, 300, 220, data1);
25473 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25474 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25477 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25478 // r.barchart(30, 30, 560, 250, xdata, {
25479 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25480 // axis : "0 0 1 1",
25481 // axisxlabels : xdata
25482 // //yvalues : cols,
25485 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25487 // this.load(null,xdata,{
25488 // axis : "0 0 1 1",
25489 // axisxlabels : xdata
25494 load : function(graphtype,xdata,opts)
25496 this.raphael.clear();
25498 graphtype = this.graphtype;
25503 var r = this.raphael,
25504 fin = function () {
25505 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25507 fout = function () {
25508 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25510 pfin = function() {
25511 this.sector.stop();
25512 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25515 this.label[0].stop();
25516 this.label[0].attr({ r: 7.5 });
25517 this.label[1].attr({ "font-weight": 800 });
25520 pfout = function() {
25521 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25524 this.label[0].animate({ r: 5 }, 500, "bounce");
25525 this.label[1].attr({ "font-weight": 400 });
25531 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25534 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25537 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25538 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25540 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25547 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25552 setTitle: function(o)
25557 initEvents: function() {
25560 this.el.on('click', this.onClick, this);
25564 onClick : function(e)
25566 Roo.log('img onclick');
25567 this.fireEvent('click', this, e);
25579 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25582 * @class Roo.bootstrap.dash.NumberBox
25583 * @extends Roo.bootstrap.Component
25584 * Bootstrap NumberBox class
25585 * @cfg {String} headline Box headline
25586 * @cfg {String} content Box content
25587 * @cfg {String} icon Box icon
25588 * @cfg {String} footer Footer text
25589 * @cfg {String} fhref Footer href
25592 * Create a new NumberBox
25593 * @param {Object} config The config object
25597 Roo.bootstrap.dash.NumberBox = function(config){
25598 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25602 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25611 getAutoCreate : function(){
25615 cls : 'small-box ',
25623 cls : 'roo-headline',
25624 html : this.headline
25628 cls : 'roo-content',
25629 html : this.content
25643 cls : 'ion ' + this.icon
25652 cls : 'small-box-footer',
25653 href : this.fhref || '#',
25657 cfg.cn.push(footer);
25664 onRender : function(ct,position){
25665 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25672 setHeadline: function (value)
25674 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25677 setFooter: function (value, href)
25679 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25682 this.el.select('a.small-box-footer',true).first().attr('href', href);
25687 setContent: function (value)
25689 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25692 initEvents: function()
25706 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25709 * @class Roo.bootstrap.dash.TabBox
25710 * @extends Roo.bootstrap.Component
25711 * Bootstrap TabBox class
25712 * @cfg {String} title Title of the TabBox
25713 * @cfg {String} icon Icon of the TabBox
25714 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25715 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25718 * Create a new TabBox
25719 * @param {Object} config The config object
25723 Roo.bootstrap.dash.TabBox = function(config){
25724 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25729 * When a pane is added
25730 * @param {Roo.bootstrap.dash.TabPane} pane
25734 * @event activatepane
25735 * When a pane is activated
25736 * @param {Roo.bootstrap.dash.TabPane} pane
25738 "activatepane" : true
25746 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25751 tabScrollable : false,
25753 getChildContainer : function()
25755 return this.el.select('.tab-content', true).first();
25758 getAutoCreate : function(){
25762 cls: 'pull-left header',
25770 cls: 'fa ' + this.icon
25776 cls: 'nav nav-tabs pull-right',
25782 if(this.tabScrollable){
25789 cls: 'nav nav-tabs pull-right',
25800 cls: 'nav-tabs-custom',
25805 cls: 'tab-content no-padding',
25813 initEvents : function()
25815 //Roo.log('add add pane handler');
25816 this.on('addpane', this.onAddPane, this);
25819 * Updates the box title
25820 * @param {String} html to set the title to.
25822 setTitle : function(value)
25824 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25826 onAddPane : function(pane)
25828 this.panes.push(pane);
25829 //Roo.log('addpane');
25831 // tabs are rendere left to right..
25832 if(!this.showtabs){
25836 var ctr = this.el.select('.nav-tabs', true).first();
25839 var existing = ctr.select('.nav-tab',true);
25840 var qty = existing.getCount();;
25843 var tab = ctr.createChild({
25845 cls : 'nav-tab' + (qty ? '' : ' active'),
25853 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25856 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25858 pane.el.addClass('active');
25863 onTabClick : function(ev,un,ob,pane)
25865 //Roo.log('tab - prev default');
25866 ev.preventDefault();
25869 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25870 pane.tab.addClass('active');
25871 //Roo.log(pane.title);
25872 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25873 // technically we should have a deactivate event.. but maybe add later.
25874 // and it should not de-activate the selected tab...
25875 this.fireEvent('activatepane', pane);
25876 pane.el.addClass('active');
25877 pane.fireEvent('activate');
25882 getActivePane : function()
25885 Roo.each(this.panes, function(p) {
25886 if(p.el.hasClass('active')){
25907 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25909 * @class Roo.bootstrap.TabPane
25910 * @extends Roo.bootstrap.Component
25911 * Bootstrap TabPane class
25912 * @cfg {Boolean} active (false | true) Default false
25913 * @cfg {String} title title of panel
25917 * Create a new TabPane
25918 * @param {Object} config The config object
25921 Roo.bootstrap.dash.TabPane = function(config){
25922 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25928 * When a pane is activated
25929 * @param {Roo.bootstrap.dash.TabPane} pane
25936 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25941 // the tabBox that this is attached to.
25944 getAutoCreate : function()
25952 cfg.cls += ' active';
25957 initEvents : function()
25959 //Roo.log('trigger add pane handler');
25960 this.parent().fireEvent('addpane', this)
25964 * Updates the tab title
25965 * @param {String} html to set the title to.
25967 setTitle: function(str)
25973 this.tab.select('a', true).first().dom.innerHTML = str;
25990 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25993 * @class Roo.bootstrap.menu.Menu
25994 * @extends Roo.bootstrap.Component
25995 * Bootstrap Menu class - container for Menu
25996 * @cfg {String} html Text of the menu
25997 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25998 * @cfg {String} icon Font awesome icon
25999 * @cfg {String} pos Menu align to (top | bottom) default bottom
26003 * Create a new Menu
26004 * @param {Object} config The config object
26008 Roo.bootstrap.menu.Menu = function(config){
26009 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26013 * @event beforeshow
26014 * Fires before this menu is displayed
26015 * @param {Roo.bootstrap.menu.Menu} this
26019 * @event beforehide
26020 * Fires before this menu is hidden
26021 * @param {Roo.bootstrap.menu.Menu} this
26026 * Fires after this menu is displayed
26027 * @param {Roo.bootstrap.menu.Menu} this
26032 * Fires after this menu is hidden
26033 * @param {Roo.bootstrap.menu.Menu} this
26038 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26039 * @param {Roo.bootstrap.menu.Menu} this
26040 * @param {Roo.EventObject} e
26047 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26051 weight : 'default',
26056 getChildContainer : function() {
26057 if(this.isSubMenu){
26061 return this.el.select('ul.dropdown-menu', true).first();
26064 getAutoCreate : function()
26069 cls : 'roo-menu-text',
26077 cls : 'fa ' + this.icon
26088 cls : 'dropdown-button btn btn-' + this.weight,
26093 cls : 'dropdown-toggle btn btn-' + this.weight,
26103 cls : 'dropdown-menu'
26109 if(this.pos == 'top'){
26110 cfg.cls += ' dropup';
26113 if(this.isSubMenu){
26116 cls : 'dropdown-menu'
26123 onRender : function(ct, position)
26125 this.isSubMenu = ct.hasClass('dropdown-submenu');
26127 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26130 initEvents : function()
26132 if(this.isSubMenu){
26136 this.hidden = true;
26138 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26139 this.triggerEl.on('click', this.onTriggerPress, this);
26141 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26142 this.buttonEl.on('click', this.onClick, this);
26148 if(this.isSubMenu){
26152 return this.el.select('ul.dropdown-menu', true).first();
26155 onClick : function(e)
26157 this.fireEvent("click", this, e);
26160 onTriggerPress : function(e)
26162 if (this.isVisible()) {
26169 isVisible : function(){
26170 return !this.hidden;
26175 this.fireEvent("beforeshow", this);
26177 this.hidden = false;
26178 this.el.addClass('open');
26180 Roo.get(document).on("mouseup", this.onMouseUp, this);
26182 this.fireEvent("show", this);
26189 this.fireEvent("beforehide", this);
26191 this.hidden = true;
26192 this.el.removeClass('open');
26194 Roo.get(document).un("mouseup", this.onMouseUp);
26196 this.fireEvent("hide", this);
26199 onMouseUp : function()
26213 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26216 * @class Roo.bootstrap.menu.Item
26217 * @extends Roo.bootstrap.Component
26218 * Bootstrap MenuItem class
26219 * @cfg {Boolean} submenu (true | false) default false
26220 * @cfg {String} html text of the item
26221 * @cfg {String} href the link
26222 * @cfg {Boolean} disable (true | false) default false
26223 * @cfg {Boolean} preventDefault (true | false) default true
26224 * @cfg {String} icon Font awesome icon
26225 * @cfg {String} pos Submenu align to (left | right) default right
26229 * Create a new Item
26230 * @param {Object} config The config object
26234 Roo.bootstrap.menu.Item = function(config){
26235 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26239 * Fires when the mouse is hovering over this menu
26240 * @param {Roo.bootstrap.menu.Item} this
26241 * @param {Roo.EventObject} e
26246 * Fires when the mouse exits this menu
26247 * @param {Roo.bootstrap.menu.Item} this
26248 * @param {Roo.EventObject} e
26254 * The raw click event for the entire grid.
26255 * @param {Roo.EventObject} e
26261 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26266 preventDefault: true,
26271 getAutoCreate : function()
26276 cls : 'roo-menu-item-text',
26284 cls : 'fa ' + this.icon
26293 href : this.href || '#',
26300 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26304 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26306 if(this.pos == 'left'){
26307 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26314 initEvents : function()
26316 this.el.on('mouseover', this.onMouseOver, this);
26317 this.el.on('mouseout', this.onMouseOut, this);
26319 this.el.select('a', true).first().on('click', this.onClick, this);
26323 onClick : function(e)
26325 if(this.preventDefault){
26326 e.preventDefault();
26329 this.fireEvent("click", this, e);
26332 onMouseOver : function(e)
26334 if(this.submenu && this.pos == 'left'){
26335 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26338 this.fireEvent("mouseover", this, e);
26341 onMouseOut : function(e)
26343 this.fireEvent("mouseout", this, e);
26355 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26358 * @class Roo.bootstrap.menu.Separator
26359 * @extends Roo.bootstrap.Component
26360 * Bootstrap Separator class
26363 * Create a new Separator
26364 * @param {Object} config The config object
26368 Roo.bootstrap.menu.Separator = function(config){
26369 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26372 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26374 getAutoCreate : function(){
26395 * @class Roo.bootstrap.Tooltip
26396 * Bootstrap Tooltip class
26397 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26398 * to determine which dom element triggers the tooltip.
26400 * It needs to add support for additional attributes like tooltip-position
26403 * Create a new Toolti
26404 * @param {Object} config The config object
26407 Roo.bootstrap.Tooltip = function(config){
26408 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26410 this.alignment = Roo.bootstrap.Tooltip.alignment;
26412 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26413 this.alignment = config.alignment;
26418 Roo.apply(Roo.bootstrap.Tooltip, {
26420 * @function init initialize tooltip monitoring.
26424 currentTip : false,
26425 currentRegion : false,
26431 Roo.get(document).on('mouseover', this.enter ,this);
26432 Roo.get(document).on('mouseout', this.leave, this);
26435 this.currentTip = new Roo.bootstrap.Tooltip();
26438 enter : function(ev)
26440 var dom = ev.getTarget();
26442 //Roo.log(['enter',dom]);
26443 var el = Roo.fly(dom);
26444 if (this.currentEl) {
26446 //Roo.log(this.currentEl);
26447 //Roo.log(this.currentEl.contains(dom));
26448 if (this.currentEl == el) {
26451 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26457 if (this.currentTip.el) {
26458 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26462 if(!el || el.dom == document){
26468 // you can not look for children, as if el is the body.. then everythign is the child..
26469 if (!el.attr('tooltip')) { //
26470 if (!el.select("[tooltip]").elements.length) {
26473 // is the mouse over this child...?
26474 bindEl = el.select("[tooltip]").first();
26475 var xy = ev.getXY();
26476 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26477 //Roo.log("not in region.");
26480 //Roo.log("child element over..");
26483 this.currentEl = bindEl;
26484 this.currentTip.bind(bindEl);
26485 this.currentRegion = Roo.lib.Region.getRegion(dom);
26486 this.currentTip.enter();
26489 leave : function(ev)
26491 var dom = ev.getTarget();
26492 //Roo.log(['leave',dom]);
26493 if (!this.currentEl) {
26498 if (dom != this.currentEl.dom) {
26501 var xy = ev.getXY();
26502 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26505 // only activate leave if mouse cursor is outside... bounding box..
26510 if (this.currentTip) {
26511 this.currentTip.leave();
26513 //Roo.log('clear currentEl');
26514 this.currentEl = false;
26519 'left' : ['r-l', [-2,0], 'right'],
26520 'right' : ['l-r', [2,0], 'left'],
26521 'bottom' : ['t-b', [0,2], 'top'],
26522 'top' : [ 'b-t', [0,-2], 'bottom']
26528 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26533 delay : null, // can be { show : 300 , hide: 500}
26537 hoverState : null, //???
26539 placement : 'bottom',
26543 getAutoCreate : function(){
26550 cls : 'tooltip-arrow'
26553 cls : 'tooltip-inner'
26560 bind : function(el)
26566 enter : function () {
26568 if (this.timeout != null) {
26569 clearTimeout(this.timeout);
26572 this.hoverState = 'in';
26573 //Roo.log("enter - show");
26574 if (!this.delay || !this.delay.show) {
26579 this.timeout = setTimeout(function () {
26580 if (_t.hoverState == 'in') {
26583 }, this.delay.show);
26587 clearTimeout(this.timeout);
26589 this.hoverState = 'out';
26590 if (!this.delay || !this.delay.hide) {
26596 this.timeout = setTimeout(function () {
26597 //Roo.log("leave - timeout");
26599 if (_t.hoverState == 'out') {
26601 Roo.bootstrap.Tooltip.currentEl = false;
26606 show : function (msg)
26609 this.render(document.body);
26612 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26614 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26616 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26618 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26620 var placement = typeof this.placement == 'function' ?
26621 this.placement.call(this, this.el, on_el) :
26624 var autoToken = /\s?auto?\s?/i;
26625 var autoPlace = autoToken.test(placement);
26627 placement = placement.replace(autoToken, '') || 'top';
26631 //this.el.setXY([0,0]);
26633 //this.el.dom.style.display='block';
26635 //this.el.appendTo(on_el);
26637 var p = this.getPosition();
26638 var box = this.el.getBox();
26644 var align = this.alignment[placement];
26646 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26648 if(placement == 'top' || placement == 'bottom'){
26650 placement = 'right';
26653 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26654 placement = 'left';
26657 var scroll = Roo.select('body', true).first().getScroll();
26659 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26663 align = this.alignment[placement];
26666 this.el.alignTo(this.bindEl, align[0],align[1]);
26667 //var arrow = this.el.select('.arrow',true).first();
26668 //arrow.set(align[2],
26670 this.el.addClass(placement);
26672 this.el.addClass('in fade');
26674 this.hoverState = null;
26676 if (this.el.hasClass('fade')) {
26687 //this.el.setXY([0,0]);
26688 this.el.removeClass('in');
26704 * @class Roo.bootstrap.LocationPicker
26705 * @extends Roo.bootstrap.Component
26706 * Bootstrap LocationPicker class
26707 * @cfg {Number} latitude Position when init default 0
26708 * @cfg {Number} longitude Position when init default 0
26709 * @cfg {Number} zoom default 15
26710 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26711 * @cfg {Boolean} mapTypeControl default false
26712 * @cfg {Boolean} disableDoubleClickZoom default false
26713 * @cfg {Boolean} scrollwheel default true
26714 * @cfg {Boolean} streetViewControl default false
26715 * @cfg {Number} radius default 0
26716 * @cfg {String} locationName
26717 * @cfg {Boolean} draggable default true
26718 * @cfg {Boolean} enableAutocomplete default false
26719 * @cfg {Boolean} enableReverseGeocode default true
26720 * @cfg {String} markerTitle
26723 * Create a new LocationPicker
26724 * @param {Object} config The config object
26728 Roo.bootstrap.LocationPicker = function(config){
26730 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26735 * Fires when the picker initialized.
26736 * @param {Roo.bootstrap.LocationPicker} this
26737 * @param {Google Location} location
26741 * @event positionchanged
26742 * Fires when the picker position changed.
26743 * @param {Roo.bootstrap.LocationPicker} this
26744 * @param {Google Location} location
26746 positionchanged : true,
26749 * Fires when the map resize.
26750 * @param {Roo.bootstrap.LocationPicker} this
26755 * Fires when the map show.
26756 * @param {Roo.bootstrap.LocationPicker} this
26761 * Fires when the map hide.
26762 * @param {Roo.bootstrap.LocationPicker} this
26767 * Fires when click the map.
26768 * @param {Roo.bootstrap.LocationPicker} this
26769 * @param {Map event} e
26773 * @event mapRightClick
26774 * Fires when right click the map.
26775 * @param {Roo.bootstrap.LocationPicker} this
26776 * @param {Map event} e
26778 mapRightClick : true,
26780 * @event markerClick
26781 * Fires when click the marker.
26782 * @param {Roo.bootstrap.LocationPicker} this
26783 * @param {Map event} e
26785 markerClick : true,
26787 * @event markerRightClick
26788 * Fires when right click the marker.
26789 * @param {Roo.bootstrap.LocationPicker} this
26790 * @param {Map event} e
26792 markerRightClick : true,
26794 * @event OverlayViewDraw
26795 * Fires when OverlayView Draw
26796 * @param {Roo.bootstrap.LocationPicker} this
26798 OverlayViewDraw : true,
26800 * @event OverlayViewOnAdd
26801 * Fires when OverlayView Draw
26802 * @param {Roo.bootstrap.LocationPicker} this
26804 OverlayViewOnAdd : true,
26806 * @event OverlayViewOnRemove
26807 * Fires when OverlayView Draw
26808 * @param {Roo.bootstrap.LocationPicker} this
26810 OverlayViewOnRemove : true,
26812 * @event OverlayViewShow
26813 * Fires when OverlayView Draw
26814 * @param {Roo.bootstrap.LocationPicker} this
26815 * @param {Pixel} cpx
26817 OverlayViewShow : true,
26819 * @event OverlayViewHide
26820 * Fires when OverlayView Draw
26821 * @param {Roo.bootstrap.LocationPicker} this
26823 OverlayViewHide : true,
26825 * @event loadexception
26826 * Fires when load google lib failed.
26827 * @param {Roo.bootstrap.LocationPicker} this
26829 loadexception : true
26834 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26836 gMapContext: false,
26842 mapTypeControl: false,
26843 disableDoubleClickZoom: false,
26845 streetViewControl: false,
26849 enableAutocomplete: false,
26850 enableReverseGeocode: true,
26853 getAutoCreate: function()
26858 cls: 'roo-location-picker'
26864 initEvents: function(ct, position)
26866 if(!this.el.getWidth() || this.isApplied()){
26870 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26875 initial: function()
26877 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26878 this.fireEvent('loadexception', this);
26882 if(!this.mapTypeId){
26883 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26886 this.gMapContext = this.GMapContext();
26888 this.initOverlayView();
26890 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26894 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26895 _this.setPosition(_this.gMapContext.marker.position);
26898 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26899 _this.fireEvent('mapClick', this, event);
26903 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26904 _this.fireEvent('mapRightClick', this, event);
26908 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26909 _this.fireEvent('markerClick', this, event);
26913 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26914 _this.fireEvent('markerRightClick', this, event);
26918 this.setPosition(this.gMapContext.location);
26920 this.fireEvent('initial', this, this.gMapContext.location);
26923 initOverlayView: function()
26927 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26931 _this.fireEvent('OverlayViewDraw', _this);
26936 _this.fireEvent('OverlayViewOnAdd', _this);
26939 onRemove: function()
26941 _this.fireEvent('OverlayViewOnRemove', _this);
26944 show: function(cpx)
26946 _this.fireEvent('OverlayViewShow', _this, cpx);
26951 _this.fireEvent('OverlayViewHide', _this);
26957 fromLatLngToContainerPixel: function(event)
26959 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26962 isApplied: function()
26964 return this.getGmapContext() == false ? false : true;
26967 getGmapContext: function()
26969 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26972 GMapContext: function()
26974 var position = new google.maps.LatLng(this.latitude, this.longitude);
26976 var _map = new google.maps.Map(this.el.dom, {
26979 mapTypeId: this.mapTypeId,
26980 mapTypeControl: this.mapTypeControl,
26981 disableDoubleClickZoom: this.disableDoubleClickZoom,
26982 scrollwheel: this.scrollwheel,
26983 streetViewControl: this.streetViewControl,
26984 locationName: this.locationName,
26985 draggable: this.draggable,
26986 enableAutocomplete: this.enableAutocomplete,
26987 enableReverseGeocode: this.enableReverseGeocode
26990 var _marker = new google.maps.Marker({
26991 position: position,
26993 title: this.markerTitle,
26994 draggable: this.draggable
27001 location: position,
27002 radius: this.radius,
27003 locationName: this.locationName,
27004 addressComponents: {
27005 formatted_address: null,
27006 addressLine1: null,
27007 addressLine2: null,
27009 streetNumber: null,
27013 stateOrProvince: null
27016 domContainer: this.el.dom,
27017 geodecoder: new google.maps.Geocoder()
27021 drawCircle: function(center, radius, options)
27023 if (this.gMapContext.circle != null) {
27024 this.gMapContext.circle.setMap(null);
27028 options = Roo.apply({}, options, {
27029 strokeColor: "#0000FF",
27030 strokeOpacity: .35,
27032 fillColor: "#0000FF",
27036 options.map = this.gMapContext.map;
27037 options.radius = radius;
27038 options.center = center;
27039 this.gMapContext.circle = new google.maps.Circle(options);
27040 return this.gMapContext.circle;
27046 setPosition: function(location)
27048 this.gMapContext.location = location;
27049 this.gMapContext.marker.setPosition(location);
27050 this.gMapContext.map.panTo(location);
27051 this.drawCircle(location, this.gMapContext.radius, {});
27055 if (this.gMapContext.settings.enableReverseGeocode) {
27056 this.gMapContext.geodecoder.geocode({
27057 latLng: this.gMapContext.location
27058 }, function(results, status) {
27060 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27061 _this.gMapContext.locationName = results[0].formatted_address;
27062 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27064 _this.fireEvent('positionchanged', this, location);
27071 this.fireEvent('positionchanged', this, location);
27076 google.maps.event.trigger(this.gMapContext.map, "resize");
27078 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27080 this.fireEvent('resize', this);
27083 setPositionByLatLng: function(latitude, longitude)
27085 this.setPosition(new google.maps.LatLng(latitude, longitude));
27088 getCurrentPosition: function()
27091 latitude: this.gMapContext.location.lat(),
27092 longitude: this.gMapContext.location.lng()
27096 getAddressName: function()
27098 return this.gMapContext.locationName;
27101 getAddressComponents: function()
27103 return this.gMapContext.addressComponents;
27106 address_component_from_google_geocode: function(address_components)
27110 for (var i = 0; i < address_components.length; i++) {
27111 var component = address_components[i];
27112 if (component.types.indexOf("postal_code") >= 0) {
27113 result.postalCode = component.short_name;
27114 } else if (component.types.indexOf("street_number") >= 0) {
27115 result.streetNumber = component.short_name;
27116 } else if (component.types.indexOf("route") >= 0) {
27117 result.streetName = component.short_name;
27118 } else if (component.types.indexOf("neighborhood") >= 0) {
27119 result.city = component.short_name;
27120 } else if (component.types.indexOf("locality") >= 0) {
27121 result.city = component.short_name;
27122 } else if (component.types.indexOf("sublocality") >= 0) {
27123 result.district = component.short_name;
27124 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27125 result.stateOrProvince = component.short_name;
27126 } else if (component.types.indexOf("country") >= 0) {
27127 result.country = component.short_name;
27131 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27132 result.addressLine2 = "";
27136 setZoomLevel: function(zoom)
27138 this.gMapContext.map.setZoom(zoom);
27151 this.fireEvent('show', this);
27162 this.fireEvent('hide', this);
27167 Roo.apply(Roo.bootstrap.LocationPicker, {
27169 OverlayView : function(map, options)
27171 options = options || {};
27185 * @class Roo.bootstrap.Alert
27186 * @extends Roo.bootstrap.Component
27187 * Bootstrap Alert class
27188 * @cfg {String} title The title of alert
27189 * @cfg {String} html The content of alert
27190 * @cfg {String} weight ( success | info | warning | danger )
27191 * @cfg {String} faicon font-awesomeicon
27194 * Create a new alert
27195 * @param {Object} config The config object
27199 Roo.bootstrap.Alert = function(config){
27200 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27204 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27211 getAutoCreate : function()
27220 cls : 'roo-alert-icon'
27225 cls : 'roo-alert-title',
27230 cls : 'roo-alert-text',
27237 cfg.cn[0].cls += ' fa ' + this.faicon;
27241 cfg.cls += ' alert-' + this.weight;
27247 initEvents: function()
27249 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27252 setTitle : function(str)
27254 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27257 setText : function(str)
27259 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27262 setWeight : function(weight)
27265 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27268 this.weight = weight;
27270 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27273 setIcon : function(icon)
27276 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27279 this.faicon = icon;
27281 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27302 * @class Roo.bootstrap.UploadCropbox
27303 * @extends Roo.bootstrap.Component
27304 * Bootstrap UploadCropbox class
27305 * @cfg {String} emptyText show when image has been loaded
27306 * @cfg {String} rotateNotify show when image too small to rotate
27307 * @cfg {Number} errorTimeout default 3000
27308 * @cfg {Number} minWidth default 300
27309 * @cfg {Number} minHeight default 300
27310 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27311 * @cfg {Boolean} isDocument (true|false) default false
27312 * @cfg {String} url action url
27313 * @cfg {String} paramName default 'imageUpload'
27314 * @cfg {String} method default POST
27315 * @cfg {Boolean} loadMask (true|false) default true
27316 * @cfg {Boolean} loadingText default 'Loading...'
27319 * Create a new UploadCropbox
27320 * @param {Object} config The config object
27323 Roo.bootstrap.UploadCropbox = function(config){
27324 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27328 * @event beforeselectfile
27329 * Fire before select file
27330 * @param {Roo.bootstrap.UploadCropbox} this
27332 "beforeselectfile" : true,
27335 * Fire after initEvent
27336 * @param {Roo.bootstrap.UploadCropbox} this
27341 * Fire after initEvent
27342 * @param {Roo.bootstrap.UploadCropbox} this
27343 * @param {String} data
27348 * Fire when preparing the file data
27349 * @param {Roo.bootstrap.UploadCropbox} this
27350 * @param {Object} file
27355 * Fire when get exception
27356 * @param {Roo.bootstrap.UploadCropbox} this
27357 * @param {XMLHttpRequest} xhr
27359 "exception" : true,
27361 * @event beforeloadcanvas
27362 * Fire before load the canvas
27363 * @param {Roo.bootstrap.UploadCropbox} this
27364 * @param {String} src
27366 "beforeloadcanvas" : true,
27369 * Fire when trash image
27370 * @param {Roo.bootstrap.UploadCropbox} this
27375 * Fire when download the image
27376 * @param {Roo.bootstrap.UploadCropbox} this
27380 * @event footerbuttonclick
27381 * Fire when footerbuttonclick
27382 * @param {Roo.bootstrap.UploadCropbox} this
27383 * @param {String} type
27385 "footerbuttonclick" : true,
27389 * @param {Roo.bootstrap.UploadCropbox} this
27394 * Fire when rotate the image
27395 * @param {Roo.bootstrap.UploadCropbox} this
27396 * @param {String} pos
27401 * Fire when inspect the file
27402 * @param {Roo.bootstrap.UploadCropbox} this
27403 * @param {Object} file
27408 * Fire when xhr upload the file
27409 * @param {Roo.bootstrap.UploadCropbox} this
27410 * @param {Object} data
27415 * Fire when arrange the file data
27416 * @param {Roo.bootstrap.UploadCropbox} this
27417 * @param {Object} formData
27422 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27425 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27427 emptyText : 'Click to upload image',
27428 rotateNotify : 'Image is too small to rotate',
27429 errorTimeout : 3000,
27443 cropType : 'image/jpeg',
27445 canvasLoaded : false,
27446 isDocument : false,
27448 paramName : 'imageUpload',
27450 loadingText : 'Loading...',
27453 getAutoCreate : function()
27457 cls : 'roo-upload-cropbox',
27461 cls : 'roo-upload-cropbox-selector',
27466 cls : 'roo-upload-cropbox-body',
27467 style : 'cursor:pointer',
27471 cls : 'roo-upload-cropbox-preview'
27475 cls : 'roo-upload-cropbox-thumb'
27479 cls : 'roo-upload-cropbox-empty-notify',
27480 html : this.emptyText
27484 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27485 html : this.rotateNotify
27491 cls : 'roo-upload-cropbox-footer',
27494 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27504 onRender : function(ct, position)
27506 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27508 if (this.buttons.length) {
27510 Roo.each(this.buttons, function(bb) {
27512 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27514 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27520 this.maskEl = this.el;
27524 initEvents : function()
27526 this.urlAPI = (window.createObjectURL && window) ||
27527 (window.URL && URL.revokeObjectURL && URL) ||
27528 (window.webkitURL && webkitURL);
27530 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27531 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27533 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27534 this.selectorEl.hide();
27536 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27537 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27539 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27540 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27541 this.thumbEl.hide();
27543 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27544 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27546 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27547 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27548 this.errorEl.hide();
27550 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27551 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27552 this.footerEl.hide();
27554 this.setThumbBoxSize();
27560 this.fireEvent('initial', this);
27567 window.addEventListener("resize", function() { _this.resize(); } );
27569 this.bodyEl.on('click', this.beforeSelectFile, this);
27572 this.bodyEl.on('touchstart', this.onTouchStart, this);
27573 this.bodyEl.on('touchmove', this.onTouchMove, this);
27574 this.bodyEl.on('touchend', this.onTouchEnd, this);
27578 this.bodyEl.on('mousedown', this.onMouseDown, this);
27579 this.bodyEl.on('mousemove', this.onMouseMove, this);
27580 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27581 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27582 Roo.get(document).on('mouseup', this.onMouseUp, this);
27585 this.selectorEl.on('change', this.onFileSelected, this);
27591 this.baseScale = 1;
27593 this.baseRotate = 1;
27594 this.dragable = false;
27595 this.pinching = false;
27598 this.cropData = false;
27599 this.notifyEl.dom.innerHTML = this.emptyText;
27601 this.selectorEl.dom.value = '';
27605 resize : function()
27607 if(this.fireEvent('resize', this) != false){
27608 this.setThumbBoxPosition();
27609 this.setCanvasPosition();
27613 onFooterButtonClick : function(e, el, o, type)
27616 case 'rotate-left' :
27617 this.onRotateLeft(e);
27619 case 'rotate-right' :
27620 this.onRotateRight(e);
27623 this.beforeSelectFile(e);
27638 this.fireEvent('footerbuttonclick', this, type);
27641 beforeSelectFile : function(e)
27643 e.preventDefault();
27645 if(this.fireEvent('beforeselectfile', this) != false){
27646 this.selectorEl.dom.click();
27650 onFileSelected : function(e)
27652 e.preventDefault();
27654 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27658 var file = this.selectorEl.dom.files[0];
27660 if(this.fireEvent('inspect', this, file) != false){
27661 this.prepare(file);
27666 trash : function(e)
27668 this.fireEvent('trash', this);
27671 download : function(e)
27673 this.fireEvent('download', this);
27676 loadCanvas : function(src)
27678 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27682 this.imageEl = document.createElement('img');
27686 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27688 this.imageEl.src = src;
27692 onLoadCanvas : function()
27694 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27695 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27697 this.bodyEl.un('click', this.beforeSelectFile, this);
27699 this.notifyEl.hide();
27700 this.thumbEl.show();
27701 this.footerEl.show();
27703 this.baseRotateLevel();
27705 if(this.isDocument){
27706 this.setThumbBoxSize();
27709 this.setThumbBoxPosition();
27711 this.baseScaleLevel();
27717 this.canvasLoaded = true;
27720 this.maskEl.unmask();
27725 setCanvasPosition : function()
27727 if(!this.canvasEl){
27731 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27732 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27734 this.previewEl.setLeft(pw);
27735 this.previewEl.setTop(ph);
27739 onMouseDown : function(e)
27743 this.dragable = true;
27744 this.pinching = false;
27746 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27747 this.dragable = false;
27751 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27752 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27756 onMouseMove : function(e)
27760 if(!this.canvasLoaded){
27764 if (!this.dragable){
27768 var minX = Math.ceil(this.thumbEl.getLeft(true));
27769 var minY = Math.ceil(this.thumbEl.getTop(true));
27771 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27772 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27774 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27775 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27777 x = x - this.mouseX;
27778 y = y - this.mouseY;
27780 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27781 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27783 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27784 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27786 this.previewEl.setLeft(bgX);
27787 this.previewEl.setTop(bgY);
27789 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27790 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27793 onMouseUp : function(e)
27797 this.dragable = false;
27800 onMouseWheel : function(e)
27804 this.startScale = this.scale;
27806 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27808 if(!this.zoomable()){
27809 this.scale = this.startScale;
27818 zoomable : function()
27820 var minScale = this.thumbEl.getWidth() / this.minWidth;
27822 if(this.minWidth < this.minHeight){
27823 minScale = this.thumbEl.getHeight() / this.minHeight;
27826 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27827 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27831 (this.rotate == 0 || this.rotate == 180) &&
27833 width > this.imageEl.OriginWidth ||
27834 height > this.imageEl.OriginHeight ||
27835 (width < this.minWidth && height < this.minHeight)
27843 (this.rotate == 90 || this.rotate == 270) &&
27845 width > this.imageEl.OriginWidth ||
27846 height > this.imageEl.OriginHeight ||
27847 (width < this.minHeight && height < this.minWidth)
27854 !this.isDocument &&
27855 (this.rotate == 0 || this.rotate == 180) &&
27857 width < this.minWidth ||
27858 width > this.imageEl.OriginWidth ||
27859 height < this.minHeight ||
27860 height > this.imageEl.OriginHeight
27867 !this.isDocument &&
27868 (this.rotate == 90 || this.rotate == 270) &&
27870 width < this.minHeight ||
27871 width > this.imageEl.OriginWidth ||
27872 height < this.minWidth ||
27873 height > this.imageEl.OriginHeight
27883 onRotateLeft : function(e)
27885 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27887 var minScale = this.thumbEl.getWidth() / this.minWidth;
27889 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27890 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27892 this.startScale = this.scale;
27894 while (this.getScaleLevel() < minScale){
27896 this.scale = this.scale + 1;
27898 if(!this.zoomable()){
27903 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27904 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27909 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27916 this.scale = this.startScale;
27918 this.onRotateFail();
27923 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27925 if(this.isDocument){
27926 this.setThumbBoxSize();
27927 this.setThumbBoxPosition();
27928 this.setCanvasPosition();
27933 this.fireEvent('rotate', this, 'left');
27937 onRotateRight : function(e)
27939 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27941 var minScale = this.thumbEl.getWidth() / this.minWidth;
27943 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27944 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27946 this.startScale = this.scale;
27948 while (this.getScaleLevel() < minScale){
27950 this.scale = this.scale + 1;
27952 if(!this.zoomable()){
27957 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27958 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27963 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27970 this.scale = this.startScale;
27972 this.onRotateFail();
27977 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27979 if(this.isDocument){
27980 this.setThumbBoxSize();
27981 this.setThumbBoxPosition();
27982 this.setCanvasPosition();
27987 this.fireEvent('rotate', this, 'right');
27990 onRotateFail : function()
27992 this.errorEl.show(true);
27996 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
28001 this.previewEl.dom.innerHTML = '';
28003 var canvasEl = document.createElement("canvas");
28005 var contextEl = canvasEl.getContext("2d");
28007 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28008 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28009 var center = this.imageEl.OriginWidth / 2;
28011 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28012 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28013 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28014 center = this.imageEl.OriginHeight / 2;
28017 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28019 contextEl.translate(center, center);
28020 contextEl.rotate(this.rotate * Math.PI / 180);
28022 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28024 this.canvasEl = document.createElement("canvas");
28026 this.contextEl = this.canvasEl.getContext("2d");
28028 switch (this.rotate) {
28031 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28032 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28034 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28039 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28040 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28042 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28043 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);
28047 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28052 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28053 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28055 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28056 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);
28060 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);
28065 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28066 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28068 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28069 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28073 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);
28080 this.previewEl.appendChild(this.canvasEl);
28082 this.setCanvasPosition();
28087 if(!this.canvasLoaded){
28091 var imageCanvas = document.createElement("canvas");
28093 var imageContext = imageCanvas.getContext("2d");
28095 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28096 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28098 var center = imageCanvas.width / 2;
28100 imageContext.translate(center, center);
28102 imageContext.rotate(this.rotate * Math.PI / 180);
28104 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28106 var canvas = document.createElement("canvas");
28108 var context = canvas.getContext("2d");
28110 canvas.width = this.minWidth;
28111 canvas.height = this.minHeight;
28113 switch (this.rotate) {
28116 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28117 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28119 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28120 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28122 var targetWidth = this.minWidth - 2 * x;
28123 var targetHeight = this.minHeight - 2 * y;
28127 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28128 scale = targetWidth / width;
28131 if(x > 0 && y == 0){
28132 scale = targetHeight / height;
28135 if(x > 0 && y > 0){
28136 scale = targetWidth / width;
28138 if(width < height){
28139 scale = targetHeight / height;
28143 context.scale(scale, scale);
28145 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28146 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28148 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28149 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28151 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28156 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28157 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28159 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28160 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28162 var targetWidth = this.minWidth - 2 * x;
28163 var targetHeight = this.minHeight - 2 * y;
28167 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28168 scale = targetWidth / width;
28171 if(x > 0 && y == 0){
28172 scale = targetHeight / height;
28175 if(x > 0 && y > 0){
28176 scale = targetWidth / width;
28178 if(width < height){
28179 scale = targetHeight / height;
28183 context.scale(scale, scale);
28185 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28186 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28188 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28189 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28191 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28193 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28198 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28199 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28201 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28202 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28204 var targetWidth = this.minWidth - 2 * x;
28205 var targetHeight = this.minHeight - 2 * y;
28209 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28210 scale = targetWidth / width;
28213 if(x > 0 && y == 0){
28214 scale = targetHeight / height;
28217 if(x > 0 && y > 0){
28218 scale = targetWidth / width;
28220 if(width < height){
28221 scale = targetHeight / height;
28225 context.scale(scale, scale);
28227 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28228 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28230 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28231 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28233 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28234 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28236 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28241 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28242 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28244 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28245 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28247 var targetWidth = this.minWidth - 2 * x;
28248 var targetHeight = this.minHeight - 2 * y;
28252 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28253 scale = targetWidth / width;
28256 if(x > 0 && y == 0){
28257 scale = targetHeight / height;
28260 if(x > 0 && y > 0){
28261 scale = targetWidth / width;
28263 if(width < height){
28264 scale = targetHeight / height;
28268 context.scale(scale, scale);
28270 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28271 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28273 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28274 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28276 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28278 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28285 this.cropData = canvas.toDataURL(this.cropType);
28287 if(this.fireEvent('crop', this, this.cropData) !== false){
28288 this.process(this.file, this.cropData);
28295 setThumbBoxSize : function()
28299 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28300 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28301 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28303 this.minWidth = width;
28304 this.minHeight = height;
28306 if(this.rotate == 90 || this.rotate == 270){
28307 this.minWidth = height;
28308 this.minHeight = width;
28313 width = Math.ceil(this.minWidth * height / this.minHeight);
28315 if(this.minWidth > this.minHeight){
28317 height = Math.ceil(this.minHeight * width / this.minWidth);
28320 this.thumbEl.setStyle({
28321 width : width + 'px',
28322 height : height + 'px'
28329 setThumbBoxPosition : function()
28331 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28332 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28334 this.thumbEl.setLeft(x);
28335 this.thumbEl.setTop(y);
28339 baseRotateLevel : function()
28341 this.baseRotate = 1;
28344 typeof(this.exif) != 'undefined' &&
28345 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28346 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28348 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28351 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28355 baseScaleLevel : function()
28359 if(this.isDocument){
28361 if(this.baseRotate == 6 || this.baseRotate == 8){
28363 height = this.thumbEl.getHeight();
28364 this.baseScale = height / this.imageEl.OriginWidth;
28366 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28367 width = this.thumbEl.getWidth();
28368 this.baseScale = width / this.imageEl.OriginHeight;
28374 height = this.thumbEl.getHeight();
28375 this.baseScale = height / this.imageEl.OriginHeight;
28377 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28378 width = this.thumbEl.getWidth();
28379 this.baseScale = width / this.imageEl.OriginWidth;
28385 if(this.baseRotate == 6 || this.baseRotate == 8){
28387 width = this.thumbEl.getHeight();
28388 this.baseScale = width / this.imageEl.OriginHeight;
28390 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28391 height = this.thumbEl.getWidth();
28392 this.baseScale = height / this.imageEl.OriginHeight;
28395 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28396 height = this.thumbEl.getWidth();
28397 this.baseScale = height / this.imageEl.OriginHeight;
28399 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28400 width = this.thumbEl.getHeight();
28401 this.baseScale = width / this.imageEl.OriginWidth;
28408 width = this.thumbEl.getWidth();
28409 this.baseScale = width / this.imageEl.OriginWidth;
28411 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28412 height = this.thumbEl.getHeight();
28413 this.baseScale = height / this.imageEl.OriginHeight;
28416 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28418 height = this.thumbEl.getHeight();
28419 this.baseScale = height / this.imageEl.OriginHeight;
28421 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28422 width = this.thumbEl.getWidth();
28423 this.baseScale = width / this.imageEl.OriginWidth;
28431 getScaleLevel : function()
28433 return this.baseScale * Math.pow(1.1, this.scale);
28436 onTouchStart : function(e)
28438 if(!this.canvasLoaded){
28439 this.beforeSelectFile(e);
28443 var touches = e.browserEvent.touches;
28449 if(touches.length == 1){
28450 this.onMouseDown(e);
28454 if(touches.length != 2){
28460 for(var i = 0, finger; finger = touches[i]; i++){
28461 coords.push(finger.pageX, finger.pageY);
28464 var x = Math.pow(coords[0] - coords[2], 2);
28465 var y = Math.pow(coords[1] - coords[3], 2);
28467 this.startDistance = Math.sqrt(x + y);
28469 this.startScale = this.scale;
28471 this.pinching = true;
28472 this.dragable = false;
28476 onTouchMove : function(e)
28478 if(!this.pinching && !this.dragable){
28482 var touches = e.browserEvent.touches;
28489 this.onMouseMove(e);
28495 for(var i = 0, finger; finger = touches[i]; i++){
28496 coords.push(finger.pageX, finger.pageY);
28499 var x = Math.pow(coords[0] - coords[2], 2);
28500 var y = Math.pow(coords[1] - coords[3], 2);
28502 this.endDistance = Math.sqrt(x + y);
28504 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28506 if(!this.zoomable()){
28507 this.scale = this.startScale;
28515 onTouchEnd : function(e)
28517 this.pinching = false;
28518 this.dragable = false;
28522 process : function(file, crop)
28525 this.maskEl.mask(this.loadingText);
28528 this.xhr = new XMLHttpRequest();
28530 file.xhr = this.xhr;
28532 this.xhr.open(this.method, this.url, true);
28535 "Accept": "application/json",
28536 "Cache-Control": "no-cache",
28537 "X-Requested-With": "XMLHttpRequest"
28540 for (var headerName in headers) {
28541 var headerValue = headers[headerName];
28543 this.xhr.setRequestHeader(headerName, headerValue);
28549 this.xhr.onload = function()
28551 _this.xhrOnLoad(_this.xhr);
28554 this.xhr.onerror = function()
28556 _this.xhrOnError(_this.xhr);
28559 var formData = new FormData();
28561 formData.append('returnHTML', 'NO');
28564 formData.append('crop', crop);
28567 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28568 formData.append(this.paramName, file, file.name);
28571 if(typeof(file.filename) != 'undefined'){
28572 formData.append('filename', file.filename);
28575 if(typeof(file.mimetype) != 'undefined'){
28576 formData.append('mimetype', file.mimetype);
28579 if(this.fireEvent('arrange', this, formData) != false){
28580 this.xhr.send(formData);
28584 xhrOnLoad : function(xhr)
28587 this.maskEl.unmask();
28590 if (xhr.readyState !== 4) {
28591 this.fireEvent('exception', this, xhr);
28595 var response = Roo.decode(xhr.responseText);
28597 if(!response.success){
28598 this.fireEvent('exception', this, xhr);
28602 var response = Roo.decode(xhr.responseText);
28604 this.fireEvent('upload', this, response);
28608 xhrOnError : function()
28611 this.maskEl.unmask();
28614 Roo.log('xhr on error');
28616 var response = Roo.decode(xhr.responseText);
28622 prepare : function(file)
28625 this.maskEl.mask(this.loadingText);
28631 if(typeof(file) === 'string'){
28632 this.loadCanvas(file);
28636 if(!file || !this.urlAPI){
28641 this.cropType = file.type;
28645 if(this.fireEvent('prepare', this, this.file) != false){
28647 var reader = new FileReader();
28649 reader.onload = function (e) {
28650 if (e.target.error) {
28651 Roo.log(e.target.error);
28655 var buffer = e.target.result,
28656 dataView = new DataView(buffer),
28658 maxOffset = dataView.byteLength - 4,
28662 if (dataView.getUint16(0) === 0xffd8) {
28663 while (offset < maxOffset) {
28664 markerBytes = dataView.getUint16(offset);
28666 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28667 markerLength = dataView.getUint16(offset + 2) + 2;
28668 if (offset + markerLength > dataView.byteLength) {
28669 Roo.log('Invalid meta data: Invalid segment size.');
28673 if(markerBytes == 0xffe1){
28674 _this.parseExifData(
28681 offset += markerLength;
28691 var url = _this.urlAPI.createObjectURL(_this.file);
28693 _this.loadCanvas(url);
28698 reader.readAsArrayBuffer(this.file);
28704 parseExifData : function(dataView, offset, length)
28706 var tiffOffset = offset + 10,
28710 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28711 // No Exif data, might be XMP data instead
28715 // Check for the ASCII code for "Exif" (0x45786966):
28716 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28717 // No Exif data, might be XMP data instead
28720 if (tiffOffset + 8 > dataView.byteLength) {
28721 Roo.log('Invalid Exif data: Invalid segment size.');
28724 // Check for the two null bytes:
28725 if (dataView.getUint16(offset + 8) !== 0x0000) {
28726 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28729 // Check the byte alignment:
28730 switch (dataView.getUint16(tiffOffset)) {
28732 littleEndian = true;
28735 littleEndian = false;
28738 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28741 // Check for the TIFF tag marker (0x002A):
28742 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28743 Roo.log('Invalid Exif data: Missing TIFF marker.');
28746 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28747 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28749 this.parseExifTags(
28752 tiffOffset + dirOffset,
28757 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28762 if (dirOffset + 6 > dataView.byteLength) {
28763 Roo.log('Invalid Exif data: Invalid directory offset.');
28766 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28767 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28768 if (dirEndOffset + 4 > dataView.byteLength) {
28769 Roo.log('Invalid Exif data: Invalid directory size.');
28772 for (i = 0; i < tagsNumber; i += 1) {
28776 dirOffset + 2 + 12 * i, // tag offset
28780 // Return the offset to the next directory:
28781 return dataView.getUint32(dirEndOffset, littleEndian);
28784 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28786 var tag = dataView.getUint16(offset, littleEndian);
28788 this.exif[tag] = this.getExifValue(
28792 dataView.getUint16(offset + 2, littleEndian), // tag type
28793 dataView.getUint32(offset + 4, littleEndian), // tag length
28798 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28800 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28809 Roo.log('Invalid Exif data: Invalid tag type.');
28813 tagSize = tagType.size * length;
28814 // Determine if the value is contained in the dataOffset bytes,
28815 // or if the value at the dataOffset is a pointer to the actual data:
28816 dataOffset = tagSize > 4 ?
28817 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28818 if (dataOffset + tagSize > dataView.byteLength) {
28819 Roo.log('Invalid Exif data: Invalid data offset.');
28822 if (length === 1) {
28823 return tagType.getValue(dataView, dataOffset, littleEndian);
28826 for (i = 0; i < length; i += 1) {
28827 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28830 if (tagType.ascii) {
28832 // Concatenate the chars:
28833 for (i = 0; i < values.length; i += 1) {
28835 // Ignore the terminating NULL byte(s):
28836 if (c === '\u0000') {
28848 Roo.apply(Roo.bootstrap.UploadCropbox, {
28850 'Orientation': 0x0112
28854 1: 0, //'top-left',
28856 3: 180, //'bottom-right',
28857 // 4: 'bottom-left',
28859 6: 90, //'right-top',
28860 // 7: 'right-bottom',
28861 8: 270 //'left-bottom'
28865 // byte, 8-bit unsigned int:
28867 getValue: function (dataView, dataOffset) {
28868 return dataView.getUint8(dataOffset);
28872 // ascii, 8-bit byte:
28874 getValue: function (dataView, dataOffset) {
28875 return String.fromCharCode(dataView.getUint8(dataOffset));
28880 // short, 16 bit int:
28882 getValue: function (dataView, dataOffset, littleEndian) {
28883 return dataView.getUint16(dataOffset, littleEndian);
28887 // long, 32 bit int:
28889 getValue: function (dataView, dataOffset, littleEndian) {
28890 return dataView.getUint32(dataOffset, littleEndian);
28894 // rational = two long values, first is numerator, second is denominator:
28896 getValue: function (dataView, dataOffset, littleEndian) {
28897 return dataView.getUint32(dataOffset, littleEndian) /
28898 dataView.getUint32(dataOffset + 4, littleEndian);
28902 // slong, 32 bit signed int:
28904 getValue: function (dataView, dataOffset, littleEndian) {
28905 return dataView.getInt32(dataOffset, littleEndian);
28909 // srational, two slongs, first is numerator, second is denominator:
28911 getValue: function (dataView, dataOffset, littleEndian) {
28912 return dataView.getInt32(dataOffset, littleEndian) /
28913 dataView.getInt32(dataOffset + 4, littleEndian);
28923 cls : 'btn-group roo-upload-cropbox-rotate-left',
28924 action : 'rotate-left',
28928 cls : 'btn btn-default',
28929 html : '<i class="fa fa-undo"></i>'
28935 cls : 'btn-group roo-upload-cropbox-picture',
28936 action : 'picture',
28940 cls : 'btn btn-default',
28941 html : '<i class="fa fa-picture-o"></i>'
28947 cls : 'btn-group roo-upload-cropbox-rotate-right',
28948 action : 'rotate-right',
28952 cls : 'btn btn-default',
28953 html : '<i class="fa fa-repeat"></i>'
28961 cls : 'btn-group roo-upload-cropbox-rotate-left',
28962 action : 'rotate-left',
28966 cls : 'btn btn-default',
28967 html : '<i class="fa fa-undo"></i>'
28973 cls : 'btn-group roo-upload-cropbox-download',
28974 action : 'download',
28978 cls : 'btn btn-default',
28979 html : '<i class="fa fa-download"></i>'
28985 cls : 'btn-group roo-upload-cropbox-crop',
28990 cls : 'btn btn-default',
28991 html : '<i class="fa fa-crop"></i>'
28997 cls : 'btn-group roo-upload-cropbox-trash',
29002 cls : 'btn btn-default',
29003 html : '<i class="fa fa-trash"></i>'
29009 cls : 'btn-group roo-upload-cropbox-rotate-right',
29010 action : 'rotate-right',
29014 cls : 'btn btn-default',
29015 html : '<i class="fa fa-repeat"></i>'
29023 cls : 'btn-group roo-upload-cropbox-rotate-left',
29024 action : 'rotate-left',
29028 cls : 'btn btn-default',
29029 html : '<i class="fa fa-undo"></i>'
29035 cls : 'btn-group roo-upload-cropbox-rotate-right',
29036 action : 'rotate-right',
29040 cls : 'btn btn-default',
29041 html : '<i class="fa fa-repeat"></i>'
29054 * @class Roo.bootstrap.DocumentManager
29055 * @extends Roo.bootstrap.Component
29056 * Bootstrap DocumentManager class
29057 * @cfg {String} paramName default 'imageUpload'
29058 * @cfg {String} toolTipName default 'filename'
29059 * @cfg {String} method default POST
29060 * @cfg {String} url action url
29061 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29062 * @cfg {Boolean} multiple multiple upload default true
29063 * @cfg {Number} thumbSize default 300
29064 * @cfg {String} fieldLabel
29065 * @cfg {Number} labelWidth default 4
29066 * @cfg {String} labelAlign (left|top) default left
29067 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29068 * @cfg {Number} labellg set the width of label (1-12)
29069 * @cfg {Number} labelmd set the width of label (1-12)
29070 * @cfg {Number} labelsm set the width of label (1-12)
29071 * @cfg {Number} labelxs set the width of label (1-12)
29074 * Create a new DocumentManager
29075 * @param {Object} config The config object
29078 Roo.bootstrap.DocumentManager = function(config){
29079 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29082 this.delegates = [];
29087 * Fire when initial the DocumentManager
29088 * @param {Roo.bootstrap.DocumentManager} this
29093 * inspect selected file
29094 * @param {Roo.bootstrap.DocumentManager} this
29095 * @param {File} file
29100 * Fire when xhr load exception
29101 * @param {Roo.bootstrap.DocumentManager} this
29102 * @param {XMLHttpRequest} xhr
29104 "exception" : true,
29106 * @event afterupload
29107 * Fire when xhr load exception
29108 * @param {Roo.bootstrap.DocumentManager} this
29109 * @param {XMLHttpRequest} xhr
29111 "afterupload" : true,
29114 * prepare the form data
29115 * @param {Roo.bootstrap.DocumentManager} this
29116 * @param {Object} formData
29121 * Fire when remove the file
29122 * @param {Roo.bootstrap.DocumentManager} this
29123 * @param {Object} file
29128 * Fire after refresh the file
29129 * @param {Roo.bootstrap.DocumentManager} this
29134 * Fire after click the image
29135 * @param {Roo.bootstrap.DocumentManager} this
29136 * @param {Object} file
29141 * Fire when upload a image and editable set to true
29142 * @param {Roo.bootstrap.DocumentManager} this
29143 * @param {Object} file
29147 * @event beforeselectfile
29148 * Fire before select file
29149 * @param {Roo.bootstrap.DocumentManager} this
29151 "beforeselectfile" : true,
29154 * Fire before process file
29155 * @param {Roo.bootstrap.DocumentManager} this
29156 * @param {Object} file
29160 * @event previewrendered
29161 * Fire when preview rendered
29162 * @param {Roo.bootstrap.DocumentManager} this
29163 * @param {Object} file
29165 "previewrendered" : true,
29168 "previewResize" : true
29173 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29182 paramName : 'imageUpload',
29183 toolTipName : 'filename',
29186 labelAlign : 'left',
29196 getAutoCreate : function()
29198 var managerWidget = {
29200 cls : 'roo-document-manager',
29204 cls : 'roo-document-manager-selector',
29209 cls : 'roo-document-manager-uploader',
29213 cls : 'roo-document-manager-upload-btn',
29214 html : '<i class="fa fa-plus"></i>'
29225 cls : 'column col-md-12',
29230 if(this.fieldLabel.length){
29235 cls : 'column col-md-12',
29236 html : this.fieldLabel
29240 cls : 'column col-md-12',
29245 if(this.labelAlign == 'left'){
29250 html : this.fieldLabel
29259 if(this.labelWidth > 12){
29260 content[0].style = "width: " + this.labelWidth + 'px';
29263 if(this.labelWidth < 13 && this.labelmd == 0){
29264 this.labelmd = this.labelWidth;
29267 if(this.labellg > 0){
29268 content[0].cls += ' col-lg-' + this.labellg;
29269 content[1].cls += ' col-lg-' + (12 - this.labellg);
29272 if(this.labelmd > 0){
29273 content[0].cls += ' col-md-' + this.labelmd;
29274 content[1].cls += ' col-md-' + (12 - this.labelmd);
29277 if(this.labelsm > 0){
29278 content[0].cls += ' col-sm-' + this.labelsm;
29279 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29282 if(this.labelxs > 0){
29283 content[0].cls += ' col-xs-' + this.labelxs;
29284 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29292 cls : 'row clearfix',
29300 initEvents : function()
29302 this.managerEl = this.el.select('.roo-document-manager', true).first();
29303 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29305 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29306 this.selectorEl.hide();
29309 this.selectorEl.attr('multiple', 'multiple');
29312 this.selectorEl.on('change', this.onFileSelected, this);
29314 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29315 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29317 this.uploader.on('click', this.onUploaderClick, this);
29319 this.renderProgressDialog();
29323 window.addEventListener("resize", function() { _this.refresh(); } );
29325 this.fireEvent('initial', this);
29328 renderProgressDialog : function()
29332 this.progressDialog = new Roo.bootstrap.Modal({
29333 cls : 'roo-document-manager-progress-dialog',
29334 allow_close : false,
29345 btnclick : function() {
29346 _this.uploadCancel();
29352 this.progressDialog.render(Roo.get(document.body));
29354 this.progress = new Roo.bootstrap.Progress({
29355 cls : 'roo-document-manager-progress',
29360 this.progress.render(this.progressDialog.getChildContainer());
29362 this.progressBar = new Roo.bootstrap.ProgressBar({
29363 cls : 'roo-document-manager-progress-bar',
29366 aria_valuemax : 12,
29370 this.progressBar.render(this.progress.getChildContainer());
29373 onUploaderClick : function(e)
29375 e.preventDefault();
29377 if(this.fireEvent('beforeselectfile', this) != false){
29378 this.selectorEl.dom.click();
29383 onFileSelected : function(e)
29385 e.preventDefault();
29387 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29391 Roo.each(this.selectorEl.dom.files, function(file){
29392 if(this.fireEvent('inspect', this, file) != false){
29393 this.files.push(file);
29403 this.selectorEl.dom.value = '';
29405 if(!this.files || !this.files.length){
29409 if(this.boxes > 0 && this.files.length > this.boxes){
29410 this.files = this.files.slice(0, this.boxes);
29413 this.uploader.show();
29415 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29416 this.uploader.hide();
29425 Roo.each(this.files, function(file){
29427 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29428 var f = this.renderPreview(file);
29433 if(file.type.indexOf('image') != -1){
29434 this.delegates.push(
29436 _this.process(file);
29437 }).createDelegate(this)
29445 _this.process(file);
29446 }).createDelegate(this)
29451 this.files = files;
29453 this.delegates = this.delegates.concat(docs);
29455 if(!this.delegates.length){
29460 this.progressBar.aria_valuemax = this.delegates.length;
29467 arrange : function()
29469 if(!this.delegates.length){
29470 this.progressDialog.hide();
29475 var delegate = this.delegates.shift();
29477 this.progressDialog.show();
29479 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29481 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29486 refresh : function()
29488 this.uploader.show();
29490 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29491 this.uploader.hide();
29494 Roo.isTouch ? this.closable(false) : this.closable(true);
29496 this.fireEvent('refresh', this);
29499 onRemove : function(e, el, o)
29501 e.preventDefault();
29503 this.fireEvent('remove', this, o);
29507 remove : function(o)
29511 Roo.each(this.files, function(file){
29512 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29521 this.files = files;
29528 Roo.each(this.files, function(file){
29533 file.target.remove();
29542 onClick : function(e, el, o)
29544 e.preventDefault();
29546 this.fireEvent('click', this, o);
29550 closable : function(closable)
29552 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29554 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29566 xhrOnLoad : function(xhr)
29568 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29572 if (xhr.readyState !== 4) {
29574 this.fireEvent('exception', this, xhr);
29578 var response = Roo.decode(xhr.responseText);
29580 if(!response.success){
29582 this.fireEvent('exception', this, xhr);
29586 var file = this.renderPreview(response.data);
29588 this.files.push(file);
29592 this.fireEvent('afterupload', this, xhr);
29596 xhrOnError : function(xhr)
29598 Roo.log('xhr on error');
29600 var response = Roo.decode(xhr.responseText);
29607 process : function(file)
29609 if(this.fireEvent('process', this, file) !== false){
29610 if(this.editable && file.type.indexOf('image') != -1){
29611 this.fireEvent('edit', this, file);
29615 this.uploadStart(file, false);
29622 uploadStart : function(file, crop)
29624 this.xhr = new XMLHttpRequest();
29626 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29631 file.xhr = this.xhr;
29633 this.managerEl.createChild({
29635 cls : 'roo-document-manager-loading',
29639 tooltip : file.name,
29640 cls : 'roo-document-manager-thumb',
29641 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29647 this.xhr.open(this.method, this.url, true);
29650 "Accept": "application/json",
29651 "Cache-Control": "no-cache",
29652 "X-Requested-With": "XMLHttpRequest"
29655 for (var headerName in headers) {
29656 var headerValue = headers[headerName];
29658 this.xhr.setRequestHeader(headerName, headerValue);
29664 this.xhr.onload = function()
29666 _this.xhrOnLoad(_this.xhr);
29669 this.xhr.onerror = function()
29671 _this.xhrOnError(_this.xhr);
29674 var formData = new FormData();
29676 formData.append('returnHTML', 'NO');
29679 formData.append('crop', crop);
29682 formData.append(this.paramName, file, file.name);
29689 if(this.fireEvent('prepare', this, formData, options) != false){
29691 if(options.manually){
29695 this.xhr.send(formData);
29699 this.uploadCancel();
29702 uploadCancel : function()
29708 this.delegates = [];
29710 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29717 renderPreview : function(file)
29719 if(typeof(file.target) != 'undefined' && file.target){
29723 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29725 var previewEl = this.managerEl.createChild({
29727 cls : 'roo-document-manager-preview',
29731 tooltip : file[this.toolTipName],
29732 cls : 'roo-document-manager-thumb',
29733 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29738 html : '<i class="fa fa-times-circle"></i>'
29743 var close = previewEl.select('button.close', true).first();
29745 close.on('click', this.onRemove, this, file);
29747 file.target = previewEl;
29749 var image = previewEl.select('img', true).first();
29753 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29755 image.on('click', this.onClick, this, file);
29757 this.fireEvent('previewrendered', this, file);
29763 onPreviewLoad : function(file, image)
29765 if(typeof(file.target) == 'undefined' || !file.target){
29769 var width = image.dom.naturalWidth || image.dom.width;
29770 var height = image.dom.naturalHeight || image.dom.height;
29772 if(!this.previewResize) {
29776 if(width > height){
29777 file.target.addClass('wide');
29781 file.target.addClass('tall');
29786 uploadFromSource : function(file, crop)
29788 this.xhr = new XMLHttpRequest();
29790 this.managerEl.createChild({
29792 cls : 'roo-document-manager-loading',
29796 tooltip : file.name,
29797 cls : 'roo-document-manager-thumb',
29798 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29804 this.xhr.open(this.method, this.url, true);
29807 "Accept": "application/json",
29808 "Cache-Control": "no-cache",
29809 "X-Requested-With": "XMLHttpRequest"
29812 for (var headerName in headers) {
29813 var headerValue = headers[headerName];
29815 this.xhr.setRequestHeader(headerName, headerValue);
29821 this.xhr.onload = function()
29823 _this.xhrOnLoad(_this.xhr);
29826 this.xhr.onerror = function()
29828 _this.xhrOnError(_this.xhr);
29831 var formData = new FormData();
29833 formData.append('returnHTML', 'NO');
29835 formData.append('crop', crop);
29837 if(typeof(file.filename) != 'undefined'){
29838 formData.append('filename', file.filename);
29841 if(typeof(file.mimetype) != 'undefined'){
29842 formData.append('mimetype', file.mimetype);
29847 if(this.fireEvent('prepare', this, formData) != false){
29848 this.xhr.send(formData);
29858 * @class Roo.bootstrap.DocumentViewer
29859 * @extends Roo.bootstrap.Component
29860 * Bootstrap DocumentViewer class
29861 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29862 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29865 * Create a new DocumentViewer
29866 * @param {Object} config The config object
29869 Roo.bootstrap.DocumentViewer = function(config){
29870 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29875 * Fire after initEvent
29876 * @param {Roo.bootstrap.DocumentViewer} this
29882 * @param {Roo.bootstrap.DocumentViewer} this
29887 * Fire after download button
29888 * @param {Roo.bootstrap.DocumentViewer} this
29893 * Fire after trash button
29894 * @param {Roo.bootstrap.DocumentViewer} this
29901 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29903 showDownload : true,
29907 getAutoCreate : function()
29911 cls : 'roo-document-viewer',
29915 cls : 'roo-document-viewer-body',
29919 cls : 'roo-document-viewer-thumb',
29923 cls : 'roo-document-viewer-image'
29931 cls : 'roo-document-viewer-footer',
29934 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29938 cls : 'btn-group roo-document-viewer-download',
29942 cls : 'btn btn-default',
29943 html : '<i class="fa fa-download"></i>'
29949 cls : 'btn-group roo-document-viewer-trash',
29953 cls : 'btn btn-default',
29954 html : '<i class="fa fa-trash"></i>'
29967 initEvents : function()
29969 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29970 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29972 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29973 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29975 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29976 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29978 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29979 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29981 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29982 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29984 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29985 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29987 this.bodyEl.on('click', this.onClick, this);
29988 this.downloadBtn.on('click', this.onDownload, this);
29989 this.trashBtn.on('click', this.onTrash, this);
29991 this.downloadBtn.hide();
29992 this.trashBtn.hide();
29994 if(this.showDownload){
29995 this.downloadBtn.show();
29998 if(this.showTrash){
29999 this.trashBtn.show();
30002 if(!this.showDownload && !this.showTrash) {
30003 this.footerEl.hide();
30008 initial : function()
30010 this.fireEvent('initial', this);
30014 onClick : function(e)
30016 e.preventDefault();
30018 this.fireEvent('click', this);
30021 onDownload : function(e)
30023 e.preventDefault();
30025 this.fireEvent('download', this);
30028 onTrash : function(e)
30030 e.preventDefault();
30032 this.fireEvent('trash', this);
30044 * @class Roo.bootstrap.NavProgressBar
30045 * @extends Roo.bootstrap.Component
30046 * Bootstrap NavProgressBar class
30049 * Create a new nav progress bar
30050 * @param {Object} config The config object
30053 Roo.bootstrap.NavProgressBar = function(config){
30054 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30056 this.bullets = this.bullets || [];
30058 // Roo.bootstrap.NavProgressBar.register(this);
30062 * Fires when the active item changes
30063 * @param {Roo.bootstrap.NavProgressBar} this
30064 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30065 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30072 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30077 getAutoCreate : function()
30079 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30083 cls : 'roo-navigation-bar-group',
30087 cls : 'roo-navigation-top-bar'
30091 cls : 'roo-navigation-bullets-bar',
30095 cls : 'roo-navigation-bar'
30102 cls : 'roo-navigation-bottom-bar'
30112 initEvents: function()
30117 onRender : function(ct, position)
30119 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30121 if(this.bullets.length){
30122 Roo.each(this.bullets, function(b){
30131 addItem : function(cfg)
30133 var item = new Roo.bootstrap.NavProgressItem(cfg);
30135 item.parentId = this.id;
30136 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30139 var top = new Roo.bootstrap.Element({
30141 cls : 'roo-navigation-bar-text'
30144 var bottom = new Roo.bootstrap.Element({
30146 cls : 'roo-navigation-bar-text'
30149 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30150 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30152 var topText = new Roo.bootstrap.Element({
30154 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30157 var bottomText = new Roo.bootstrap.Element({
30159 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30162 topText.onRender(top.el, null);
30163 bottomText.onRender(bottom.el, null);
30166 item.bottomEl = bottom;
30169 this.barItems.push(item);
30174 getActive : function()
30176 var active = false;
30178 Roo.each(this.barItems, function(v){
30180 if (!v.isActive()) {
30192 setActiveItem : function(item)
30196 Roo.each(this.barItems, function(v){
30197 if (v.rid == item.rid) {
30201 if (v.isActive()) {
30202 v.setActive(false);
30207 item.setActive(true);
30209 this.fireEvent('changed', this, item, prev);
30212 getBarItem: function(rid)
30216 Roo.each(this.barItems, function(e) {
30217 if (e.rid != rid) {
30228 indexOfItem : function(item)
30232 Roo.each(this.barItems, function(v, i){
30234 if (v.rid != item.rid) {
30245 setActiveNext : function()
30247 var i = this.indexOfItem(this.getActive());
30249 if (i > this.barItems.length) {
30253 this.setActiveItem(this.barItems[i+1]);
30256 setActivePrev : function()
30258 var i = this.indexOfItem(this.getActive());
30264 this.setActiveItem(this.barItems[i-1]);
30267 format : function()
30269 if(!this.barItems.length){
30273 var width = 100 / this.barItems.length;
30275 Roo.each(this.barItems, function(i){
30276 i.el.setStyle('width', width + '%');
30277 i.topEl.el.setStyle('width', width + '%');
30278 i.bottomEl.el.setStyle('width', width + '%');
30287 * Nav Progress Item
30292 * @class Roo.bootstrap.NavProgressItem
30293 * @extends Roo.bootstrap.Component
30294 * Bootstrap NavProgressItem class
30295 * @cfg {String} rid the reference id
30296 * @cfg {Boolean} active (true|false) Is item active default false
30297 * @cfg {Boolean} disabled (true|false) Is item active default false
30298 * @cfg {String} html
30299 * @cfg {String} position (top|bottom) text position default bottom
30300 * @cfg {String} icon show icon instead of number
30303 * Create a new NavProgressItem
30304 * @param {Object} config The config object
30306 Roo.bootstrap.NavProgressItem = function(config){
30307 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30312 * The raw click event for the entire grid.
30313 * @param {Roo.bootstrap.NavProgressItem} this
30314 * @param {Roo.EventObject} e
30321 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30327 position : 'bottom',
30330 getAutoCreate : function()
30332 var iconCls = 'roo-navigation-bar-item-icon';
30334 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30338 cls: 'roo-navigation-bar-item',
30348 cfg.cls += ' active';
30351 cfg.cls += ' disabled';
30357 disable : function()
30359 this.setDisabled(true);
30362 enable : function()
30364 this.setDisabled(false);
30367 initEvents: function()
30369 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30371 this.iconEl.on('click', this.onClick, this);
30374 onClick : function(e)
30376 e.preventDefault();
30382 if(this.fireEvent('click', this, e) === false){
30386 this.parent().setActiveItem(this);
30389 isActive: function ()
30391 return this.active;
30394 setActive : function(state)
30396 if(this.active == state){
30400 this.active = state;
30403 this.el.addClass('active');
30407 this.el.removeClass('active');
30412 setDisabled : function(state)
30414 if(this.disabled == state){
30418 this.disabled = state;
30421 this.el.addClass('disabled');
30425 this.el.removeClass('disabled');
30428 tooltipEl : function()
30430 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30443 * @class Roo.bootstrap.FieldLabel
30444 * @extends Roo.bootstrap.Component
30445 * Bootstrap FieldLabel class
30446 * @cfg {String} html contents of the element
30447 * @cfg {String} tag tag of the element default label
30448 * @cfg {String} cls class of the element
30449 * @cfg {String} target label target
30450 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30451 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30452 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30453 * @cfg {String} iconTooltip default "This field is required"
30454 * @cfg {String} indicatorpos (left|right) default left
30457 * Create a new FieldLabel
30458 * @param {Object} config The config object
30461 Roo.bootstrap.FieldLabel = function(config){
30462 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30467 * Fires after the field has been marked as invalid.
30468 * @param {Roo.form.FieldLabel} this
30469 * @param {String} msg The validation message
30474 * Fires after the field has been validated with no errors.
30475 * @param {Roo.form.FieldLabel} this
30481 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30488 invalidClass : 'has-warning',
30489 validClass : 'has-success',
30490 iconTooltip : 'This field is required',
30491 indicatorpos : 'left',
30493 getAutoCreate : function(){
30496 if (!this.allowBlank) {
30502 cls : 'roo-bootstrap-field-label ' + this.cls,
30507 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30508 tooltip : this.iconTooltip
30517 if(this.indicatorpos == 'right'){
30520 cls : 'roo-bootstrap-field-label ' + this.cls,
30529 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30530 tooltip : this.iconTooltip
30539 initEvents: function()
30541 Roo.bootstrap.Element.superclass.initEvents.call(this);
30543 this.indicator = this.indicatorEl();
30545 if(this.indicator){
30546 this.indicator.removeClass('visible');
30547 this.indicator.addClass('invisible');
30550 Roo.bootstrap.FieldLabel.register(this);
30553 indicatorEl : function()
30555 var indicator = this.el.select('i.roo-required-indicator',true).first();
30566 * Mark this field as valid
30568 markValid : function()
30570 if(this.indicator){
30571 this.indicator.removeClass('visible');
30572 this.indicator.addClass('invisible');
30574 if (Roo.bootstrap.version == 3) {
30575 this.el.removeClass(this.invalidClass);
30576 this.el.addClass(this.validClass);
30578 this.el.removeClass('is-invalid');
30579 this.el.addClass('is-valid');
30583 this.fireEvent('valid', this);
30587 * Mark this field as invalid
30588 * @param {String} msg The validation message
30590 markInvalid : function(msg)
30592 if(this.indicator){
30593 this.indicator.removeClass('invisible');
30594 this.indicator.addClass('visible');
30596 if (Roo.bootstrap.version == 3) {
30597 this.el.removeClass(this.validClass);
30598 this.el.addClass(this.invalidClass);
30600 this.el.removeClass('is-valid');
30601 this.el.addClass('is-invalid');
30605 this.fireEvent('invalid', this, msg);
30611 Roo.apply(Roo.bootstrap.FieldLabel, {
30616 * register a FieldLabel Group
30617 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30619 register : function(label)
30621 if(this.groups.hasOwnProperty(label.target)){
30625 this.groups[label.target] = label;
30629 * fetch a FieldLabel Group based on the target
30630 * @param {string} target
30631 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30633 get: function(target) {
30634 if (typeof(this.groups[target]) == 'undefined') {
30638 return this.groups[target] ;
30647 * page DateSplitField.
30653 * @class Roo.bootstrap.DateSplitField
30654 * @extends Roo.bootstrap.Component
30655 * Bootstrap DateSplitField class
30656 * @cfg {string} fieldLabel - the label associated
30657 * @cfg {Number} labelWidth set the width of label (0-12)
30658 * @cfg {String} labelAlign (top|left)
30659 * @cfg {Boolean} dayAllowBlank (true|false) default false
30660 * @cfg {Boolean} monthAllowBlank (true|false) default false
30661 * @cfg {Boolean} yearAllowBlank (true|false) default false
30662 * @cfg {string} dayPlaceholder
30663 * @cfg {string} monthPlaceholder
30664 * @cfg {string} yearPlaceholder
30665 * @cfg {string} dayFormat default 'd'
30666 * @cfg {string} monthFormat default 'm'
30667 * @cfg {string} yearFormat default 'Y'
30668 * @cfg {Number} labellg set the width of label (1-12)
30669 * @cfg {Number} labelmd set the width of label (1-12)
30670 * @cfg {Number} labelsm set the width of label (1-12)
30671 * @cfg {Number} labelxs set the width of label (1-12)
30675 * Create a new DateSplitField
30676 * @param {Object} config The config object
30679 Roo.bootstrap.DateSplitField = function(config){
30680 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30686 * getting the data of years
30687 * @param {Roo.bootstrap.DateSplitField} this
30688 * @param {Object} years
30693 * getting the data of days
30694 * @param {Roo.bootstrap.DateSplitField} this
30695 * @param {Object} days
30700 * Fires after the field has been marked as invalid.
30701 * @param {Roo.form.Field} this
30702 * @param {String} msg The validation message
30707 * Fires after the field has been validated with no errors.
30708 * @param {Roo.form.Field} this
30714 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30717 labelAlign : 'top',
30719 dayAllowBlank : false,
30720 monthAllowBlank : false,
30721 yearAllowBlank : false,
30722 dayPlaceholder : '',
30723 monthPlaceholder : '',
30724 yearPlaceholder : '',
30728 isFormField : true,
30734 getAutoCreate : function()
30738 cls : 'row roo-date-split-field-group',
30743 cls : 'form-hidden-field roo-date-split-field-group-value',
30749 var labelCls = 'col-md-12';
30750 var contentCls = 'col-md-4';
30752 if(this.fieldLabel){
30756 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30760 html : this.fieldLabel
30765 if(this.labelAlign == 'left'){
30767 if(this.labelWidth > 12){
30768 label.style = "width: " + this.labelWidth + 'px';
30771 if(this.labelWidth < 13 && this.labelmd == 0){
30772 this.labelmd = this.labelWidth;
30775 if(this.labellg > 0){
30776 labelCls = ' col-lg-' + this.labellg;
30777 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30780 if(this.labelmd > 0){
30781 labelCls = ' col-md-' + this.labelmd;
30782 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30785 if(this.labelsm > 0){
30786 labelCls = ' col-sm-' + this.labelsm;
30787 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30790 if(this.labelxs > 0){
30791 labelCls = ' col-xs-' + this.labelxs;
30792 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30796 label.cls += ' ' + labelCls;
30798 cfg.cn.push(label);
30801 Roo.each(['day', 'month', 'year'], function(t){
30804 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30811 inputEl: function ()
30813 return this.el.select('.roo-date-split-field-group-value', true).first();
30816 onRender : function(ct, position)
30820 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30822 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30824 this.dayField = new Roo.bootstrap.ComboBox({
30825 allowBlank : this.dayAllowBlank,
30826 alwaysQuery : true,
30827 displayField : 'value',
30830 forceSelection : true,
30832 placeholder : this.dayPlaceholder,
30833 selectOnFocus : true,
30834 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30835 triggerAction : 'all',
30837 valueField : 'value',
30838 store : new Roo.data.SimpleStore({
30839 data : (function() {
30841 _this.fireEvent('days', _this, days);
30844 fields : [ 'value' ]
30847 select : function (_self, record, index)
30849 _this.setValue(_this.getValue());
30854 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30856 this.monthField = new Roo.bootstrap.MonthField({
30857 after : '<i class=\"fa fa-calendar\"></i>',
30858 allowBlank : this.monthAllowBlank,
30859 placeholder : this.monthPlaceholder,
30862 render : function (_self)
30864 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30865 e.preventDefault();
30869 select : function (_self, oldvalue, newvalue)
30871 _this.setValue(_this.getValue());
30876 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30878 this.yearField = new Roo.bootstrap.ComboBox({
30879 allowBlank : this.yearAllowBlank,
30880 alwaysQuery : true,
30881 displayField : 'value',
30884 forceSelection : true,
30886 placeholder : this.yearPlaceholder,
30887 selectOnFocus : true,
30888 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30889 triggerAction : 'all',
30891 valueField : 'value',
30892 store : new Roo.data.SimpleStore({
30893 data : (function() {
30895 _this.fireEvent('years', _this, years);
30898 fields : [ 'value' ]
30901 select : function (_self, record, index)
30903 _this.setValue(_this.getValue());
30908 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30911 setValue : function(v, format)
30913 this.inputEl.dom.value = v;
30915 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30917 var d = Date.parseDate(v, f);
30924 this.setDay(d.format(this.dayFormat));
30925 this.setMonth(d.format(this.monthFormat));
30926 this.setYear(d.format(this.yearFormat));
30933 setDay : function(v)
30935 this.dayField.setValue(v);
30936 this.inputEl.dom.value = this.getValue();
30941 setMonth : function(v)
30943 this.monthField.setValue(v, true);
30944 this.inputEl.dom.value = this.getValue();
30949 setYear : function(v)
30951 this.yearField.setValue(v);
30952 this.inputEl.dom.value = this.getValue();
30957 getDay : function()
30959 return this.dayField.getValue();
30962 getMonth : function()
30964 return this.monthField.getValue();
30967 getYear : function()
30969 return this.yearField.getValue();
30972 getValue : function()
30974 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30976 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30986 this.inputEl.dom.value = '';
30991 validate : function()
30993 var d = this.dayField.validate();
30994 var m = this.monthField.validate();
30995 var y = this.yearField.validate();
31000 (!this.dayAllowBlank && !d) ||
31001 (!this.monthAllowBlank && !m) ||
31002 (!this.yearAllowBlank && !y)
31007 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31016 this.markInvalid();
31021 markValid : function()
31024 var label = this.el.select('label', true).first();
31025 var icon = this.el.select('i.fa-star', true).first();
31031 this.fireEvent('valid', this);
31035 * Mark this field as invalid
31036 * @param {String} msg The validation message
31038 markInvalid : function(msg)
31041 var label = this.el.select('label', true).first();
31042 var icon = this.el.select('i.fa-star', true).first();
31044 if(label && !icon){
31045 this.el.select('.roo-date-split-field-label', true).createChild({
31047 cls : 'text-danger fa fa-lg fa-star',
31048 tooltip : 'This field is required',
31049 style : 'margin-right:5px;'
31053 this.fireEvent('invalid', this, msg);
31056 clearInvalid : function()
31058 var label = this.el.select('label', true).first();
31059 var icon = this.el.select('i.fa-star', true).first();
31065 this.fireEvent('valid', this);
31068 getName: function()
31078 * http://masonry.desandro.com
31080 * The idea is to render all the bricks based on vertical width...
31082 * The original code extends 'outlayer' - we might need to use that....
31088 * @class Roo.bootstrap.LayoutMasonry
31089 * @extends Roo.bootstrap.Component
31090 * Bootstrap Layout Masonry class
31093 * Create a new Element
31094 * @param {Object} config The config object
31097 Roo.bootstrap.LayoutMasonry = function(config){
31099 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31103 Roo.bootstrap.LayoutMasonry.register(this);
31109 * Fire after layout the items
31110 * @param {Roo.bootstrap.LayoutMasonry} this
31111 * @param {Roo.EventObject} e
31118 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31121 * @cfg {Boolean} isLayoutInstant = no animation?
31123 isLayoutInstant : false, // needed?
31126 * @cfg {Number} boxWidth width of the columns
31131 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31136 * @cfg {Number} padWidth padding below box..
31141 * @cfg {Number} gutter gutter width..
31146 * @cfg {Number} maxCols maximum number of columns
31152 * @cfg {Boolean} isAutoInitial defalut true
31154 isAutoInitial : true,
31159 * @cfg {Boolean} isHorizontal defalut false
31161 isHorizontal : false,
31163 currentSize : null,
31169 bricks: null, //CompositeElement
31173 _isLayoutInited : false,
31175 // isAlternative : false, // only use for vertical layout...
31178 * @cfg {Number} alternativePadWidth padding below box..
31180 alternativePadWidth : 50,
31182 selectedBrick : [],
31184 getAutoCreate : function(){
31186 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31190 cls: 'blog-masonary-wrapper ' + this.cls,
31192 cls : 'mas-boxes masonary'
31199 getChildContainer: function( )
31201 if (this.boxesEl) {
31202 return this.boxesEl;
31205 this.boxesEl = this.el.select('.mas-boxes').first();
31207 return this.boxesEl;
31211 initEvents : function()
31215 if(this.isAutoInitial){
31216 Roo.log('hook children rendered');
31217 this.on('childrenrendered', function() {
31218 Roo.log('children rendered');
31224 initial : function()
31226 this.selectedBrick = [];
31228 this.currentSize = this.el.getBox(true);
31230 Roo.EventManager.onWindowResize(this.resize, this);
31232 if(!this.isAutoInitial){
31240 //this.layout.defer(500,this);
31244 resize : function()
31246 var cs = this.el.getBox(true);
31249 this.currentSize.width == cs.width &&
31250 this.currentSize.x == cs.x &&
31251 this.currentSize.height == cs.height &&
31252 this.currentSize.y == cs.y
31254 Roo.log("no change in with or X or Y");
31258 this.currentSize = cs;
31264 layout : function()
31266 this._resetLayout();
31268 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31270 this.layoutItems( isInstant );
31272 this._isLayoutInited = true;
31274 this.fireEvent('layout', this);
31278 _resetLayout : function()
31280 if(this.isHorizontal){
31281 this.horizontalMeasureColumns();
31285 this.verticalMeasureColumns();
31289 verticalMeasureColumns : function()
31291 this.getContainerWidth();
31293 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31294 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31298 var boxWidth = this.boxWidth + this.padWidth;
31300 if(this.containerWidth < this.boxWidth){
31301 boxWidth = this.containerWidth
31304 var containerWidth = this.containerWidth;
31306 var cols = Math.floor(containerWidth / boxWidth);
31308 this.cols = Math.max( cols, 1 );
31310 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31312 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31314 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31316 this.colWidth = boxWidth + avail - this.padWidth;
31318 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31319 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31322 horizontalMeasureColumns : function()
31324 this.getContainerWidth();
31326 var boxWidth = this.boxWidth;
31328 if(this.containerWidth < boxWidth){
31329 boxWidth = this.containerWidth;
31332 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31334 this.el.setHeight(boxWidth);
31338 getContainerWidth : function()
31340 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31343 layoutItems : function( isInstant )
31345 Roo.log(this.bricks);
31347 var items = Roo.apply([], this.bricks);
31349 if(this.isHorizontal){
31350 this._horizontalLayoutItems( items , isInstant );
31354 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31355 // this._verticalAlternativeLayoutItems( items , isInstant );
31359 this._verticalLayoutItems( items , isInstant );
31363 _verticalLayoutItems : function ( items , isInstant)
31365 if ( !items || !items.length ) {
31370 ['xs', 'xs', 'xs', 'tall'],
31371 ['xs', 'xs', 'tall'],
31372 ['xs', 'xs', 'sm'],
31373 ['xs', 'xs', 'xs'],
31379 ['sm', 'xs', 'xs'],
31383 ['tall', 'xs', 'xs', 'xs'],
31384 ['tall', 'xs', 'xs'],
31396 Roo.each(items, function(item, k){
31398 switch (item.size) {
31399 // these layouts take up a full box,
31410 boxes.push([item]);
31433 var filterPattern = function(box, length)
31441 var pattern = box.slice(0, length);
31445 Roo.each(pattern, function(i){
31446 format.push(i.size);
31449 Roo.each(standard, function(s){
31451 if(String(s) != String(format)){
31460 if(!match && length == 1){
31465 filterPattern(box, length - 1);
31469 queue.push(pattern);
31471 box = box.slice(length, box.length);
31473 filterPattern(box, 4);
31479 Roo.each(boxes, function(box, k){
31485 if(box.length == 1){
31490 filterPattern(box, 4);
31494 this._processVerticalLayoutQueue( queue, isInstant );
31498 // _verticalAlternativeLayoutItems : function( items , isInstant )
31500 // if ( !items || !items.length ) {
31504 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31508 _horizontalLayoutItems : function ( items , isInstant)
31510 if ( !items || !items.length || items.length < 3) {
31516 var eItems = items.slice(0, 3);
31518 items = items.slice(3, items.length);
31521 ['xs', 'xs', 'xs', 'wide'],
31522 ['xs', 'xs', 'wide'],
31523 ['xs', 'xs', 'sm'],
31524 ['xs', 'xs', 'xs'],
31530 ['sm', 'xs', 'xs'],
31534 ['wide', 'xs', 'xs', 'xs'],
31535 ['wide', 'xs', 'xs'],
31548 Roo.each(items, function(item, k){
31550 switch (item.size) {
31561 boxes.push([item]);
31585 var filterPattern = function(box, length)
31593 var pattern = box.slice(0, length);
31597 Roo.each(pattern, function(i){
31598 format.push(i.size);
31601 Roo.each(standard, function(s){
31603 if(String(s) != String(format)){
31612 if(!match && length == 1){
31617 filterPattern(box, length - 1);
31621 queue.push(pattern);
31623 box = box.slice(length, box.length);
31625 filterPattern(box, 4);
31631 Roo.each(boxes, function(box, k){
31637 if(box.length == 1){
31642 filterPattern(box, 4);
31649 var pos = this.el.getBox(true);
31653 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31655 var hit_end = false;
31657 Roo.each(queue, function(box){
31661 Roo.each(box, function(b){
31663 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31673 Roo.each(box, function(b){
31675 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31678 mx = Math.max(mx, b.x);
31682 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31686 Roo.each(box, function(b){
31688 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31702 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31705 /** Sets position of item in DOM
31706 * @param {Element} item
31707 * @param {Number} x - horizontal position
31708 * @param {Number} y - vertical position
31709 * @param {Boolean} isInstant - disables transitions
31711 _processVerticalLayoutQueue : function( queue, isInstant )
31713 var pos = this.el.getBox(true);
31718 for (var i = 0; i < this.cols; i++){
31722 Roo.each(queue, function(box, k){
31724 var col = k % this.cols;
31726 Roo.each(box, function(b,kk){
31728 b.el.position('absolute');
31730 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31731 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31733 if(b.size == 'md-left' || b.size == 'md-right'){
31734 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31735 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31738 b.el.setWidth(width);
31739 b.el.setHeight(height);
31741 b.el.select('iframe',true).setSize(width,height);
31745 for (var i = 0; i < this.cols; i++){
31747 if(maxY[i] < maxY[col]){
31752 col = Math.min(col, i);
31756 x = pos.x + col * (this.colWidth + this.padWidth);
31760 var positions = [];
31762 switch (box.length){
31764 positions = this.getVerticalOneBoxColPositions(x, y, box);
31767 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31770 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31773 positions = this.getVerticalFourBoxColPositions(x, y, box);
31779 Roo.each(box, function(b,kk){
31781 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31783 var sz = b.el.getSize();
31785 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31793 for (var i = 0; i < this.cols; i++){
31794 mY = Math.max(mY, maxY[i]);
31797 this.el.setHeight(mY - pos.y);
31801 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31803 // var pos = this.el.getBox(true);
31806 // var maxX = pos.right;
31808 // var maxHeight = 0;
31810 // Roo.each(items, function(item, k){
31814 // item.el.position('absolute');
31816 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31818 // item.el.setWidth(width);
31820 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31822 // item.el.setHeight(height);
31825 // item.el.setXY([x, y], isInstant ? false : true);
31827 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31830 // y = y + height + this.alternativePadWidth;
31832 // maxHeight = maxHeight + height + this.alternativePadWidth;
31836 // this.el.setHeight(maxHeight);
31840 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31842 var pos = this.el.getBox(true);
31847 var maxX = pos.right;
31849 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31851 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31853 Roo.each(queue, function(box, k){
31855 Roo.each(box, function(b, kk){
31857 b.el.position('absolute');
31859 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31860 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31862 if(b.size == 'md-left' || b.size == 'md-right'){
31863 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31864 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31867 b.el.setWidth(width);
31868 b.el.setHeight(height);
31876 var positions = [];
31878 switch (box.length){
31880 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31883 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31886 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31889 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31895 Roo.each(box, function(b,kk){
31897 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31899 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31907 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31909 Roo.each(eItems, function(b,k){
31911 b.size = (k == 0) ? 'sm' : 'xs';
31912 b.x = (k == 0) ? 2 : 1;
31913 b.y = (k == 0) ? 2 : 1;
31915 b.el.position('absolute');
31917 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31919 b.el.setWidth(width);
31921 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31923 b.el.setHeight(height);
31927 var positions = [];
31930 x : maxX - this.unitWidth * 2 - this.gutter,
31935 x : maxX - this.unitWidth,
31936 y : minY + (this.unitWidth + this.gutter) * 2
31940 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31944 Roo.each(eItems, function(b,k){
31946 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31952 getVerticalOneBoxColPositions : function(x, y, box)
31956 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31958 if(box[0].size == 'md-left'){
31962 if(box[0].size == 'md-right'){
31967 x : x + (this.unitWidth + this.gutter) * rand,
31974 getVerticalTwoBoxColPositions : function(x, y, box)
31978 if(box[0].size == 'xs'){
31982 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31986 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
32000 x : x + (this.unitWidth + this.gutter) * 2,
32001 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32008 getVerticalThreeBoxColPositions : function(x, y, box)
32012 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32020 x : x + (this.unitWidth + this.gutter) * 1,
32025 x : x + (this.unitWidth + this.gutter) * 2,
32033 if(box[0].size == 'xs' && box[1].size == 'xs'){
32042 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32046 x : x + (this.unitWidth + this.gutter) * 1,
32060 x : x + (this.unitWidth + this.gutter) * 2,
32065 x : x + (this.unitWidth + this.gutter) * 2,
32066 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32073 getVerticalFourBoxColPositions : function(x, y, box)
32077 if(box[0].size == 'xs'){
32086 y : y + (this.unitHeight + this.gutter) * 1
32091 y : y + (this.unitHeight + this.gutter) * 2
32095 x : x + (this.unitWidth + this.gutter) * 1,
32109 x : x + (this.unitWidth + this.gutter) * 2,
32114 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32115 y : y + (this.unitHeight + this.gutter) * 1
32119 x : x + (this.unitWidth + this.gutter) * 2,
32120 y : y + (this.unitWidth + this.gutter) * 2
32127 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32131 if(box[0].size == 'md-left'){
32133 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32140 if(box[0].size == 'md-right'){
32142 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32143 y : minY + (this.unitWidth + this.gutter) * 1
32149 var rand = Math.floor(Math.random() * (4 - box[0].y));
32152 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32153 y : minY + (this.unitWidth + this.gutter) * rand
32160 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32164 if(box[0].size == 'xs'){
32167 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32172 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32173 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32181 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32186 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32187 y : minY + (this.unitWidth + this.gutter) * 2
32194 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32198 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32201 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32206 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32207 y : minY + (this.unitWidth + this.gutter) * 1
32211 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32212 y : minY + (this.unitWidth + this.gutter) * 2
32219 if(box[0].size == 'xs' && box[1].size == 'xs'){
32222 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32227 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32232 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32233 y : minY + (this.unitWidth + this.gutter) * 1
32241 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32246 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32247 y : minY + (this.unitWidth + this.gutter) * 2
32251 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32252 y : minY + (this.unitWidth + this.gutter) * 2
32259 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32263 if(box[0].size == 'xs'){
32266 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32271 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32276 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),
32281 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32282 y : minY + (this.unitWidth + this.gutter) * 1
32290 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32295 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32296 y : minY + (this.unitWidth + this.gutter) * 2
32300 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32301 y : minY + (this.unitWidth + this.gutter) * 2
32305 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),
32306 y : minY + (this.unitWidth + this.gutter) * 2
32314 * remove a Masonry Brick
32315 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32317 removeBrick : function(brick_id)
32323 for (var i = 0; i<this.bricks.length; i++) {
32324 if (this.bricks[i].id == brick_id) {
32325 this.bricks.splice(i,1);
32326 this.el.dom.removeChild(Roo.get(brick_id).dom);
32333 * adds a Masonry Brick
32334 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32336 addBrick : function(cfg)
32338 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32339 //this.register(cn);
32340 cn.parentId = this.id;
32341 cn.render(this.el);
32346 * register a Masonry Brick
32347 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32350 register : function(brick)
32352 this.bricks.push(brick);
32353 brick.masonryId = this.id;
32357 * clear all the Masonry Brick
32359 clearAll : function()
32362 //this.getChildContainer().dom.innerHTML = "";
32363 this.el.dom.innerHTML = '';
32366 getSelected : function()
32368 if (!this.selectedBrick) {
32372 return this.selectedBrick;
32376 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32380 * register a Masonry Layout
32381 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32384 register : function(layout)
32386 this.groups[layout.id] = layout;
32389 * fetch a Masonry Layout based on the masonry layout ID
32390 * @param {string} the masonry layout to add
32391 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32394 get: function(layout_id) {
32395 if (typeof(this.groups[layout_id]) == 'undefined') {
32398 return this.groups[layout_id] ;
32410 * http://masonry.desandro.com
32412 * The idea is to render all the bricks based on vertical width...
32414 * The original code extends 'outlayer' - we might need to use that....
32420 * @class Roo.bootstrap.LayoutMasonryAuto
32421 * @extends Roo.bootstrap.Component
32422 * Bootstrap Layout Masonry class
32425 * Create a new Element
32426 * @param {Object} config The config object
32429 Roo.bootstrap.LayoutMasonryAuto = function(config){
32430 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32433 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32436 * @cfg {Boolean} isFitWidth - resize the width..
32438 isFitWidth : false, // options..
32440 * @cfg {Boolean} isOriginLeft = left align?
32442 isOriginLeft : true,
32444 * @cfg {Boolean} isOriginTop = top align?
32446 isOriginTop : false,
32448 * @cfg {Boolean} isLayoutInstant = no animation?
32450 isLayoutInstant : false, // needed?
32452 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32454 isResizingContainer : true,
32456 * @cfg {Number} columnWidth width of the columns
32462 * @cfg {Number} maxCols maximum number of columns
32467 * @cfg {Number} padHeight padding below box..
32473 * @cfg {Boolean} isAutoInitial defalut true
32476 isAutoInitial : true,
32482 initialColumnWidth : 0,
32483 currentSize : null,
32485 colYs : null, // array.
32492 bricks: null, //CompositeElement
32493 cols : 0, // array?
32494 // element : null, // wrapped now this.el
32495 _isLayoutInited : null,
32498 getAutoCreate : function(){
32502 cls: 'blog-masonary-wrapper ' + this.cls,
32504 cls : 'mas-boxes masonary'
32511 getChildContainer: function( )
32513 if (this.boxesEl) {
32514 return this.boxesEl;
32517 this.boxesEl = this.el.select('.mas-boxes').first();
32519 return this.boxesEl;
32523 initEvents : function()
32527 if(this.isAutoInitial){
32528 Roo.log('hook children rendered');
32529 this.on('childrenrendered', function() {
32530 Roo.log('children rendered');
32537 initial : function()
32539 this.reloadItems();
32541 this.currentSize = this.el.getBox(true);
32543 /// was window resize... - let's see if this works..
32544 Roo.EventManager.onWindowResize(this.resize, this);
32546 if(!this.isAutoInitial){
32551 this.layout.defer(500,this);
32554 reloadItems: function()
32556 this.bricks = this.el.select('.masonry-brick', true);
32558 this.bricks.each(function(b) {
32559 //Roo.log(b.getSize());
32560 if (!b.attr('originalwidth')) {
32561 b.attr('originalwidth', b.getSize().width);
32566 Roo.log(this.bricks.elements.length);
32569 resize : function()
32572 var cs = this.el.getBox(true);
32574 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32575 Roo.log("no change in with or X");
32578 this.currentSize = cs;
32582 layout : function()
32585 this._resetLayout();
32586 //this._manageStamps();
32588 // don't animate first layout
32589 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32590 this.layoutItems( isInstant );
32592 // flag for initalized
32593 this._isLayoutInited = true;
32596 layoutItems : function( isInstant )
32598 //var items = this._getItemsForLayout( this.items );
32599 // original code supports filtering layout items.. we just ignore it..
32601 this._layoutItems( this.bricks , isInstant );
32603 this._postLayout();
32605 _layoutItems : function ( items , isInstant)
32607 //this.fireEvent( 'layout', this, items );
32610 if ( !items || !items.elements.length ) {
32611 // no items, emit event with empty array
32616 items.each(function(item) {
32617 Roo.log("layout item");
32619 // get x/y object from method
32620 var position = this._getItemLayoutPosition( item );
32622 position.item = item;
32623 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32624 queue.push( position );
32627 this._processLayoutQueue( queue );
32629 /** Sets position of item in DOM
32630 * @param {Element} item
32631 * @param {Number} x - horizontal position
32632 * @param {Number} y - vertical position
32633 * @param {Boolean} isInstant - disables transitions
32635 _processLayoutQueue : function( queue )
32637 for ( var i=0, len = queue.length; i < len; i++ ) {
32638 var obj = queue[i];
32639 obj.item.position('absolute');
32640 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32646 * Any logic you want to do after each layout,
32647 * i.e. size the container
32649 _postLayout : function()
32651 this.resizeContainer();
32654 resizeContainer : function()
32656 if ( !this.isResizingContainer ) {
32659 var size = this._getContainerSize();
32661 this.el.setSize(size.width,size.height);
32662 this.boxesEl.setSize(size.width,size.height);
32668 _resetLayout : function()
32670 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32671 this.colWidth = this.el.getWidth();
32672 //this.gutter = this.el.getWidth();
32674 this.measureColumns();
32680 this.colYs.push( 0 );
32686 measureColumns : function()
32688 this.getContainerWidth();
32689 // if columnWidth is 0, default to outerWidth of first item
32690 if ( !this.columnWidth ) {
32691 var firstItem = this.bricks.first();
32692 Roo.log(firstItem);
32693 this.columnWidth = this.containerWidth;
32694 if (firstItem && firstItem.attr('originalwidth') ) {
32695 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32697 // columnWidth fall back to item of first element
32698 Roo.log("set column width?");
32699 this.initialColumnWidth = this.columnWidth ;
32701 // if first elem has no width, default to size of container
32706 if (this.initialColumnWidth) {
32707 this.columnWidth = this.initialColumnWidth;
32712 // column width is fixed at the top - however if container width get's smaller we should
32715 // this bit calcs how man columns..
32717 var columnWidth = this.columnWidth += this.gutter;
32719 // calculate columns
32720 var containerWidth = this.containerWidth + this.gutter;
32722 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32723 // fix rounding errors, typically with gutters
32724 var excess = columnWidth - containerWidth % columnWidth;
32727 // if overshoot is less than a pixel, round up, otherwise floor it
32728 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32729 cols = Math[ mathMethod ]( cols );
32730 this.cols = Math.max( cols, 1 );
32731 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32733 // padding positioning..
32734 var totalColWidth = this.cols * this.columnWidth;
32735 var padavail = this.containerWidth - totalColWidth;
32736 // so for 2 columns - we need 3 'pads'
32738 var padNeeded = (1+this.cols) * this.padWidth;
32740 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32742 this.columnWidth += padExtra
32743 //this.padWidth = Math.floor(padavail / ( this.cols));
32745 // adjust colum width so that padding is fixed??
32747 // we have 3 columns ... total = width * 3
32748 // we have X left over... that should be used by
32750 //if (this.expandC) {
32758 getContainerWidth : function()
32760 /* // container is parent if fit width
32761 var container = this.isFitWidth ? this.element.parentNode : this.element;
32762 // check that this.size and size are there
32763 // IE8 triggers resize on body size change, so they might not be
32765 var size = getSize( container ); //FIXME
32766 this.containerWidth = size && size.innerWidth; //FIXME
32769 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32773 _getItemLayoutPosition : function( item ) // what is item?
32775 // we resize the item to our columnWidth..
32777 item.setWidth(this.columnWidth);
32778 item.autoBoxAdjust = false;
32780 var sz = item.getSize();
32782 // how many columns does this brick span
32783 var remainder = this.containerWidth % this.columnWidth;
32785 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32786 // round if off by 1 pixel, otherwise use ceil
32787 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32788 colSpan = Math.min( colSpan, this.cols );
32790 // normally this should be '1' as we dont' currently allow multi width columns..
32792 var colGroup = this._getColGroup( colSpan );
32793 // get the minimum Y value from the columns
32794 var minimumY = Math.min.apply( Math, colGroup );
32795 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32797 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32799 // position the brick
32801 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32802 y: this.currentSize.y + minimumY + this.padHeight
32806 // apply setHeight to necessary columns
32807 var setHeight = minimumY + sz.height + this.padHeight;
32808 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32810 var setSpan = this.cols + 1 - colGroup.length;
32811 for ( var i = 0; i < setSpan; i++ ) {
32812 this.colYs[ shortColIndex + i ] = setHeight ;
32819 * @param {Number} colSpan - number of columns the element spans
32820 * @returns {Array} colGroup
32822 _getColGroup : function( colSpan )
32824 if ( colSpan < 2 ) {
32825 // if brick spans only one column, use all the column Ys
32830 // how many different places could this brick fit horizontally
32831 var groupCount = this.cols + 1 - colSpan;
32832 // for each group potential horizontal position
32833 for ( var i = 0; i < groupCount; i++ ) {
32834 // make an array of colY values for that one group
32835 var groupColYs = this.colYs.slice( i, i + colSpan );
32836 // and get the max value of the array
32837 colGroup[i] = Math.max.apply( Math, groupColYs );
32842 _manageStamp : function( stamp )
32844 var stampSize = stamp.getSize();
32845 var offset = stamp.getBox();
32846 // get the columns that this stamp affects
32847 var firstX = this.isOriginLeft ? offset.x : offset.right;
32848 var lastX = firstX + stampSize.width;
32849 var firstCol = Math.floor( firstX / this.columnWidth );
32850 firstCol = Math.max( 0, firstCol );
32852 var lastCol = Math.floor( lastX / this.columnWidth );
32853 // lastCol should not go over if multiple of columnWidth #425
32854 lastCol -= lastX % this.columnWidth ? 0 : 1;
32855 lastCol = Math.min( this.cols - 1, lastCol );
32857 // set colYs to bottom of the stamp
32858 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32861 for ( var i = firstCol; i <= lastCol; i++ ) {
32862 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32867 _getContainerSize : function()
32869 this.maxY = Math.max.apply( Math, this.colYs );
32874 if ( this.isFitWidth ) {
32875 size.width = this._getContainerFitWidth();
32881 _getContainerFitWidth : function()
32883 var unusedCols = 0;
32884 // count unused columns
32887 if ( this.colYs[i] !== 0 ) {
32892 // fit container to columns that have been used
32893 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32896 needsResizeLayout : function()
32898 var previousWidth = this.containerWidth;
32899 this.getContainerWidth();
32900 return previousWidth !== this.containerWidth;
32915 * @class Roo.bootstrap.MasonryBrick
32916 * @extends Roo.bootstrap.Component
32917 * Bootstrap MasonryBrick class
32920 * Create a new MasonryBrick
32921 * @param {Object} config The config object
32924 Roo.bootstrap.MasonryBrick = function(config){
32926 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32928 Roo.bootstrap.MasonryBrick.register(this);
32934 * When a MasonryBrick is clcik
32935 * @param {Roo.bootstrap.MasonryBrick} this
32936 * @param {Roo.EventObject} e
32942 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32945 * @cfg {String} title
32949 * @cfg {String} html
32953 * @cfg {String} bgimage
32957 * @cfg {String} videourl
32961 * @cfg {String} cls
32965 * @cfg {String} href
32969 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32974 * @cfg {String} placetitle (center|bottom)
32979 * @cfg {Boolean} isFitContainer defalut true
32981 isFitContainer : true,
32984 * @cfg {Boolean} preventDefault defalut false
32986 preventDefault : false,
32989 * @cfg {Boolean} inverse defalut false
32991 maskInverse : false,
32993 getAutoCreate : function()
32995 if(!this.isFitContainer){
32996 return this.getSplitAutoCreate();
32999 var cls = 'masonry-brick masonry-brick-full';
33001 if(this.href.length){
33002 cls += ' masonry-brick-link';
33005 if(this.bgimage.length){
33006 cls += ' masonry-brick-image';
33009 if(this.maskInverse){
33010 cls += ' mask-inverse';
33013 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33014 cls += ' enable-mask';
33018 cls += ' masonry-' + this.size + '-brick';
33021 if(this.placetitle.length){
33023 switch (this.placetitle) {
33025 cls += ' masonry-center-title';
33028 cls += ' masonry-bottom-title';
33035 if(!this.html.length && !this.bgimage.length){
33036 cls += ' masonry-center-title';
33039 if(!this.html.length && this.bgimage.length){
33040 cls += ' masonry-bottom-title';
33045 cls += ' ' + this.cls;
33049 tag: (this.href.length) ? 'a' : 'div',
33054 cls: 'masonry-brick-mask'
33058 cls: 'masonry-brick-paragraph',
33064 if(this.href.length){
33065 cfg.href = this.href;
33068 var cn = cfg.cn[1].cn;
33070 if(this.title.length){
33073 cls: 'masonry-brick-title',
33078 if(this.html.length){
33081 cls: 'masonry-brick-text',
33086 if (!this.title.length && !this.html.length) {
33087 cfg.cn[1].cls += ' hide';
33090 if(this.bgimage.length){
33093 cls: 'masonry-brick-image-view',
33098 if(this.videourl.length){
33099 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33100 // youtube support only?
33103 cls: 'masonry-brick-image-view',
33106 allowfullscreen : true
33114 getSplitAutoCreate : function()
33116 var cls = 'masonry-brick masonry-brick-split';
33118 if(this.href.length){
33119 cls += ' masonry-brick-link';
33122 if(this.bgimage.length){
33123 cls += ' masonry-brick-image';
33127 cls += ' masonry-' + this.size + '-brick';
33130 switch (this.placetitle) {
33132 cls += ' masonry-center-title';
33135 cls += ' masonry-bottom-title';
33138 if(!this.bgimage.length){
33139 cls += ' masonry-center-title';
33142 if(this.bgimage.length){
33143 cls += ' masonry-bottom-title';
33149 cls += ' ' + this.cls;
33153 tag: (this.href.length) ? 'a' : 'div',
33158 cls: 'masonry-brick-split-head',
33162 cls: 'masonry-brick-paragraph',
33169 cls: 'masonry-brick-split-body',
33175 if(this.href.length){
33176 cfg.href = this.href;
33179 if(this.title.length){
33180 cfg.cn[0].cn[0].cn.push({
33182 cls: 'masonry-brick-title',
33187 if(this.html.length){
33188 cfg.cn[1].cn.push({
33190 cls: 'masonry-brick-text',
33195 if(this.bgimage.length){
33196 cfg.cn[0].cn.push({
33198 cls: 'masonry-brick-image-view',
33203 if(this.videourl.length){
33204 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33205 // youtube support only?
33206 cfg.cn[0].cn.cn.push({
33208 cls: 'masonry-brick-image-view',
33211 allowfullscreen : true
33218 initEvents: function()
33220 switch (this.size) {
33253 this.el.on('touchstart', this.onTouchStart, this);
33254 this.el.on('touchmove', this.onTouchMove, this);
33255 this.el.on('touchend', this.onTouchEnd, this);
33256 this.el.on('contextmenu', this.onContextMenu, this);
33258 this.el.on('mouseenter' ,this.enter, this);
33259 this.el.on('mouseleave', this.leave, this);
33260 this.el.on('click', this.onClick, this);
33263 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33264 this.parent().bricks.push(this);
33269 onClick: function(e, el)
33271 var time = this.endTimer - this.startTimer;
33272 // Roo.log(e.preventDefault());
33275 e.preventDefault();
33280 if(!this.preventDefault){
33284 e.preventDefault();
33286 if (this.activeClass != '') {
33287 this.selectBrick();
33290 this.fireEvent('click', this, e);
33293 enter: function(e, el)
33295 e.preventDefault();
33297 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33301 if(this.bgimage.length && this.html.length){
33302 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33306 leave: function(e, el)
33308 e.preventDefault();
33310 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33314 if(this.bgimage.length && this.html.length){
33315 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33319 onTouchStart: function(e, el)
33321 // e.preventDefault();
33323 this.touchmoved = false;
33325 if(!this.isFitContainer){
33329 if(!this.bgimage.length || !this.html.length){
33333 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33335 this.timer = new Date().getTime();
33339 onTouchMove: function(e, el)
33341 this.touchmoved = true;
33344 onContextMenu : function(e,el)
33346 e.preventDefault();
33347 e.stopPropagation();
33351 onTouchEnd: function(e, el)
33353 // e.preventDefault();
33355 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33362 if(!this.bgimage.length || !this.html.length){
33364 if(this.href.length){
33365 window.location.href = this.href;
33371 if(!this.isFitContainer){
33375 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33377 window.location.href = this.href;
33380 //selection on single brick only
33381 selectBrick : function() {
33383 if (!this.parentId) {
33387 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33388 var index = m.selectedBrick.indexOf(this.id);
33391 m.selectedBrick.splice(index,1);
33392 this.el.removeClass(this.activeClass);
33396 for(var i = 0; i < m.selectedBrick.length; i++) {
33397 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33398 b.el.removeClass(b.activeClass);
33401 m.selectedBrick = [];
33403 m.selectedBrick.push(this.id);
33404 this.el.addClass(this.activeClass);
33408 isSelected : function(){
33409 return this.el.hasClass(this.activeClass);
33414 Roo.apply(Roo.bootstrap.MasonryBrick, {
33417 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33419 * register a Masonry Brick
33420 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33423 register : function(brick)
33425 //this.groups[brick.id] = brick;
33426 this.groups.add(brick.id, brick);
33429 * fetch a masonry brick based on the masonry brick ID
33430 * @param {string} the masonry brick to add
33431 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33434 get: function(brick_id)
33436 // if (typeof(this.groups[brick_id]) == 'undefined') {
33439 // return this.groups[brick_id] ;
33441 if(this.groups.key(brick_id)) {
33442 return this.groups.key(brick_id);
33460 * @class Roo.bootstrap.Brick
33461 * @extends Roo.bootstrap.Component
33462 * Bootstrap Brick class
33465 * Create a new Brick
33466 * @param {Object} config The config object
33469 Roo.bootstrap.Brick = function(config){
33470 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33476 * When a Brick is click
33477 * @param {Roo.bootstrap.Brick} this
33478 * @param {Roo.EventObject} e
33484 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33487 * @cfg {String} title
33491 * @cfg {String} html
33495 * @cfg {String} bgimage
33499 * @cfg {String} cls
33503 * @cfg {String} href
33507 * @cfg {String} video
33511 * @cfg {Boolean} square
33515 getAutoCreate : function()
33517 var cls = 'roo-brick';
33519 if(this.href.length){
33520 cls += ' roo-brick-link';
33523 if(this.bgimage.length){
33524 cls += ' roo-brick-image';
33527 if(!this.html.length && !this.bgimage.length){
33528 cls += ' roo-brick-center-title';
33531 if(!this.html.length && this.bgimage.length){
33532 cls += ' roo-brick-bottom-title';
33536 cls += ' ' + this.cls;
33540 tag: (this.href.length) ? 'a' : 'div',
33545 cls: 'roo-brick-paragraph',
33551 if(this.href.length){
33552 cfg.href = this.href;
33555 var cn = cfg.cn[0].cn;
33557 if(this.title.length){
33560 cls: 'roo-brick-title',
33565 if(this.html.length){
33568 cls: 'roo-brick-text',
33575 if(this.bgimage.length){
33578 cls: 'roo-brick-image-view',
33586 initEvents: function()
33588 if(this.title.length || this.html.length){
33589 this.el.on('mouseenter' ,this.enter, this);
33590 this.el.on('mouseleave', this.leave, this);
33593 Roo.EventManager.onWindowResize(this.resize, this);
33595 if(this.bgimage.length){
33596 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33597 this.imageEl.on('load', this.onImageLoad, this);
33604 onImageLoad : function()
33609 resize : function()
33611 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33613 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33615 if(this.bgimage.length){
33616 var image = this.el.select('.roo-brick-image-view', true).first();
33618 image.setWidth(paragraph.getWidth());
33621 image.setHeight(paragraph.getWidth());
33624 this.el.setHeight(image.getHeight());
33625 paragraph.setHeight(image.getHeight());
33631 enter: function(e, el)
33633 e.preventDefault();
33635 if(this.bgimage.length){
33636 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33637 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33641 leave: function(e, el)
33643 e.preventDefault();
33645 if(this.bgimage.length){
33646 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33647 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33662 * @class Roo.bootstrap.NumberField
33663 * @extends Roo.bootstrap.Input
33664 * Bootstrap NumberField class
33670 * Create a new NumberField
33671 * @param {Object} config The config object
33674 Roo.bootstrap.NumberField = function(config){
33675 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33678 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33681 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33683 allowDecimals : true,
33685 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33687 decimalSeparator : ".",
33689 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33691 decimalPrecision : 2,
33693 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33695 allowNegative : true,
33698 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33702 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33704 minValue : Number.NEGATIVE_INFINITY,
33706 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33708 maxValue : Number.MAX_VALUE,
33710 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33712 minText : "The minimum value for this field is {0}",
33714 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33716 maxText : "The maximum value for this field is {0}",
33718 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33719 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33721 nanText : "{0} is not a valid number",
33723 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33725 thousandsDelimiter : false,
33727 * @cfg {String} valueAlign alignment of value
33729 valueAlign : "left",
33731 getAutoCreate : function()
33733 var hiddenInput = {
33737 cls: 'hidden-number-input'
33741 hiddenInput.name = this.name;
33746 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33748 this.name = hiddenInput.name;
33750 if(cfg.cn.length > 0) {
33751 cfg.cn.push(hiddenInput);
33758 initEvents : function()
33760 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33762 var allowed = "0123456789";
33764 if(this.allowDecimals){
33765 allowed += this.decimalSeparator;
33768 if(this.allowNegative){
33772 if(this.thousandsDelimiter) {
33776 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33778 var keyPress = function(e){
33780 var k = e.getKey();
33782 var c = e.getCharCode();
33785 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33786 allowed.indexOf(String.fromCharCode(c)) === -1
33792 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33796 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33801 this.el.on("keypress", keyPress, this);
33804 validateValue : function(value)
33807 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33811 var num = this.parseValue(value);
33814 this.markInvalid(String.format(this.nanText, value));
33818 if(num < this.minValue){
33819 this.markInvalid(String.format(this.minText, this.minValue));
33823 if(num > this.maxValue){
33824 this.markInvalid(String.format(this.maxText, this.maxValue));
33831 getValue : function()
33833 var v = this.hiddenEl().getValue();
33835 return this.fixPrecision(this.parseValue(v));
33838 parseValue : function(value)
33840 if(this.thousandsDelimiter) {
33842 r = new RegExp(",", "g");
33843 value = value.replace(r, "");
33846 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33847 return isNaN(value) ? '' : value;
33850 fixPrecision : function(value)
33852 if(this.thousandsDelimiter) {
33854 r = new RegExp(",", "g");
33855 value = value.replace(r, "");
33858 var nan = isNaN(value);
33860 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33861 return nan ? '' : value;
33863 return parseFloat(value).toFixed(this.decimalPrecision);
33866 setValue : function(v)
33868 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33874 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33876 this.inputEl().dom.value = (v == '') ? '' :
33877 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33879 if(!this.allowZero && v === '0') {
33880 this.hiddenEl().dom.value = '';
33881 this.inputEl().dom.value = '';
33888 decimalPrecisionFcn : function(v)
33890 return Math.floor(v);
33893 beforeBlur : function()
33895 var v = this.parseValue(this.getRawValue());
33897 if(v || v === 0 || v === ''){
33902 hiddenEl : function()
33904 return this.el.select('input.hidden-number-input',true).first();
33916 * @class Roo.bootstrap.DocumentSlider
33917 * @extends Roo.bootstrap.Component
33918 * Bootstrap DocumentSlider class
33921 * Create a new DocumentViewer
33922 * @param {Object} config The config object
33925 Roo.bootstrap.DocumentSlider = function(config){
33926 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33933 * Fire after initEvent
33934 * @param {Roo.bootstrap.DocumentSlider} this
33939 * Fire after update
33940 * @param {Roo.bootstrap.DocumentSlider} this
33946 * @param {Roo.bootstrap.DocumentSlider} this
33952 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33958 getAutoCreate : function()
33962 cls : 'roo-document-slider',
33966 cls : 'roo-document-slider-header',
33970 cls : 'roo-document-slider-header-title'
33976 cls : 'roo-document-slider-body',
33980 cls : 'roo-document-slider-prev',
33984 cls : 'fa fa-chevron-left'
33990 cls : 'roo-document-slider-thumb',
33994 cls : 'roo-document-slider-image'
34000 cls : 'roo-document-slider-next',
34004 cls : 'fa fa-chevron-right'
34016 initEvents : function()
34018 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34019 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34021 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34022 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34024 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34025 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34027 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34028 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34030 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34031 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34033 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34034 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34036 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34037 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34039 this.thumbEl.on('click', this.onClick, this);
34041 this.prevIndicator.on('click', this.prev, this);
34043 this.nextIndicator.on('click', this.next, this);
34047 initial : function()
34049 if(this.files.length){
34050 this.indicator = 1;
34054 this.fireEvent('initial', this);
34057 update : function()
34059 this.imageEl.attr('src', this.files[this.indicator - 1]);
34061 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34063 this.prevIndicator.show();
34065 if(this.indicator == 1){
34066 this.prevIndicator.hide();
34069 this.nextIndicator.show();
34071 if(this.indicator == this.files.length){
34072 this.nextIndicator.hide();
34075 this.thumbEl.scrollTo('top');
34077 this.fireEvent('update', this);
34080 onClick : function(e)
34082 e.preventDefault();
34084 this.fireEvent('click', this);
34089 e.preventDefault();
34091 this.indicator = Math.max(1, this.indicator - 1);
34098 e.preventDefault();
34100 this.indicator = Math.min(this.files.length, this.indicator + 1);
34114 * @class Roo.bootstrap.RadioSet
34115 * @extends Roo.bootstrap.Input
34116 * Bootstrap RadioSet class
34117 * @cfg {String} indicatorpos (left|right) default left
34118 * @cfg {Boolean} inline (true|false) inline the element (default true)
34119 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34121 * Create a new RadioSet
34122 * @param {Object} config The config object
34125 Roo.bootstrap.RadioSet = function(config){
34127 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34131 Roo.bootstrap.RadioSet.register(this);
34136 * Fires when the element is checked or unchecked.
34137 * @param {Roo.bootstrap.RadioSet} this This radio
34138 * @param {Roo.bootstrap.Radio} item The checked item
34143 * Fires when the element is click.
34144 * @param {Roo.bootstrap.RadioSet} this This radio set
34145 * @param {Roo.bootstrap.Radio} item The checked item
34146 * @param {Roo.EventObject} e The event object
34153 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34161 indicatorpos : 'left',
34163 getAutoCreate : function()
34167 cls : 'roo-radio-set-label',
34171 html : this.fieldLabel
34175 if (Roo.bootstrap.version == 3) {
34178 if(this.indicatorpos == 'left'){
34181 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34182 tooltip : 'This field is required'
34187 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34188 tooltip : 'This field is required'
34194 cls : 'roo-radio-set-items'
34197 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34199 if (align === 'left' && this.fieldLabel.length) {
34202 cls : "roo-radio-set-right",
34208 if(this.labelWidth > 12){
34209 label.style = "width: " + this.labelWidth + 'px';
34212 if(this.labelWidth < 13 && this.labelmd == 0){
34213 this.labelmd = this.labelWidth;
34216 if(this.labellg > 0){
34217 label.cls += ' col-lg-' + this.labellg;
34218 items.cls += ' col-lg-' + (12 - this.labellg);
34221 if(this.labelmd > 0){
34222 label.cls += ' col-md-' + this.labelmd;
34223 items.cls += ' col-md-' + (12 - this.labelmd);
34226 if(this.labelsm > 0){
34227 label.cls += ' col-sm-' + this.labelsm;
34228 items.cls += ' col-sm-' + (12 - this.labelsm);
34231 if(this.labelxs > 0){
34232 label.cls += ' col-xs-' + this.labelxs;
34233 items.cls += ' col-xs-' + (12 - this.labelxs);
34239 cls : 'roo-radio-set',
34243 cls : 'roo-radio-set-input',
34246 value : this.value ? this.value : ''
34253 if(this.weight.length){
34254 cfg.cls += ' roo-radio-' + this.weight;
34258 cfg.cls += ' roo-radio-set-inline';
34262 ['xs','sm','md','lg'].map(function(size){
34263 if (settings[size]) {
34264 cfg.cls += ' col-' + size + '-' + settings[size];
34272 initEvents : function()
34274 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34275 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34277 if(!this.fieldLabel.length){
34278 this.labelEl.hide();
34281 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34282 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34284 this.indicator = this.indicatorEl();
34286 if(this.indicator){
34287 this.indicator.addClass('invisible');
34290 this.originalValue = this.getValue();
34294 inputEl: function ()
34296 return this.el.select('.roo-radio-set-input', true).first();
34299 getChildContainer : function()
34301 return this.itemsEl;
34304 register : function(item)
34306 this.radioes.push(item);
34310 validate : function()
34312 if(this.getVisibilityEl().hasClass('hidden')){
34318 Roo.each(this.radioes, function(i){
34327 if(this.allowBlank) {
34331 if(this.disabled || valid){
34336 this.markInvalid();
34341 markValid : function()
34343 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34344 this.indicatorEl().removeClass('visible');
34345 this.indicatorEl().addClass('invisible');
34349 if (Roo.bootstrap.version == 3) {
34350 this.el.removeClass([this.invalidClass, this.validClass]);
34351 this.el.addClass(this.validClass);
34353 this.el.removeClass(['is-invalid','is-valid']);
34354 this.el.addClass(['is-valid']);
34356 this.fireEvent('valid', this);
34359 markInvalid : function(msg)
34361 if(this.allowBlank || this.disabled){
34365 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34366 this.indicatorEl().removeClass('invisible');
34367 this.indicatorEl().addClass('visible');
34369 if (Roo.bootstrap.version == 3) {
34370 this.el.removeClass([this.invalidClass, this.validClass]);
34371 this.el.addClass(this.invalidClass);
34373 this.el.removeClass(['is-invalid','is-valid']);
34374 this.el.addClass(['is-invalid']);
34377 this.fireEvent('invalid', this, msg);
34381 setValue : function(v, suppressEvent)
34383 if(this.value === v){
34390 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34393 Roo.each(this.radioes, function(i){
34395 i.el.removeClass('checked');
34398 Roo.each(this.radioes, function(i){
34400 if(i.value === v || i.value.toString() === v.toString()){
34402 i.el.addClass('checked');
34404 if(suppressEvent !== true){
34405 this.fireEvent('check', this, i);
34416 clearInvalid : function(){
34418 if(!this.el || this.preventMark){
34422 this.el.removeClass([this.invalidClass]);
34424 this.fireEvent('valid', this);
34429 Roo.apply(Roo.bootstrap.RadioSet, {
34433 register : function(set)
34435 this.groups[set.name] = set;
34438 get: function(name)
34440 if (typeof(this.groups[name]) == 'undefined') {
34444 return this.groups[name] ;
34450 * Ext JS Library 1.1.1
34451 * Copyright(c) 2006-2007, Ext JS, LLC.
34453 * Originally Released Under LGPL - original licence link has changed is not relivant.
34456 * <script type="text/javascript">
34461 * @class Roo.bootstrap.SplitBar
34462 * @extends Roo.util.Observable
34463 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34467 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34468 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34469 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34470 split.minSize = 100;
34471 split.maxSize = 600;
34472 split.animate = true;
34473 split.on('moved', splitterMoved);
34476 * Create a new SplitBar
34477 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34478 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34479 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34480 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34481 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34482 position of the SplitBar).
34484 Roo.bootstrap.SplitBar = function(cfg){
34489 // dragElement : elm
34490 // resizingElement: el,
34492 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34493 // placement : Roo.bootstrap.SplitBar.LEFT ,
34494 // existingProxy ???
34497 this.el = Roo.get(cfg.dragElement, true);
34498 this.el.dom.unselectable = "on";
34500 this.resizingEl = Roo.get(cfg.resizingElement, true);
34504 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34505 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34508 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34511 * The minimum size of the resizing element. (Defaults to 0)
34517 * The maximum size of the resizing element. (Defaults to 2000)
34520 this.maxSize = 2000;
34523 * Whether to animate the transition to the new size
34526 this.animate = false;
34529 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34532 this.useShim = false;
34537 if(!cfg.existingProxy){
34539 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34541 this.proxy = Roo.get(cfg.existingProxy).dom;
34544 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34547 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34550 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34553 this.dragSpecs = {};
34556 * @private The adapter to use to positon and resize elements
34558 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34559 this.adapter.init(this);
34561 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34563 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34564 this.el.addClass("roo-splitbar-h");
34567 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34568 this.el.addClass("roo-splitbar-v");
34574 * Fires when the splitter is moved (alias for {@link #event-moved})
34575 * @param {Roo.bootstrap.SplitBar} this
34576 * @param {Number} newSize the new width or height
34581 * Fires when the splitter is moved
34582 * @param {Roo.bootstrap.SplitBar} this
34583 * @param {Number} newSize the new width or height
34587 * @event beforeresize
34588 * Fires before the splitter is dragged
34589 * @param {Roo.bootstrap.SplitBar} this
34591 "beforeresize" : true,
34593 "beforeapply" : true
34596 Roo.util.Observable.call(this);
34599 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34600 onStartProxyDrag : function(x, y){
34601 this.fireEvent("beforeresize", this);
34603 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34605 o.enableDisplayMode("block");
34606 // all splitbars share the same overlay
34607 Roo.bootstrap.SplitBar.prototype.overlay = o;
34609 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34610 this.overlay.show();
34611 Roo.get(this.proxy).setDisplayed("block");
34612 var size = this.adapter.getElementSize(this);
34613 this.activeMinSize = this.getMinimumSize();;
34614 this.activeMaxSize = this.getMaximumSize();;
34615 var c1 = size - this.activeMinSize;
34616 var c2 = Math.max(this.activeMaxSize - size, 0);
34617 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34618 this.dd.resetConstraints();
34619 this.dd.setXConstraint(
34620 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34621 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34623 this.dd.setYConstraint(0, 0);
34625 this.dd.resetConstraints();
34626 this.dd.setXConstraint(0, 0);
34627 this.dd.setYConstraint(
34628 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34629 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34632 this.dragSpecs.startSize = size;
34633 this.dragSpecs.startPoint = [x, y];
34634 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34638 * @private Called after the drag operation by the DDProxy
34640 onEndProxyDrag : function(e){
34641 Roo.get(this.proxy).setDisplayed(false);
34642 var endPoint = Roo.lib.Event.getXY(e);
34644 this.overlay.hide();
34647 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34648 newSize = this.dragSpecs.startSize +
34649 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34650 endPoint[0] - this.dragSpecs.startPoint[0] :
34651 this.dragSpecs.startPoint[0] - endPoint[0]
34654 newSize = this.dragSpecs.startSize +
34655 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34656 endPoint[1] - this.dragSpecs.startPoint[1] :
34657 this.dragSpecs.startPoint[1] - endPoint[1]
34660 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34661 if(newSize != this.dragSpecs.startSize){
34662 if(this.fireEvent('beforeapply', this, newSize) !== false){
34663 this.adapter.setElementSize(this, newSize);
34664 this.fireEvent("moved", this, newSize);
34665 this.fireEvent("resize", this, newSize);
34671 * Get the adapter this SplitBar uses
34672 * @return The adapter object
34674 getAdapter : function(){
34675 return this.adapter;
34679 * Set the adapter this SplitBar uses
34680 * @param {Object} adapter A SplitBar adapter object
34682 setAdapter : function(adapter){
34683 this.adapter = adapter;
34684 this.adapter.init(this);
34688 * Gets the minimum size for the resizing element
34689 * @return {Number} The minimum size
34691 getMinimumSize : function(){
34692 return this.minSize;
34696 * Sets the minimum size for the resizing element
34697 * @param {Number} minSize The minimum size
34699 setMinimumSize : function(minSize){
34700 this.minSize = minSize;
34704 * Gets the maximum size for the resizing element
34705 * @return {Number} The maximum size
34707 getMaximumSize : function(){
34708 return this.maxSize;
34712 * Sets the maximum size for the resizing element
34713 * @param {Number} maxSize The maximum size
34715 setMaximumSize : function(maxSize){
34716 this.maxSize = maxSize;
34720 * Sets the initialize size for the resizing element
34721 * @param {Number} size The initial size
34723 setCurrentSize : function(size){
34724 var oldAnimate = this.animate;
34725 this.animate = false;
34726 this.adapter.setElementSize(this, size);
34727 this.animate = oldAnimate;
34731 * Destroy this splitbar.
34732 * @param {Boolean} removeEl True to remove the element
34734 destroy : function(removeEl){
34736 this.shim.remove();
34739 this.proxy.parentNode.removeChild(this.proxy);
34747 * @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.
34749 Roo.bootstrap.SplitBar.createProxy = function(dir){
34750 var proxy = new Roo.Element(document.createElement("div"));
34751 proxy.unselectable();
34752 var cls = 'roo-splitbar-proxy';
34753 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34754 document.body.appendChild(proxy.dom);
34759 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34760 * Default Adapter. It assumes the splitter and resizing element are not positioned
34761 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34763 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34766 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34767 // do nothing for now
34768 init : function(s){
34772 * Called before drag operations to get the current size of the resizing element.
34773 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34775 getElementSize : function(s){
34776 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34777 return s.resizingEl.getWidth();
34779 return s.resizingEl.getHeight();
34784 * Called after drag operations to set the size of the resizing element.
34785 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34786 * @param {Number} newSize The new size to set
34787 * @param {Function} onComplete A function to be invoked when resizing is complete
34789 setElementSize : function(s, newSize, onComplete){
34790 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34792 s.resizingEl.setWidth(newSize);
34794 onComplete(s, newSize);
34797 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34802 s.resizingEl.setHeight(newSize);
34804 onComplete(s, newSize);
34807 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34814 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34815 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34816 * Adapter that moves the splitter element to align with the resized sizing element.
34817 * Used with an absolute positioned SplitBar.
34818 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34819 * document.body, make sure you assign an id to the body element.
34821 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34822 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34823 this.container = Roo.get(container);
34826 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34827 init : function(s){
34828 this.basic.init(s);
34831 getElementSize : function(s){
34832 return this.basic.getElementSize(s);
34835 setElementSize : function(s, newSize, onComplete){
34836 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34839 moveSplitter : function(s){
34840 var yes = Roo.bootstrap.SplitBar;
34841 switch(s.placement){
34843 s.el.setX(s.resizingEl.getRight());
34846 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34849 s.el.setY(s.resizingEl.getBottom());
34852 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34859 * Orientation constant - Create a vertical SplitBar
34863 Roo.bootstrap.SplitBar.VERTICAL = 1;
34866 * Orientation constant - Create a horizontal SplitBar
34870 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34873 * Placement constant - The resizing element is to the left of the splitter element
34877 Roo.bootstrap.SplitBar.LEFT = 1;
34880 * Placement constant - The resizing element is to the right of the splitter element
34884 Roo.bootstrap.SplitBar.RIGHT = 2;
34887 * Placement constant - The resizing element is positioned above the splitter element
34891 Roo.bootstrap.SplitBar.TOP = 3;
34894 * Placement constant - The resizing element is positioned under splitter element
34898 Roo.bootstrap.SplitBar.BOTTOM = 4;
34899 Roo.namespace("Roo.bootstrap.layout");/*
34901 * Ext JS Library 1.1.1
34902 * Copyright(c) 2006-2007, Ext JS, LLC.
34904 * Originally Released Under LGPL - original licence link has changed is not relivant.
34907 * <script type="text/javascript">
34911 * @class Roo.bootstrap.layout.Manager
34912 * @extends Roo.bootstrap.Component
34913 * Base class for layout managers.
34915 Roo.bootstrap.layout.Manager = function(config)
34917 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34923 /** false to disable window resize monitoring @type Boolean */
34924 this.monitorWindowResize = true;
34929 * Fires when a layout is performed.
34930 * @param {Roo.LayoutManager} this
34934 * @event regionresized
34935 * Fires when the user resizes a region.
34936 * @param {Roo.LayoutRegion} region The resized region
34937 * @param {Number} newSize The new size (width for east/west, height for north/south)
34939 "regionresized" : true,
34941 * @event regioncollapsed
34942 * Fires when a region is collapsed.
34943 * @param {Roo.LayoutRegion} region The collapsed region
34945 "regioncollapsed" : true,
34947 * @event regionexpanded
34948 * Fires when a region is expanded.
34949 * @param {Roo.LayoutRegion} region The expanded region
34951 "regionexpanded" : true
34953 this.updating = false;
34956 this.el = Roo.get(config.el);
34962 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34967 monitorWindowResize : true,
34973 onRender : function(ct, position)
34976 this.el = Roo.get(ct);
34979 //this.fireEvent('render',this);
34983 initEvents: function()
34987 // ie scrollbar fix
34988 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34989 document.body.scroll = "no";
34990 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34991 this.el.position('relative');
34993 this.id = this.el.id;
34994 this.el.addClass("roo-layout-container");
34995 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34996 if(this.el.dom != document.body ) {
34997 this.el.on('resize', this.layout,this);
34998 this.el.on('show', this.layout,this);
35004 * Returns true if this layout is currently being updated
35005 * @return {Boolean}
35007 isUpdating : function(){
35008 return this.updating;
35012 * Suspend the LayoutManager from doing auto-layouts while
35013 * making multiple add or remove calls
35015 beginUpdate : function(){
35016 this.updating = true;
35020 * Restore auto-layouts and optionally disable the manager from performing a layout
35021 * @param {Boolean} noLayout true to disable a layout update
35023 endUpdate : function(noLayout){
35024 this.updating = false;
35030 layout: function(){
35034 onRegionResized : function(region, newSize){
35035 this.fireEvent("regionresized", region, newSize);
35039 onRegionCollapsed : function(region){
35040 this.fireEvent("regioncollapsed", region);
35043 onRegionExpanded : function(region){
35044 this.fireEvent("regionexpanded", region);
35048 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35049 * performs box-model adjustments.
35050 * @return {Object} The size as an object {width: (the width), height: (the height)}
35052 getViewSize : function()
35055 if(this.el.dom != document.body){
35056 size = this.el.getSize();
35058 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35060 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35061 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35066 * Returns the Element this layout is bound to.
35067 * @return {Roo.Element}
35069 getEl : function(){
35074 * Returns the specified region.
35075 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35076 * @return {Roo.LayoutRegion}
35078 getRegion : function(target){
35079 return this.regions[target.toLowerCase()];
35082 onWindowResize : function(){
35083 if(this.monitorWindowResize){
35090 * Ext JS Library 1.1.1
35091 * Copyright(c) 2006-2007, Ext JS, LLC.
35093 * Originally Released Under LGPL - original licence link has changed is not relivant.
35096 * <script type="text/javascript">
35099 * @class Roo.bootstrap.layout.Border
35100 * @extends Roo.bootstrap.layout.Manager
35101 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35102 * please see: examples/bootstrap/nested.html<br><br>
35104 <b>The container the layout is rendered into can be either the body element or any other element.
35105 If it is not the body element, the container needs to either be an absolute positioned element,
35106 or you will need to add "position:relative" to the css of the container. You will also need to specify
35107 the container size if it is not the body element.</b>
35110 * Create a new Border
35111 * @param {Object} config Configuration options
35113 Roo.bootstrap.layout.Border = function(config){
35114 config = config || {};
35115 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35119 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35120 if(config[region]){
35121 config[region].region = region;
35122 this.addRegion(config[region]);
35128 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35130 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35132 parent : false, // this might point to a 'nest' or a ???
35135 * Creates and adds a new region if it doesn't already exist.
35136 * @param {String} target The target region key (north, south, east, west or center).
35137 * @param {Object} config The regions config object
35138 * @return {BorderLayoutRegion} The new region
35140 addRegion : function(config)
35142 if(!this.regions[config.region]){
35143 var r = this.factory(config);
35144 this.bindRegion(r);
35146 return this.regions[config.region];
35150 bindRegion : function(r){
35151 this.regions[r.config.region] = r;
35153 r.on("visibilitychange", this.layout, this);
35154 r.on("paneladded", this.layout, this);
35155 r.on("panelremoved", this.layout, this);
35156 r.on("invalidated", this.layout, this);
35157 r.on("resized", this.onRegionResized, this);
35158 r.on("collapsed", this.onRegionCollapsed, this);
35159 r.on("expanded", this.onRegionExpanded, this);
35163 * Performs a layout update.
35165 layout : function()
35167 if(this.updating) {
35171 // render all the rebions if they have not been done alreayd?
35172 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35173 if(this.regions[region] && !this.regions[region].bodyEl){
35174 this.regions[region].onRender(this.el)
35178 var size = this.getViewSize();
35179 var w = size.width;
35180 var h = size.height;
35185 //var x = 0, y = 0;
35187 var rs = this.regions;
35188 var north = rs["north"];
35189 var south = rs["south"];
35190 var west = rs["west"];
35191 var east = rs["east"];
35192 var center = rs["center"];
35193 //if(this.hideOnLayout){ // not supported anymore
35194 //c.el.setStyle("display", "none");
35196 if(north && north.isVisible()){
35197 var b = north.getBox();
35198 var m = north.getMargins();
35199 b.width = w - (m.left+m.right);
35202 centerY = b.height + b.y + m.bottom;
35203 centerH -= centerY;
35204 north.updateBox(this.safeBox(b));
35206 if(south && south.isVisible()){
35207 var b = south.getBox();
35208 var m = south.getMargins();
35209 b.width = w - (m.left+m.right);
35211 var totalHeight = (b.height + m.top + m.bottom);
35212 b.y = h - totalHeight + m.top;
35213 centerH -= totalHeight;
35214 south.updateBox(this.safeBox(b));
35216 if(west && west.isVisible()){
35217 var b = west.getBox();
35218 var m = west.getMargins();
35219 b.height = centerH - (m.top+m.bottom);
35221 b.y = centerY + m.top;
35222 var totalWidth = (b.width + m.left + m.right);
35223 centerX += totalWidth;
35224 centerW -= totalWidth;
35225 west.updateBox(this.safeBox(b));
35227 if(east && east.isVisible()){
35228 var b = east.getBox();
35229 var m = east.getMargins();
35230 b.height = centerH - (m.top+m.bottom);
35231 var totalWidth = (b.width + m.left + m.right);
35232 b.x = w - totalWidth + m.left;
35233 b.y = centerY + m.top;
35234 centerW -= totalWidth;
35235 east.updateBox(this.safeBox(b));
35238 var m = center.getMargins();
35240 x: centerX + m.left,
35241 y: centerY + m.top,
35242 width: centerW - (m.left+m.right),
35243 height: centerH - (m.top+m.bottom)
35245 //if(this.hideOnLayout){
35246 //center.el.setStyle("display", "block");
35248 center.updateBox(this.safeBox(centerBox));
35251 this.fireEvent("layout", this);
35255 safeBox : function(box){
35256 box.width = Math.max(0, box.width);
35257 box.height = Math.max(0, box.height);
35262 * Adds a ContentPanel (or subclass) to this layout.
35263 * @param {String} target The target region key (north, south, east, west or center).
35264 * @param {Roo.ContentPanel} panel The panel to add
35265 * @return {Roo.ContentPanel} The added panel
35267 add : function(target, panel){
35269 target = target.toLowerCase();
35270 return this.regions[target].add(panel);
35274 * Remove a ContentPanel (or subclass) to this layout.
35275 * @param {String} target The target region key (north, south, east, west or center).
35276 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35277 * @return {Roo.ContentPanel} The removed panel
35279 remove : function(target, panel){
35280 target = target.toLowerCase();
35281 return this.regions[target].remove(panel);
35285 * Searches all regions for a panel with the specified id
35286 * @param {String} panelId
35287 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35289 findPanel : function(panelId){
35290 var rs = this.regions;
35291 for(var target in rs){
35292 if(typeof rs[target] != "function"){
35293 var p = rs[target].getPanel(panelId);
35303 * Searches all regions for a panel with the specified id and activates (shows) it.
35304 * @param {String/ContentPanel} panelId The panels id or the panel itself
35305 * @return {Roo.ContentPanel} The shown panel or null
35307 showPanel : function(panelId) {
35308 var rs = this.regions;
35309 for(var target in rs){
35310 var r = rs[target];
35311 if(typeof r != "function"){
35312 if(r.hasPanel(panelId)){
35313 return r.showPanel(panelId);
35321 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35322 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35325 restoreState : function(provider){
35327 provider = Roo.state.Manager;
35329 var sm = new Roo.LayoutStateManager();
35330 sm.init(this, provider);
35336 * Adds a xtype elements to the layout.
35340 xtype : 'ContentPanel',
35347 xtype : 'NestedLayoutPanel',
35353 items : [ ... list of content panels or nested layout panels.. ]
35357 * @param {Object} cfg Xtype definition of item to add.
35359 addxtype : function(cfg)
35361 // basically accepts a pannel...
35362 // can accept a layout region..!?!?
35363 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35366 // theory? children can only be panels??
35368 //if (!cfg.xtype.match(/Panel$/)) {
35373 if (typeof(cfg.region) == 'undefined') {
35374 Roo.log("Failed to add Panel, region was not set");
35378 var region = cfg.region;
35384 xitems = cfg.items;
35389 if ( region == 'center') {
35390 Roo.log("Center: " + cfg.title);
35396 case 'Content': // ContentPanel (el, cfg)
35397 case 'Scroll': // ContentPanel (el, cfg)
35399 cfg.autoCreate = cfg.autoCreate || true;
35400 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35402 // var el = this.el.createChild();
35403 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35406 this.add(region, ret);
35410 case 'TreePanel': // our new panel!
35411 cfg.el = this.el.createChild();
35412 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35413 this.add(region, ret);
35418 // create a new Layout (which is a Border Layout...
35420 var clayout = cfg.layout;
35421 clayout.el = this.el.createChild();
35422 clayout.items = clayout.items || [];
35426 // replace this exitems with the clayout ones..
35427 xitems = clayout.items;
35429 // force background off if it's in center...
35430 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35431 cfg.background = false;
35433 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35436 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35437 //console.log('adding nested layout panel ' + cfg.toSource());
35438 this.add(region, ret);
35439 nb = {}; /// find first...
35444 // needs grid and region
35446 //var el = this.getRegion(region).el.createChild();
35448 *var el = this.el.createChild();
35449 // create the grid first...
35450 cfg.grid.container = el;
35451 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35454 if (region == 'center' && this.active ) {
35455 cfg.background = false;
35458 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35460 this.add(region, ret);
35462 if (cfg.background) {
35463 // render grid on panel activation (if panel background)
35464 ret.on('activate', function(gp) {
35465 if (!gp.grid.rendered) {
35466 // gp.grid.render(el);
35470 // cfg.grid.render(el);
35476 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35477 // it was the old xcomponent building that caused this before.
35478 // espeically if border is the top element in the tree.
35488 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35490 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35491 this.add(region, ret);
35495 throw "Can not add '" + cfg.xtype + "' to Border";
35501 this.beginUpdate();
35505 Roo.each(xitems, function(i) {
35506 region = nb && i.region ? i.region : false;
35508 var add = ret.addxtype(i);
35511 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35512 if (!i.background) {
35513 abn[region] = nb[region] ;
35520 // make the last non-background panel active..
35521 //if (nb) { Roo.log(abn); }
35524 for(var r in abn) {
35525 region = this.getRegion(r);
35527 // tried using nb[r], but it does not work..
35529 region.showPanel(abn[r]);
35540 factory : function(cfg)
35543 var validRegions = Roo.bootstrap.layout.Border.regions;
35545 var target = cfg.region;
35548 var r = Roo.bootstrap.layout;
35552 return new r.North(cfg);
35554 return new r.South(cfg);
35556 return new r.East(cfg);
35558 return new r.West(cfg);
35560 return new r.Center(cfg);
35562 throw 'Layout region "'+target+'" not supported.';
35569 * Ext JS Library 1.1.1
35570 * Copyright(c) 2006-2007, Ext JS, LLC.
35572 * Originally Released Under LGPL - original licence link has changed is not relivant.
35575 * <script type="text/javascript">
35579 * @class Roo.bootstrap.layout.Basic
35580 * @extends Roo.util.Observable
35581 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35582 * and does not have a titlebar, tabs or any other features. All it does is size and position
35583 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35584 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35585 * @cfg {string} region the region that it inhabits..
35586 * @cfg {bool} skipConfig skip config?
35590 Roo.bootstrap.layout.Basic = function(config){
35592 this.mgr = config.mgr;
35594 this.position = config.region;
35596 var skipConfig = config.skipConfig;
35600 * @scope Roo.BasicLayoutRegion
35604 * @event beforeremove
35605 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35606 * @param {Roo.LayoutRegion} this
35607 * @param {Roo.ContentPanel} panel The panel
35608 * @param {Object} e The cancel event object
35610 "beforeremove" : true,
35612 * @event invalidated
35613 * Fires when the layout for this region is changed.
35614 * @param {Roo.LayoutRegion} this
35616 "invalidated" : true,
35618 * @event visibilitychange
35619 * Fires when this region is shown or hidden
35620 * @param {Roo.LayoutRegion} this
35621 * @param {Boolean} visibility true or false
35623 "visibilitychange" : true,
35625 * @event paneladded
35626 * Fires when a panel is added.
35627 * @param {Roo.LayoutRegion} this
35628 * @param {Roo.ContentPanel} panel The panel
35630 "paneladded" : true,
35632 * @event panelremoved
35633 * Fires when a panel is removed.
35634 * @param {Roo.LayoutRegion} this
35635 * @param {Roo.ContentPanel} panel The panel
35637 "panelremoved" : true,
35639 * @event beforecollapse
35640 * Fires when this region before collapse.
35641 * @param {Roo.LayoutRegion} this
35643 "beforecollapse" : true,
35646 * Fires when this region is collapsed.
35647 * @param {Roo.LayoutRegion} this
35649 "collapsed" : true,
35652 * Fires when this region is expanded.
35653 * @param {Roo.LayoutRegion} this
35658 * Fires when this region is slid into view.
35659 * @param {Roo.LayoutRegion} this
35661 "slideshow" : true,
35664 * Fires when this region slides out of view.
35665 * @param {Roo.LayoutRegion} this
35667 "slidehide" : true,
35669 * @event panelactivated
35670 * Fires when a panel is activated.
35671 * @param {Roo.LayoutRegion} this
35672 * @param {Roo.ContentPanel} panel The activated panel
35674 "panelactivated" : true,
35677 * Fires when the user resizes this region.
35678 * @param {Roo.LayoutRegion} this
35679 * @param {Number} newSize The new size (width for east/west, height for north/south)
35683 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35684 this.panels = new Roo.util.MixedCollection();
35685 this.panels.getKey = this.getPanelId.createDelegate(this);
35687 this.activePanel = null;
35688 // ensure listeners are added...
35690 if (config.listeners || config.events) {
35691 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35692 listeners : config.listeners || {},
35693 events : config.events || {}
35697 if(skipConfig !== true){
35698 this.applyConfig(config);
35702 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35704 getPanelId : function(p){
35708 applyConfig : function(config){
35709 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35710 this.config = config;
35715 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35716 * the width, for horizontal (north, south) the height.
35717 * @param {Number} newSize The new width or height
35719 resizeTo : function(newSize){
35720 var el = this.el ? this.el :
35721 (this.activePanel ? this.activePanel.getEl() : null);
35723 switch(this.position){
35726 el.setWidth(newSize);
35727 this.fireEvent("resized", this, newSize);
35731 el.setHeight(newSize);
35732 this.fireEvent("resized", this, newSize);
35738 getBox : function(){
35739 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35742 getMargins : function(){
35743 return this.margins;
35746 updateBox : function(box){
35748 var el = this.activePanel.getEl();
35749 el.dom.style.left = box.x + "px";
35750 el.dom.style.top = box.y + "px";
35751 this.activePanel.setSize(box.width, box.height);
35755 * Returns the container element for this region.
35756 * @return {Roo.Element}
35758 getEl : function(){
35759 return this.activePanel;
35763 * Returns true if this region is currently visible.
35764 * @return {Boolean}
35766 isVisible : function(){
35767 return this.activePanel ? true : false;
35770 setActivePanel : function(panel){
35771 panel = this.getPanel(panel);
35772 if(this.activePanel && this.activePanel != panel){
35773 this.activePanel.setActiveState(false);
35774 this.activePanel.getEl().setLeftTop(-10000,-10000);
35776 this.activePanel = panel;
35777 panel.setActiveState(true);
35779 panel.setSize(this.box.width, this.box.height);
35781 this.fireEvent("panelactivated", this, panel);
35782 this.fireEvent("invalidated");
35786 * Show the specified panel.
35787 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35788 * @return {Roo.ContentPanel} The shown panel or null
35790 showPanel : function(panel){
35791 panel = this.getPanel(panel);
35793 this.setActivePanel(panel);
35799 * Get the active panel for this region.
35800 * @return {Roo.ContentPanel} The active panel or null
35802 getActivePanel : function(){
35803 return this.activePanel;
35807 * Add the passed ContentPanel(s)
35808 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35809 * @return {Roo.ContentPanel} The panel added (if only one was added)
35811 add : function(panel){
35812 if(arguments.length > 1){
35813 for(var i = 0, len = arguments.length; i < len; i++) {
35814 this.add(arguments[i]);
35818 if(this.hasPanel(panel)){
35819 this.showPanel(panel);
35822 var el = panel.getEl();
35823 if(el.dom.parentNode != this.mgr.el.dom){
35824 this.mgr.el.dom.appendChild(el.dom);
35826 if(panel.setRegion){
35827 panel.setRegion(this);
35829 this.panels.add(panel);
35830 el.setStyle("position", "absolute");
35831 if(!panel.background){
35832 this.setActivePanel(panel);
35833 if(this.config.initialSize && this.panels.getCount()==1){
35834 this.resizeTo(this.config.initialSize);
35837 this.fireEvent("paneladded", this, panel);
35842 * Returns true if the panel is in this region.
35843 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35844 * @return {Boolean}
35846 hasPanel : function(panel){
35847 if(typeof panel == "object"){ // must be panel obj
35848 panel = panel.getId();
35850 return this.getPanel(panel) ? true : false;
35854 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35855 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35856 * @param {Boolean} preservePanel Overrides the config preservePanel option
35857 * @return {Roo.ContentPanel} The panel that was removed
35859 remove : function(panel, preservePanel){
35860 panel = this.getPanel(panel);
35865 this.fireEvent("beforeremove", this, panel, e);
35866 if(e.cancel === true){
35869 var panelId = panel.getId();
35870 this.panels.removeKey(panelId);
35875 * Returns the panel specified or null if it's not in this region.
35876 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35877 * @return {Roo.ContentPanel}
35879 getPanel : function(id){
35880 if(typeof id == "object"){ // must be panel obj
35883 return this.panels.get(id);
35887 * Returns this regions position (north/south/east/west/center).
35890 getPosition: function(){
35891 return this.position;
35895 * Ext JS Library 1.1.1
35896 * Copyright(c) 2006-2007, Ext JS, LLC.
35898 * Originally Released Under LGPL - original licence link has changed is not relivant.
35901 * <script type="text/javascript">
35905 * @class Roo.bootstrap.layout.Region
35906 * @extends Roo.bootstrap.layout.Basic
35907 * This class represents a region in a layout manager.
35909 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35910 * @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})
35911 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35912 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35913 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35914 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35915 * @cfg {String} title The title for the region (overrides panel titles)
35916 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35917 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35918 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35919 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35920 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35921 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35922 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35923 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35924 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35925 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35927 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35928 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35929 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35930 * @cfg {Number} width For East/West panels
35931 * @cfg {Number} height For North/South panels
35932 * @cfg {Boolean} split To show the splitter
35933 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35935 * @cfg {string} cls Extra CSS classes to add to region
35937 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35938 * @cfg {string} region the region that it inhabits..
35941 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35942 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35944 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35945 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35946 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35948 Roo.bootstrap.layout.Region = function(config)
35950 this.applyConfig(config);
35952 var mgr = config.mgr;
35953 var pos = config.region;
35954 config.skipConfig = true;
35955 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35958 this.onRender(mgr.el);
35961 this.visible = true;
35962 this.collapsed = false;
35963 this.unrendered_panels = [];
35966 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35968 position: '', // set by wrapper (eg. north/south etc..)
35969 unrendered_panels : null, // unrendered panels.
35971 tabPosition : false,
35973 mgr: false, // points to 'Border'
35976 createBody : function(){
35977 /** This region's body element
35978 * @type Roo.Element */
35979 this.bodyEl = this.el.createChild({
35981 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35985 onRender: function(ctr, pos)
35987 var dh = Roo.DomHelper;
35988 /** This region's container element
35989 * @type Roo.Element */
35990 this.el = dh.append(ctr.dom, {
35992 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35994 /** This region's title element
35995 * @type Roo.Element */
35997 this.titleEl = dh.append(this.el.dom, {
35999 unselectable: "on",
36000 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36002 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36003 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36007 this.titleEl.enableDisplayMode();
36008 /** This region's title text element
36009 * @type HTMLElement */
36010 this.titleTextEl = this.titleEl.dom.firstChild;
36011 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36013 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36014 this.closeBtn.enableDisplayMode();
36015 this.closeBtn.on("click", this.closeClicked, this);
36016 this.closeBtn.hide();
36018 this.createBody(this.config);
36019 if(this.config.hideWhenEmpty){
36021 this.on("paneladded", this.validateVisibility, this);
36022 this.on("panelremoved", this.validateVisibility, this);
36024 if(this.autoScroll){
36025 this.bodyEl.setStyle("overflow", "auto");
36027 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36029 //if(c.titlebar !== false){
36030 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36031 this.titleEl.hide();
36033 this.titleEl.show();
36034 if(this.config.title){
36035 this.titleTextEl.innerHTML = this.config.title;
36039 if(this.config.collapsed){
36040 this.collapse(true);
36042 if(this.config.hidden){
36046 if (this.unrendered_panels && this.unrendered_panels.length) {
36047 for (var i =0;i< this.unrendered_panels.length; i++) {
36048 this.add(this.unrendered_panels[i]);
36050 this.unrendered_panels = null;
36056 applyConfig : function(c)
36059 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36060 var dh = Roo.DomHelper;
36061 if(c.titlebar !== false){
36062 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36063 this.collapseBtn.on("click", this.collapse, this);
36064 this.collapseBtn.enableDisplayMode();
36066 if(c.showPin === true || this.showPin){
36067 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36068 this.stickBtn.enableDisplayMode();
36069 this.stickBtn.on("click", this.expand, this);
36070 this.stickBtn.hide();
36075 /** This region's collapsed element
36076 * @type Roo.Element */
36079 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36080 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36083 if(c.floatable !== false){
36084 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36085 this.collapsedEl.on("click", this.collapseClick, this);
36088 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36089 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36090 id: "message", unselectable: "on", style:{"float":"left"}});
36091 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36093 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36094 this.expandBtn.on("click", this.expand, this);
36098 if(this.collapseBtn){
36099 this.collapseBtn.setVisible(c.collapsible == true);
36102 this.cmargins = c.cmargins || this.cmargins ||
36103 (this.position == "west" || this.position == "east" ?
36104 {top: 0, left: 2, right:2, bottom: 0} :
36105 {top: 2, left: 0, right:0, bottom: 2});
36107 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36110 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36112 this.autoScroll = c.autoScroll || false;
36117 this.duration = c.duration || .30;
36118 this.slideDuration = c.slideDuration || .45;
36123 * Returns true if this region is currently visible.
36124 * @return {Boolean}
36126 isVisible : function(){
36127 return this.visible;
36131 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36132 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36134 //setCollapsedTitle : function(title){
36135 // title = title || " ";
36136 // if(this.collapsedTitleTextEl){
36137 // this.collapsedTitleTextEl.innerHTML = title;
36141 getBox : function(){
36143 // if(!this.collapsed){
36144 b = this.el.getBox(false, true);
36146 // b = this.collapsedEl.getBox(false, true);
36151 getMargins : function(){
36152 return this.margins;
36153 //return this.collapsed ? this.cmargins : this.margins;
36156 highlight : function(){
36157 this.el.addClass("x-layout-panel-dragover");
36160 unhighlight : function(){
36161 this.el.removeClass("x-layout-panel-dragover");
36164 updateBox : function(box)
36166 if (!this.bodyEl) {
36167 return; // not rendered yet..
36171 if(!this.collapsed){
36172 this.el.dom.style.left = box.x + "px";
36173 this.el.dom.style.top = box.y + "px";
36174 this.updateBody(box.width, box.height);
36176 this.collapsedEl.dom.style.left = box.x + "px";
36177 this.collapsedEl.dom.style.top = box.y + "px";
36178 this.collapsedEl.setSize(box.width, box.height);
36181 this.tabs.autoSizeTabs();
36185 updateBody : function(w, h)
36188 this.el.setWidth(w);
36189 w -= this.el.getBorderWidth("rl");
36190 if(this.config.adjustments){
36191 w += this.config.adjustments[0];
36194 if(h !== null && h > 0){
36195 this.el.setHeight(h);
36196 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36197 h -= this.el.getBorderWidth("tb");
36198 if(this.config.adjustments){
36199 h += this.config.adjustments[1];
36201 this.bodyEl.setHeight(h);
36203 h = this.tabs.syncHeight(h);
36206 if(this.panelSize){
36207 w = w !== null ? w : this.panelSize.width;
36208 h = h !== null ? h : this.panelSize.height;
36210 if(this.activePanel){
36211 var el = this.activePanel.getEl();
36212 w = w !== null ? w : el.getWidth();
36213 h = h !== null ? h : el.getHeight();
36214 this.panelSize = {width: w, height: h};
36215 this.activePanel.setSize(w, h);
36217 if(Roo.isIE && this.tabs){
36218 this.tabs.el.repaint();
36223 * Returns the container element for this region.
36224 * @return {Roo.Element}
36226 getEl : function(){
36231 * Hides this region.
36234 //if(!this.collapsed){
36235 this.el.dom.style.left = "-2000px";
36238 // this.collapsedEl.dom.style.left = "-2000px";
36239 // this.collapsedEl.hide();
36241 this.visible = false;
36242 this.fireEvent("visibilitychange", this, false);
36246 * Shows this region if it was previously hidden.
36249 //if(!this.collapsed){
36252 // this.collapsedEl.show();
36254 this.visible = true;
36255 this.fireEvent("visibilitychange", this, true);
36258 closeClicked : function(){
36259 if(this.activePanel){
36260 this.remove(this.activePanel);
36264 collapseClick : function(e){
36266 e.stopPropagation();
36269 e.stopPropagation();
36275 * Collapses this region.
36276 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36279 collapse : function(skipAnim, skipCheck = false){
36280 if(this.collapsed) {
36284 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36286 this.collapsed = true;
36288 this.split.el.hide();
36290 if(this.config.animate && skipAnim !== true){
36291 this.fireEvent("invalidated", this);
36292 this.animateCollapse();
36294 this.el.setLocation(-20000,-20000);
36296 this.collapsedEl.show();
36297 this.fireEvent("collapsed", this);
36298 this.fireEvent("invalidated", this);
36304 animateCollapse : function(){
36309 * Expands this region if it was previously collapsed.
36310 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36311 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36314 expand : function(e, skipAnim){
36316 e.stopPropagation();
36318 if(!this.collapsed || this.el.hasActiveFx()) {
36322 this.afterSlideIn();
36325 this.collapsed = false;
36326 if(this.config.animate && skipAnim !== true){
36327 this.animateExpand();
36331 this.split.el.show();
36333 this.collapsedEl.setLocation(-2000,-2000);
36334 this.collapsedEl.hide();
36335 this.fireEvent("invalidated", this);
36336 this.fireEvent("expanded", this);
36340 animateExpand : function(){
36344 initTabs : function()
36346 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36348 var ts = new Roo.bootstrap.panel.Tabs({
36349 el: this.bodyEl.dom,
36351 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36352 disableTooltips: this.config.disableTabTips,
36353 toolbar : this.config.toolbar
36356 if(this.config.hideTabs){
36357 ts.stripWrap.setDisplayed(false);
36360 ts.resizeTabs = this.config.resizeTabs === true;
36361 ts.minTabWidth = this.config.minTabWidth || 40;
36362 ts.maxTabWidth = this.config.maxTabWidth || 250;
36363 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36364 ts.monitorResize = false;
36365 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36366 ts.bodyEl.addClass('roo-layout-tabs-body');
36367 this.panels.each(this.initPanelAsTab, this);
36370 initPanelAsTab : function(panel){
36371 var ti = this.tabs.addTab(
36375 this.config.closeOnTab && panel.isClosable(),
36378 if(panel.tabTip !== undefined){
36379 ti.setTooltip(panel.tabTip);
36381 ti.on("activate", function(){
36382 this.setActivePanel(panel);
36385 if(this.config.closeOnTab){
36386 ti.on("beforeclose", function(t, e){
36388 this.remove(panel);
36392 panel.tabItem = ti;
36397 updatePanelTitle : function(panel, title)
36399 if(this.activePanel == panel){
36400 this.updateTitle(title);
36403 var ti = this.tabs.getTab(panel.getEl().id);
36405 if(panel.tabTip !== undefined){
36406 ti.setTooltip(panel.tabTip);
36411 updateTitle : function(title){
36412 if(this.titleTextEl && !this.config.title){
36413 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36417 setActivePanel : function(panel)
36419 panel = this.getPanel(panel);
36420 if(this.activePanel && this.activePanel != panel){
36421 if(this.activePanel.setActiveState(false) === false){
36425 this.activePanel = panel;
36426 panel.setActiveState(true);
36427 if(this.panelSize){
36428 panel.setSize(this.panelSize.width, this.panelSize.height);
36431 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36433 this.updateTitle(panel.getTitle());
36435 this.fireEvent("invalidated", this);
36437 this.fireEvent("panelactivated", this, panel);
36441 * Shows the specified panel.
36442 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36443 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36445 showPanel : function(panel)
36447 panel = this.getPanel(panel);
36450 var tab = this.tabs.getTab(panel.getEl().id);
36451 if(tab.isHidden()){
36452 this.tabs.unhideTab(tab.id);
36456 this.setActivePanel(panel);
36463 * Get the active panel for this region.
36464 * @return {Roo.ContentPanel} The active panel or null
36466 getActivePanel : function(){
36467 return this.activePanel;
36470 validateVisibility : function(){
36471 if(this.panels.getCount() < 1){
36472 this.updateTitle(" ");
36473 this.closeBtn.hide();
36476 if(!this.isVisible()){
36483 * Adds the passed ContentPanel(s) to this region.
36484 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36485 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36487 add : function(panel)
36489 if(arguments.length > 1){
36490 for(var i = 0, len = arguments.length; i < len; i++) {
36491 this.add(arguments[i]);
36496 // if we have not been rendered yet, then we can not really do much of this..
36497 if (!this.bodyEl) {
36498 this.unrendered_panels.push(panel);
36505 if(this.hasPanel(panel)){
36506 this.showPanel(panel);
36509 panel.setRegion(this);
36510 this.panels.add(panel);
36511 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36512 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36513 // and hide them... ???
36514 this.bodyEl.dom.appendChild(panel.getEl().dom);
36515 if(panel.background !== true){
36516 this.setActivePanel(panel);
36518 this.fireEvent("paneladded", this, panel);
36525 this.initPanelAsTab(panel);
36529 if(panel.background !== true){
36530 this.tabs.activate(panel.getEl().id);
36532 this.fireEvent("paneladded", this, panel);
36537 * Hides the tab for the specified panel.
36538 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36540 hidePanel : function(panel){
36541 if(this.tabs && (panel = this.getPanel(panel))){
36542 this.tabs.hideTab(panel.getEl().id);
36547 * Unhides the tab for a previously hidden panel.
36548 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36550 unhidePanel : function(panel){
36551 if(this.tabs && (panel = this.getPanel(panel))){
36552 this.tabs.unhideTab(panel.getEl().id);
36556 clearPanels : function(){
36557 while(this.panels.getCount() > 0){
36558 this.remove(this.panels.first());
36563 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36564 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36565 * @param {Boolean} preservePanel Overrides the config preservePanel option
36566 * @return {Roo.ContentPanel} The panel that was removed
36568 remove : function(panel, preservePanel)
36570 panel = this.getPanel(panel);
36575 this.fireEvent("beforeremove", this, panel, e);
36576 if(e.cancel === true){
36579 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36580 var panelId = panel.getId();
36581 this.panels.removeKey(panelId);
36583 document.body.appendChild(panel.getEl().dom);
36586 this.tabs.removeTab(panel.getEl().id);
36587 }else if (!preservePanel){
36588 this.bodyEl.dom.removeChild(panel.getEl().dom);
36590 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36591 var p = this.panels.first();
36592 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36593 tempEl.appendChild(p.getEl().dom);
36594 this.bodyEl.update("");
36595 this.bodyEl.dom.appendChild(p.getEl().dom);
36597 this.updateTitle(p.getTitle());
36599 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36600 this.setActivePanel(p);
36602 panel.setRegion(null);
36603 if(this.activePanel == panel){
36604 this.activePanel = null;
36606 if(this.config.autoDestroy !== false && preservePanel !== true){
36607 try{panel.destroy();}catch(e){}
36609 this.fireEvent("panelremoved", this, panel);
36614 * Returns the TabPanel component used by this region
36615 * @return {Roo.TabPanel}
36617 getTabs : function(){
36621 createTool : function(parentEl, className){
36622 var btn = Roo.DomHelper.append(parentEl, {
36624 cls: "x-layout-tools-button",
36627 cls: "roo-layout-tools-button-inner " + className,
36631 btn.addClassOnOver("roo-layout-tools-button-over");
36636 * Ext JS Library 1.1.1
36637 * Copyright(c) 2006-2007, Ext JS, LLC.
36639 * Originally Released Under LGPL - original licence link has changed is not relivant.
36642 * <script type="text/javascript">
36648 * @class Roo.SplitLayoutRegion
36649 * @extends Roo.LayoutRegion
36650 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36652 Roo.bootstrap.layout.Split = function(config){
36653 this.cursor = config.cursor;
36654 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36657 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36659 splitTip : "Drag to resize.",
36660 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36661 useSplitTips : false,
36663 applyConfig : function(config){
36664 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36667 onRender : function(ctr,pos) {
36669 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36670 if(!this.config.split){
36675 var splitEl = Roo.DomHelper.append(ctr.dom, {
36677 id: this.el.id + "-split",
36678 cls: "roo-layout-split roo-layout-split-"+this.position,
36681 /** The SplitBar for this region
36682 * @type Roo.SplitBar */
36683 // does not exist yet...
36684 Roo.log([this.position, this.orientation]);
36686 this.split = new Roo.bootstrap.SplitBar({
36687 dragElement : splitEl,
36688 resizingElement: this.el,
36689 orientation : this.orientation
36692 this.split.on("moved", this.onSplitMove, this);
36693 this.split.useShim = this.config.useShim === true;
36694 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36695 if(this.useSplitTips){
36696 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36698 //if(config.collapsible){
36699 // this.split.el.on("dblclick", this.collapse, this);
36702 if(typeof this.config.minSize != "undefined"){
36703 this.split.minSize = this.config.minSize;
36705 if(typeof this.config.maxSize != "undefined"){
36706 this.split.maxSize = this.config.maxSize;
36708 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36709 this.hideSplitter();
36714 getHMaxSize : function(){
36715 var cmax = this.config.maxSize || 10000;
36716 var center = this.mgr.getRegion("center");
36717 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36720 getVMaxSize : function(){
36721 var cmax = this.config.maxSize || 10000;
36722 var center = this.mgr.getRegion("center");
36723 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36726 onSplitMove : function(split, newSize){
36727 this.fireEvent("resized", this, newSize);
36731 * Returns the {@link Roo.SplitBar} for this region.
36732 * @return {Roo.SplitBar}
36734 getSplitBar : function(){
36739 this.hideSplitter();
36740 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36743 hideSplitter : function(){
36745 this.split.el.setLocation(-2000,-2000);
36746 this.split.el.hide();
36752 this.split.el.show();
36754 Roo.bootstrap.layout.Split.superclass.show.call(this);
36757 beforeSlide: function(){
36758 if(Roo.isGecko){// firefox overflow auto bug workaround
36759 this.bodyEl.clip();
36761 this.tabs.bodyEl.clip();
36763 if(this.activePanel){
36764 this.activePanel.getEl().clip();
36766 if(this.activePanel.beforeSlide){
36767 this.activePanel.beforeSlide();
36773 afterSlide : function(){
36774 if(Roo.isGecko){// firefox overflow auto bug workaround
36775 this.bodyEl.unclip();
36777 this.tabs.bodyEl.unclip();
36779 if(this.activePanel){
36780 this.activePanel.getEl().unclip();
36781 if(this.activePanel.afterSlide){
36782 this.activePanel.afterSlide();
36788 initAutoHide : function(){
36789 if(this.autoHide !== false){
36790 if(!this.autoHideHd){
36791 var st = new Roo.util.DelayedTask(this.slideIn, this);
36792 this.autoHideHd = {
36793 "mouseout": function(e){
36794 if(!e.within(this.el, true)){
36798 "mouseover" : function(e){
36804 this.el.on(this.autoHideHd);
36808 clearAutoHide : function(){
36809 if(this.autoHide !== false){
36810 this.el.un("mouseout", this.autoHideHd.mouseout);
36811 this.el.un("mouseover", this.autoHideHd.mouseover);
36815 clearMonitor : function(){
36816 Roo.get(document).un("click", this.slideInIf, this);
36819 // these names are backwards but not changed for compat
36820 slideOut : function(){
36821 if(this.isSlid || this.el.hasActiveFx()){
36824 this.isSlid = true;
36825 if(this.collapseBtn){
36826 this.collapseBtn.hide();
36828 this.closeBtnState = this.closeBtn.getStyle('display');
36829 this.closeBtn.hide();
36831 this.stickBtn.show();
36834 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36835 this.beforeSlide();
36836 this.el.setStyle("z-index", 10001);
36837 this.el.slideIn(this.getSlideAnchor(), {
36838 callback: function(){
36840 this.initAutoHide();
36841 Roo.get(document).on("click", this.slideInIf, this);
36842 this.fireEvent("slideshow", this);
36849 afterSlideIn : function(){
36850 this.clearAutoHide();
36851 this.isSlid = false;
36852 this.clearMonitor();
36853 this.el.setStyle("z-index", "");
36854 if(this.collapseBtn){
36855 this.collapseBtn.show();
36857 this.closeBtn.setStyle('display', this.closeBtnState);
36859 this.stickBtn.hide();
36861 this.fireEvent("slidehide", this);
36864 slideIn : function(cb){
36865 if(!this.isSlid || this.el.hasActiveFx()){
36869 this.isSlid = false;
36870 this.beforeSlide();
36871 this.el.slideOut(this.getSlideAnchor(), {
36872 callback: function(){
36873 this.el.setLeftTop(-10000, -10000);
36875 this.afterSlideIn();
36883 slideInIf : function(e){
36884 if(!e.within(this.el)){
36889 animateCollapse : function(){
36890 this.beforeSlide();
36891 this.el.setStyle("z-index", 20000);
36892 var anchor = this.getSlideAnchor();
36893 this.el.slideOut(anchor, {
36894 callback : function(){
36895 this.el.setStyle("z-index", "");
36896 this.collapsedEl.slideIn(anchor, {duration:.3});
36898 this.el.setLocation(-10000,-10000);
36900 this.fireEvent("collapsed", this);
36907 animateExpand : function(){
36908 this.beforeSlide();
36909 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36910 this.el.setStyle("z-index", 20000);
36911 this.collapsedEl.hide({
36914 this.el.slideIn(this.getSlideAnchor(), {
36915 callback : function(){
36916 this.el.setStyle("z-index", "");
36919 this.split.el.show();
36921 this.fireEvent("invalidated", this);
36922 this.fireEvent("expanded", this);
36950 getAnchor : function(){
36951 return this.anchors[this.position];
36954 getCollapseAnchor : function(){
36955 return this.canchors[this.position];
36958 getSlideAnchor : function(){
36959 return this.sanchors[this.position];
36962 getAlignAdj : function(){
36963 var cm = this.cmargins;
36964 switch(this.position){
36980 getExpandAdj : function(){
36981 var c = this.collapsedEl, cm = this.cmargins;
36982 switch(this.position){
36984 return [-(cm.right+c.getWidth()+cm.left), 0];
36987 return [cm.right+c.getWidth()+cm.left, 0];
36990 return [0, -(cm.top+cm.bottom+c.getHeight())];
36993 return [0, cm.top+cm.bottom+c.getHeight()];
36999 * Ext JS Library 1.1.1
37000 * Copyright(c) 2006-2007, Ext JS, LLC.
37002 * Originally Released Under LGPL - original licence link has changed is not relivant.
37005 * <script type="text/javascript">
37008 * These classes are private internal classes
37010 Roo.bootstrap.layout.Center = function(config){
37011 config.region = "center";
37012 Roo.bootstrap.layout.Region.call(this, config);
37013 this.visible = true;
37014 this.minWidth = config.minWidth || 20;
37015 this.minHeight = config.minHeight || 20;
37018 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37020 // center panel can't be hidden
37024 // center panel can't be hidden
37027 getMinWidth: function(){
37028 return this.minWidth;
37031 getMinHeight: function(){
37032 return this.minHeight;
37046 Roo.bootstrap.layout.North = function(config)
37048 config.region = 'north';
37049 config.cursor = 'n-resize';
37051 Roo.bootstrap.layout.Split.call(this, config);
37055 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37056 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37057 this.split.el.addClass("roo-layout-split-v");
37059 var size = config.initialSize || config.height;
37060 if(typeof size != "undefined"){
37061 this.el.setHeight(size);
37064 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37066 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37070 getBox : function(){
37071 if(this.collapsed){
37072 return this.collapsedEl.getBox();
37074 var box = this.el.getBox();
37076 box.height += this.split.el.getHeight();
37081 updateBox : function(box){
37082 if(this.split && !this.collapsed){
37083 box.height -= this.split.el.getHeight();
37084 this.split.el.setLeft(box.x);
37085 this.split.el.setTop(box.y+box.height);
37086 this.split.el.setWidth(box.width);
37088 if(this.collapsed){
37089 this.updateBody(box.width, null);
37091 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37099 Roo.bootstrap.layout.South = function(config){
37100 config.region = 'south';
37101 config.cursor = 's-resize';
37102 Roo.bootstrap.layout.Split.call(this, config);
37104 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37105 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37106 this.split.el.addClass("roo-layout-split-v");
37108 var size = config.initialSize || config.height;
37109 if(typeof size != "undefined"){
37110 this.el.setHeight(size);
37114 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37115 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37116 getBox : function(){
37117 if(this.collapsed){
37118 return this.collapsedEl.getBox();
37120 var box = this.el.getBox();
37122 var sh = this.split.el.getHeight();
37129 updateBox : function(box){
37130 if(this.split && !this.collapsed){
37131 var sh = this.split.el.getHeight();
37134 this.split.el.setLeft(box.x);
37135 this.split.el.setTop(box.y-sh);
37136 this.split.el.setWidth(box.width);
37138 if(this.collapsed){
37139 this.updateBody(box.width, null);
37141 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37145 Roo.bootstrap.layout.East = function(config){
37146 config.region = "east";
37147 config.cursor = "e-resize";
37148 Roo.bootstrap.layout.Split.call(this, config);
37150 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37151 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37152 this.split.el.addClass("roo-layout-split-h");
37154 var size = config.initialSize || config.width;
37155 if(typeof size != "undefined"){
37156 this.el.setWidth(size);
37159 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37160 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37161 getBox : function(){
37162 if(this.collapsed){
37163 return this.collapsedEl.getBox();
37165 var box = this.el.getBox();
37167 var sw = this.split.el.getWidth();
37174 updateBox : function(box){
37175 if(this.split && !this.collapsed){
37176 var sw = this.split.el.getWidth();
37178 this.split.el.setLeft(box.x);
37179 this.split.el.setTop(box.y);
37180 this.split.el.setHeight(box.height);
37183 if(this.collapsed){
37184 this.updateBody(null, box.height);
37186 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37190 Roo.bootstrap.layout.West = function(config){
37191 config.region = "west";
37192 config.cursor = "w-resize";
37194 Roo.bootstrap.layout.Split.call(this, config);
37196 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37197 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37198 this.split.el.addClass("roo-layout-split-h");
37202 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37203 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37205 onRender: function(ctr, pos)
37207 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37208 var size = this.config.initialSize || this.config.width;
37209 if(typeof size != "undefined"){
37210 this.el.setWidth(size);
37214 getBox : function(){
37215 if(this.collapsed){
37216 return this.collapsedEl.getBox();
37218 var box = this.el.getBox();
37220 box.width += this.split.el.getWidth();
37225 updateBox : function(box){
37226 if(this.split && !this.collapsed){
37227 var sw = this.split.el.getWidth();
37229 this.split.el.setLeft(box.x+box.width);
37230 this.split.el.setTop(box.y);
37231 this.split.el.setHeight(box.height);
37233 if(this.collapsed){
37234 this.updateBody(null, box.height);
37236 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37238 });Roo.namespace("Roo.bootstrap.panel");/*
37240 * Ext JS Library 1.1.1
37241 * Copyright(c) 2006-2007, Ext JS, LLC.
37243 * Originally Released Under LGPL - original licence link has changed is not relivant.
37246 * <script type="text/javascript">
37249 * @class Roo.ContentPanel
37250 * @extends Roo.util.Observable
37251 * A basic ContentPanel element.
37252 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37253 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37254 * @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
37255 * @cfg {Boolean} closable True if the panel can be closed/removed
37256 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37257 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37258 * @cfg {Toolbar} toolbar A toolbar for this panel
37259 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37260 * @cfg {String} title The title for this panel
37261 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37262 * @cfg {String} url Calls {@link #setUrl} with this value
37263 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37264 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37265 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37266 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37267 * @cfg {Boolean} badges render the badges
37270 * Create a new ContentPanel.
37271 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37272 * @param {String/Object} config A string to set only the title or a config object
37273 * @param {String} content (optional) Set the HTML content for this panel
37274 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37276 Roo.bootstrap.panel.Content = function( config){
37278 this.tpl = config.tpl || false;
37280 var el = config.el;
37281 var content = config.content;
37283 if(config.autoCreate){ // xtype is available if this is called from factory
37286 this.el = Roo.get(el);
37287 if(!this.el && config && config.autoCreate){
37288 if(typeof config.autoCreate == "object"){
37289 if(!config.autoCreate.id){
37290 config.autoCreate.id = config.id||el;
37292 this.el = Roo.DomHelper.append(document.body,
37293 config.autoCreate, true);
37295 var elcfg = { tag: "div",
37296 cls: "roo-layout-inactive-content",
37300 elcfg.html = config.html;
37304 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37307 this.closable = false;
37308 this.loaded = false;
37309 this.active = false;
37312 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37314 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37316 this.wrapEl = this.el; //this.el.wrap();
37318 if (config.toolbar.items) {
37319 ti = config.toolbar.items ;
37320 delete config.toolbar.items ;
37324 this.toolbar.render(this.wrapEl, 'before');
37325 for(var i =0;i < ti.length;i++) {
37326 // Roo.log(['add child', items[i]]);
37327 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37329 this.toolbar.items = nitems;
37330 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37331 delete config.toolbar;
37335 // xtype created footer. - not sure if will work as we normally have to render first..
37336 if (this.footer && !this.footer.el && this.footer.xtype) {
37337 if (!this.wrapEl) {
37338 this.wrapEl = this.el.wrap();
37341 this.footer.container = this.wrapEl.createChild();
37343 this.footer = Roo.factory(this.footer, Roo);
37348 if(typeof config == "string"){
37349 this.title = config;
37351 Roo.apply(this, config);
37355 this.resizeEl = Roo.get(this.resizeEl, true);
37357 this.resizeEl = this.el;
37359 // handle view.xtype
37367 * Fires when this panel is activated.
37368 * @param {Roo.ContentPanel} this
37372 * @event deactivate
37373 * Fires when this panel is activated.
37374 * @param {Roo.ContentPanel} this
37376 "deactivate" : true,
37380 * Fires when this panel is resized if fitToFrame is true.
37381 * @param {Roo.ContentPanel} this
37382 * @param {Number} width The width after any component adjustments
37383 * @param {Number} height The height after any component adjustments
37389 * Fires when this tab is created
37390 * @param {Roo.ContentPanel} this
37401 if(this.autoScroll){
37402 this.resizeEl.setStyle("overflow", "auto");
37404 // fix randome scrolling
37405 //this.el.on('scroll', function() {
37406 // Roo.log('fix random scolling');
37407 // this.scrollTo('top',0);
37410 content = content || this.content;
37412 this.setContent(content);
37414 if(config && config.url){
37415 this.setUrl(this.url, this.params, this.loadOnce);
37420 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37422 if (this.view && typeof(this.view.xtype) != 'undefined') {
37423 this.view.el = this.el.appendChild(document.createElement("div"));
37424 this.view = Roo.factory(this.view);
37425 this.view.render && this.view.render(false, '');
37429 this.fireEvent('render', this);
37432 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37436 setRegion : function(region){
37437 this.region = region;
37438 this.setActiveClass(region && !this.background);
37442 setActiveClass: function(state)
37445 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37446 this.el.setStyle('position','relative');
37448 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37449 this.el.setStyle('position', 'absolute');
37454 * Returns the toolbar for this Panel if one was configured.
37455 * @return {Roo.Toolbar}
37457 getToolbar : function(){
37458 return this.toolbar;
37461 setActiveState : function(active)
37463 this.active = active;
37464 this.setActiveClass(active);
37466 if(this.fireEvent("deactivate", this) === false){
37471 this.fireEvent("activate", this);
37475 * Updates this panel's element
37476 * @param {String} content The new content
37477 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37479 setContent : function(content, loadScripts){
37480 this.el.update(content, loadScripts);
37483 ignoreResize : function(w, h){
37484 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37487 this.lastSize = {width: w, height: h};
37492 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37493 * @return {Roo.UpdateManager} The UpdateManager
37495 getUpdateManager : function(){
37496 return this.el.getUpdateManager();
37499 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37500 * @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:
37503 url: "your-url.php",
37504 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37505 callback: yourFunction,
37506 scope: yourObject, //(optional scope)
37509 text: "Loading...",
37514 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37515 * 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.
37516 * @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}
37517 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37518 * @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.
37519 * @return {Roo.ContentPanel} this
37522 var um = this.el.getUpdateManager();
37523 um.update.apply(um, arguments);
37529 * 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.
37530 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37531 * @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)
37532 * @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)
37533 * @return {Roo.UpdateManager} The UpdateManager
37535 setUrl : function(url, params, loadOnce){
37536 if(this.refreshDelegate){
37537 this.removeListener("activate", this.refreshDelegate);
37539 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37540 this.on("activate", this.refreshDelegate);
37541 return this.el.getUpdateManager();
37544 _handleRefresh : function(url, params, loadOnce){
37545 if(!loadOnce || !this.loaded){
37546 var updater = this.el.getUpdateManager();
37547 updater.update(url, params, this._setLoaded.createDelegate(this));
37551 _setLoaded : function(){
37552 this.loaded = true;
37556 * Returns this panel's id
37559 getId : function(){
37564 * Returns this panel's element - used by regiosn to add.
37565 * @return {Roo.Element}
37567 getEl : function(){
37568 return this.wrapEl || this.el;
37573 adjustForComponents : function(width, height)
37575 //Roo.log('adjustForComponents ');
37576 if(this.resizeEl != this.el){
37577 width -= this.el.getFrameWidth('lr');
37578 height -= this.el.getFrameWidth('tb');
37581 var te = this.toolbar.getEl();
37582 te.setWidth(width);
37583 height -= te.getHeight();
37586 var te = this.footer.getEl();
37587 te.setWidth(width);
37588 height -= te.getHeight();
37592 if(this.adjustments){
37593 width += this.adjustments[0];
37594 height += this.adjustments[1];
37596 return {"width": width, "height": height};
37599 setSize : function(width, height){
37600 if(this.fitToFrame && !this.ignoreResize(width, height)){
37601 if(this.fitContainer && this.resizeEl != this.el){
37602 this.el.setSize(width, height);
37604 var size = this.adjustForComponents(width, height);
37605 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37606 this.fireEvent('resize', this, size.width, size.height);
37611 * Returns this panel's title
37614 getTitle : function(){
37616 if (typeof(this.title) != 'object') {
37621 for (var k in this.title) {
37622 if (!this.title.hasOwnProperty(k)) {
37626 if (k.indexOf('-') >= 0) {
37627 var s = k.split('-');
37628 for (var i = 0; i<s.length; i++) {
37629 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37632 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37639 * Set this panel's title
37640 * @param {String} title
37642 setTitle : function(title){
37643 this.title = title;
37645 this.region.updatePanelTitle(this, title);
37650 * Returns true is this panel was configured to be closable
37651 * @return {Boolean}
37653 isClosable : function(){
37654 return this.closable;
37657 beforeSlide : function(){
37659 this.resizeEl.clip();
37662 afterSlide : function(){
37664 this.resizeEl.unclip();
37668 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37669 * Will fail silently if the {@link #setUrl} method has not been called.
37670 * This does not activate the panel, just updates its content.
37672 refresh : function(){
37673 if(this.refreshDelegate){
37674 this.loaded = false;
37675 this.refreshDelegate();
37680 * Destroys this panel
37682 destroy : function(){
37683 this.el.removeAllListeners();
37684 var tempEl = document.createElement("span");
37685 tempEl.appendChild(this.el.dom);
37686 tempEl.innerHTML = "";
37692 * form - if the content panel contains a form - this is a reference to it.
37693 * @type {Roo.form.Form}
37697 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37698 * This contains a reference to it.
37704 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37714 * @param {Object} cfg Xtype definition of item to add.
37718 getChildContainer: function () {
37719 return this.getEl();
37724 var ret = new Roo.factory(cfg);
37729 if (cfg.xtype.match(/^Form$/)) {
37732 //if (this.footer) {
37733 // el = this.footer.container.insertSibling(false, 'before');
37735 el = this.el.createChild();
37738 this.form = new Roo.form.Form(cfg);
37741 if ( this.form.allItems.length) {
37742 this.form.render(el.dom);
37746 // should only have one of theses..
37747 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37748 // views.. should not be just added - used named prop 'view''
37750 cfg.el = this.el.appendChild(document.createElement("div"));
37753 var ret = new Roo.factory(cfg);
37755 ret.render && ret.render(false, ''); // render blank..
37765 * @class Roo.bootstrap.panel.Grid
37766 * @extends Roo.bootstrap.panel.Content
37768 * Create a new GridPanel.
37769 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37770 * @param {Object} config A the config object
37776 Roo.bootstrap.panel.Grid = function(config)
37780 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37781 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37783 config.el = this.wrapper;
37784 //this.el = this.wrapper;
37786 if (config.container) {
37787 // ctor'ed from a Border/panel.grid
37790 this.wrapper.setStyle("overflow", "hidden");
37791 this.wrapper.addClass('roo-grid-container');
37796 if(config.toolbar){
37797 var tool_el = this.wrapper.createChild();
37798 this.toolbar = Roo.factory(config.toolbar);
37800 if (config.toolbar.items) {
37801 ti = config.toolbar.items ;
37802 delete config.toolbar.items ;
37806 this.toolbar.render(tool_el);
37807 for(var i =0;i < ti.length;i++) {
37808 // Roo.log(['add child', items[i]]);
37809 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37811 this.toolbar.items = nitems;
37813 delete config.toolbar;
37816 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37817 config.grid.scrollBody = true;;
37818 config.grid.monitorWindowResize = false; // turn off autosizing
37819 config.grid.autoHeight = false;
37820 config.grid.autoWidth = false;
37822 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37824 if (config.background) {
37825 // render grid on panel activation (if panel background)
37826 this.on('activate', function(gp) {
37827 if (!gp.grid.rendered) {
37828 gp.grid.render(this.wrapper);
37829 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37834 this.grid.render(this.wrapper);
37835 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37838 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37839 // ??? needed ??? config.el = this.wrapper;
37844 // xtype created footer. - not sure if will work as we normally have to render first..
37845 if (this.footer && !this.footer.el && this.footer.xtype) {
37847 var ctr = this.grid.getView().getFooterPanel(true);
37848 this.footer.dataSource = this.grid.dataSource;
37849 this.footer = Roo.factory(this.footer, Roo);
37850 this.footer.render(ctr);
37860 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37861 getId : function(){
37862 return this.grid.id;
37866 * Returns the grid for this panel
37867 * @return {Roo.bootstrap.Table}
37869 getGrid : function(){
37873 setSize : function(width, height){
37874 if(!this.ignoreResize(width, height)){
37875 var grid = this.grid;
37876 var size = this.adjustForComponents(width, height);
37877 var gridel = grid.getGridEl();
37878 gridel.setSize(size.width, size.height);
37880 var thd = grid.getGridEl().select('thead',true).first();
37881 var tbd = grid.getGridEl().select('tbody', true).first();
37883 tbd.setSize(width, height - thd.getHeight());
37892 beforeSlide : function(){
37893 this.grid.getView().scroller.clip();
37896 afterSlide : function(){
37897 this.grid.getView().scroller.unclip();
37900 destroy : function(){
37901 this.grid.destroy();
37903 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37908 * @class Roo.bootstrap.panel.Nest
37909 * @extends Roo.bootstrap.panel.Content
37911 * Create a new Panel, that can contain a layout.Border.
37914 * @param {Roo.BorderLayout} layout The layout for this panel
37915 * @param {String/Object} config A string to set only the title or a config object
37917 Roo.bootstrap.panel.Nest = function(config)
37919 // construct with only one argument..
37920 /* FIXME - implement nicer consturctors
37921 if (layout.layout) {
37923 layout = config.layout;
37924 delete config.layout;
37926 if (layout.xtype && !layout.getEl) {
37927 // then layout needs constructing..
37928 layout = Roo.factory(layout, Roo);
37932 config.el = config.layout.getEl();
37934 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37936 config.layout.monitorWindowResize = false; // turn off autosizing
37937 this.layout = config.layout;
37938 this.layout.getEl().addClass("roo-layout-nested-layout");
37939 this.layout.parent = this;
37946 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37948 setSize : function(width, height){
37949 if(!this.ignoreResize(width, height)){
37950 var size = this.adjustForComponents(width, height);
37951 var el = this.layout.getEl();
37952 if (size.height < 1) {
37953 el.setWidth(size.width);
37955 el.setSize(size.width, size.height);
37957 var touch = el.dom.offsetWidth;
37958 this.layout.layout();
37959 // ie requires a double layout on the first pass
37960 if(Roo.isIE && !this.initialized){
37961 this.initialized = true;
37962 this.layout.layout();
37967 // activate all subpanels if not currently active..
37969 setActiveState : function(active){
37970 this.active = active;
37971 this.setActiveClass(active);
37974 this.fireEvent("deactivate", this);
37978 this.fireEvent("activate", this);
37979 // not sure if this should happen before or after..
37980 if (!this.layout) {
37981 return; // should not happen..
37984 for (var r in this.layout.regions) {
37985 reg = this.layout.getRegion(r);
37986 if (reg.getActivePanel()) {
37987 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37988 reg.setActivePanel(reg.getActivePanel());
37991 if (!reg.panels.length) {
37994 reg.showPanel(reg.getPanel(0));
38003 * Returns the nested BorderLayout for this panel
38004 * @return {Roo.BorderLayout}
38006 getLayout : function(){
38007 return this.layout;
38011 * Adds a xtype elements to the layout of the nested panel
38015 xtype : 'ContentPanel',
38022 xtype : 'NestedLayoutPanel',
38028 items : [ ... list of content panels or nested layout panels.. ]
38032 * @param {Object} cfg Xtype definition of item to add.
38034 addxtype : function(cfg) {
38035 return this.layout.addxtype(cfg);
38040 * Ext JS Library 1.1.1
38041 * Copyright(c) 2006-2007, Ext JS, LLC.
38043 * Originally Released Under LGPL - original licence link has changed is not relivant.
38046 * <script type="text/javascript">
38049 * @class Roo.TabPanel
38050 * @extends Roo.util.Observable
38051 * A lightweight tab container.
38055 // basic tabs 1, built from existing content
38056 var tabs = new Roo.TabPanel("tabs1");
38057 tabs.addTab("script", "View Script");
38058 tabs.addTab("markup", "View Markup");
38059 tabs.activate("script");
38061 // more advanced tabs, built from javascript
38062 var jtabs = new Roo.TabPanel("jtabs");
38063 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38065 // set up the UpdateManager
38066 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38067 var updater = tab2.getUpdateManager();
38068 updater.setDefaultUrl("ajax1.htm");
38069 tab2.on('activate', updater.refresh, updater, true);
38071 // Use setUrl for Ajax loading
38072 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38073 tab3.setUrl("ajax2.htm", null, true);
38076 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38079 jtabs.activate("jtabs-1");
38082 * Create a new TabPanel.
38083 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38084 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38086 Roo.bootstrap.panel.Tabs = function(config){
38088 * The container element for this TabPanel.
38089 * @type Roo.Element
38091 this.el = Roo.get(config.el);
38094 if(typeof config == "boolean"){
38095 this.tabPosition = config ? "bottom" : "top";
38097 Roo.apply(this, config);
38101 if(this.tabPosition == "bottom"){
38102 // if tabs are at the bottom = create the body first.
38103 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38104 this.el.addClass("roo-tabs-bottom");
38106 // next create the tabs holders
38108 if (this.tabPosition == "west"){
38110 var reg = this.region; // fake it..
38112 if (!reg.mgr.parent) {
38115 reg = reg.mgr.parent.region;
38117 Roo.log("got nest?");
38119 if (reg.mgr.getRegion('west')) {
38120 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38121 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38122 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38123 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38124 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38132 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38133 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38134 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38135 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38140 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38143 // finally - if tabs are at the top, then create the body last..
38144 if(this.tabPosition != "bottom"){
38145 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38146 * @type Roo.Element
38148 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38149 this.el.addClass("roo-tabs-top");
38153 this.bodyEl.setStyle("position", "relative");
38155 this.active = null;
38156 this.activateDelegate = this.activate.createDelegate(this);
38161 * Fires when the active tab changes
38162 * @param {Roo.TabPanel} this
38163 * @param {Roo.TabPanelItem} activePanel The new active tab
38167 * @event beforetabchange
38168 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38169 * @param {Roo.TabPanel} this
38170 * @param {Object} e Set cancel to true on this object to cancel the tab change
38171 * @param {Roo.TabPanelItem} tab The tab being changed to
38173 "beforetabchange" : true
38176 Roo.EventManager.onWindowResize(this.onResize, this);
38177 this.cpad = this.el.getPadding("lr");
38178 this.hiddenCount = 0;
38181 // toolbar on the tabbar support...
38182 if (this.toolbar) {
38183 alert("no toolbar support yet");
38184 this.toolbar = false;
38186 var tcfg = this.toolbar;
38187 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38188 this.toolbar = new Roo.Toolbar(tcfg);
38189 if (Roo.isSafari) {
38190 var tbl = tcfg.container.child('table', true);
38191 tbl.setAttribute('width', '100%');
38199 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38202 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38204 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38206 tabPosition : "top",
38208 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38210 currentTabWidth : 0,
38212 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38216 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38220 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38222 preferredTabWidth : 175,
38224 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38226 resizeTabs : false,
38228 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38230 monitorResize : true,
38232 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38234 toolbar : false, // set by caller..
38236 region : false, /// set by caller
38238 disableTooltips : true, // not used yet...
38241 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38242 * @param {String} id The id of the div to use <b>or create</b>
38243 * @param {String} text The text for the tab
38244 * @param {String} content (optional) Content to put in the TabPanelItem body
38245 * @param {Boolean} closable (optional) True to create a close icon on the tab
38246 * @return {Roo.TabPanelItem} The created TabPanelItem
38248 addTab : function(id, text, content, closable, tpl)
38250 var item = new Roo.bootstrap.panel.TabItem({
38254 closable : closable,
38257 this.addTabItem(item);
38259 item.setContent(content);
38265 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38266 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38267 * @return {Roo.TabPanelItem}
38269 getTab : function(id){
38270 return this.items[id];
38274 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38275 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38277 hideTab : function(id){
38278 var t = this.items[id];
38281 this.hiddenCount++;
38282 this.autoSizeTabs();
38287 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38288 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38290 unhideTab : function(id){
38291 var t = this.items[id];
38293 t.setHidden(false);
38294 this.hiddenCount--;
38295 this.autoSizeTabs();
38300 * Adds an existing {@link Roo.TabPanelItem}.
38301 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38303 addTabItem : function(item)
38305 this.items[item.id] = item;
38306 this.items.push(item);
38307 this.autoSizeTabs();
38308 // if(this.resizeTabs){
38309 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38310 // this.autoSizeTabs();
38312 // item.autoSize();
38317 * Removes a {@link Roo.TabPanelItem}.
38318 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38320 removeTab : function(id){
38321 var items = this.items;
38322 var tab = items[id];
38323 if(!tab) { return; }
38324 var index = items.indexOf(tab);
38325 if(this.active == tab && items.length > 1){
38326 var newTab = this.getNextAvailable(index);
38331 this.stripEl.dom.removeChild(tab.pnode.dom);
38332 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38333 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38335 items.splice(index, 1);
38336 delete this.items[tab.id];
38337 tab.fireEvent("close", tab);
38338 tab.purgeListeners();
38339 this.autoSizeTabs();
38342 getNextAvailable : function(start){
38343 var items = this.items;
38345 // look for a next tab that will slide over to
38346 // replace the one being removed
38347 while(index < items.length){
38348 var item = items[++index];
38349 if(item && !item.isHidden()){
38353 // if one isn't found select the previous tab (on the left)
38356 var item = items[--index];
38357 if(item && !item.isHidden()){
38365 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38366 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38368 disableTab : function(id){
38369 var tab = this.items[id];
38370 if(tab && this.active != tab){
38376 * Enables a {@link Roo.TabPanelItem} that is disabled.
38377 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38379 enableTab : function(id){
38380 var tab = this.items[id];
38385 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38386 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38387 * @return {Roo.TabPanelItem} The TabPanelItem.
38389 activate : function(id)
38391 //Roo.log('activite:' + id);
38393 var tab = this.items[id];
38397 if(tab == this.active || tab.disabled){
38401 this.fireEvent("beforetabchange", this, e, tab);
38402 if(e.cancel !== true && !tab.disabled){
38404 this.active.hide();
38406 this.active = this.items[id];
38407 this.active.show();
38408 this.fireEvent("tabchange", this, this.active);
38414 * Gets the active {@link Roo.TabPanelItem}.
38415 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38417 getActiveTab : function(){
38418 return this.active;
38422 * Updates the tab body element to fit the height of the container element
38423 * for overflow scrolling
38424 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38426 syncHeight : function(targetHeight){
38427 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38428 var bm = this.bodyEl.getMargins();
38429 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38430 this.bodyEl.setHeight(newHeight);
38434 onResize : function(){
38435 if(this.monitorResize){
38436 this.autoSizeTabs();
38441 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38443 beginUpdate : function(){
38444 this.updating = true;
38448 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38450 endUpdate : function(){
38451 this.updating = false;
38452 this.autoSizeTabs();
38456 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38458 autoSizeTabs : function()
38460 var count = this.items.length;
38461 var vcount = count - this.hiddenCount;
38464 this.stripEl.hide();
38466 this.stripEl.show();
38469 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38474 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38475 var availWidth = Math.floor(w / vcount);
38476 var b = this.stripBody;
38477 if(b.getWidth() > w){
38478 var tabs = this.items;
38479 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38480 if(availWidth < this.minTabWidth){
38481 /*if(!this.sleft){ // incomplete scrolling code
38482 this.createScrollButtons();
38485 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38488 if(this.currentTabWidth < this.preferredTabWidth){
38489 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38495 * Returns the number of tabs in this TabPanel.
38498 getCount : function(){
38499 return this.items.length;
38503 * Resizes all the tabs to the passed width
38504 * @param {Number} The new width
38506 setTabWidth : function(width){
38507 this.currentTabWidth = width;
38508 for(var i = 0, len = this.items.length; i < len; i++) {
38509 if(!this.items[i].isHidden()) {
38510 this.items[i].setWidth(width);
38516 * Destroys this TabPanel
38517 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38519 destroy : function(removeEl){
38520 Roo.EventManager.removeResizeListener(this.onResize, this);
38521 for(var i = 0, len = this.items.length; i < len; i++){
38522 this.items[i].purgeListeners();
38524 if(removeEl === true){
38525 this.el.update("");
38530 createStrip : function(container)
38532 var strip = document.createElement("nav");
38533 strip.className = Roo.bootstrap.version == 4 ?
38534 "navbar-light bg-light" :
38535 "navbar navbar-default"; //"x-tabs-wrap";
38536 container.appendChild(strip);
38540 createStripList : function(strip)
38542 // div wrapper for retard IE
38543 // returns the "tr" element.
38544 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38545 //'<div class="x-tabs-strip-wrap">'+
38546 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38547 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38548 return strip.firstChild; //.firstChild.firstChild.firstChild;
38550 createBody : function(container)
38552 var body = document.createElement("div");
38553 Roo.id(body, "tab-body");
38554 //Roo.fly(body).addClass("x-tabs-body");
38555 Roo.fly(body).addClass("tab-content");
38556 container.appendChild(body);
38559 createItemBody :function(bodyEl, id){
38560 var body = Roo.getDom(id);
38562 body = document.createElement("div");
38565 //Roo.fly(body).addClass("x-tabs-item-body");
38566 Roo.fly(body).addClass("tab-pane");
38567 bodyEl.insertBefore(body, bodyEl.firstChild);
38571 createStripElements : function(stripEl, text, closable, tpl)
38573 var td = document.createElement("li"); // was td..
38574 td.className = 'nav-item';
38576 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38579 stripEl.appendChild(td);
38581 td.className = "x-tabs-closable";
38582 if(!this.closeTpl){
38583 this.closeTpl = new Roo.Template(
38584 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38585 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38586 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38589 var el = this.closeTpl.overwrite(td, {"text": text});
38590 var close = el.getElementsByTagName("div")[0];
38591 var inner = el.getElementsByTagName("em")[0];
38592 return {"el": el, "close": close, "inner": inner};
38595 // not sure what this is..
38596 // if(!this.tabTpl){
38597 //this.tabTpl = new Roo.Template(
38598 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38599 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38601 // this.tabTpl = new Roo.Template(
38602 // '<a href="#">' +
38603 // '<span unselectable="on"' +
38604 // (this.disableTooltips ? '' : ' title="{text}"') +
38605 // ' >{text}</span></a>'
38611 var template = tpl || this.tabTpl || false;
38614 template = new Roo.Template(
38615 Roo.bootstrap.version == 4 ?
38617 '<a class="nav-link" href="#" unselectable="on"' +
38618 (this.disableTooltips ? '' : ' title="{text}"') +
38621 '<a class="nav-link" href="#">' +
38622 '<span unselectable="on"' +
38623 (this.disableTooltips ? '' : ' title="{text}"') +
38624 ' >{text}</span></a>'
38629 switch (typeof(template)) {
38633 template = new Roo.Template(template);
38639 var el = template.overwrite(td, {"text": text});
38641 var inner = el.getElementsByTagName("span")[0];
38643 return {"el": el, "inner": inner};
38651 * @class Roo.TabPanelItem
38652 * @extends Roo.util.Observable
38653 * Represents an individual item (tab plus body) in a TabPanel.
38654 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38655 * @param {String} id The id of this TabPanelItem
38656 * @param {String} text The text for the tab of this TabPanelItem
38657 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38659 Roo.bootstrap.panel.TabItem = function(config){
38661 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38662 * @type Roo.TabPanel
38664 this.tabPanel = config.panel;
38666 * The id for this TabPanelItem
38669 this.id = config.id;
38671 this.disabled = false;
38673 this.text = config.text;
38675 this.loaded = false;
38676 this.closable = config.closable;
38679 * The body element for this TabPanelItem.
38680 * @type Roo.Element
38682 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38683 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38684 this.bodyEl.setStyle("display", "block");
38685 this.bodyEl.setStyle("zoom", "1");
38686 //this.hideAction();
38688 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38690 this.el = Roo.get(els.el);
38691 this.inner = Roo.get(els.inner, true);
38692 this.textEl = Roo.bootstrap.version == 4 ?
38693 this.el : Roo.get(this.el.dom.firstChild, true);
38695 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38696 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38699 // this.el.on("mousedown", this.onTabMouseDown, this);
38700 this.el.on("click", this.onTabClick, this);
38702 if(config.closable){
38703 var c = Roo.get(els.close, true);
38704 c.dom.title = this.closeText;
38705 c.addClassOnOver("close-over");
38706 c.on("click", this.closeClick, this);
38712 * Fires when this tab becomes the active tab.
38713 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38714 * @param {Roo.TabPanelItem} this
38718 * @event beforeclose
38719 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38720 * @param {Roo.TabPanelItem} this
38721 * @param {Object} e Set cancel to true on this object to cancel the close.
38723 "beforeclose": true,
38726 * Fires when this tab is closed.
38727 * @param {Roo.TabPanelItem} this
38731 * @event deactivate
38732 * Fires when this tab is no longer the active tab.
38733 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38734 * @param {Roo.TabPanelItem} this
38736 "deactivate" : true
38738 this.hidden = false;
38740 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38743 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38745 purgeListeners : function(){
38746 Roo.util.Observable.prototype.purgeListeners.call(this);
38747 this.el.removeAllListeners();
38750 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38753 this.status_node.addClass("active");
38756 this.tabPanel.stripWrap.repaint();
38758 this.fireEvent("activate", this.tabPanel, this);
38762 * Returns true if this tab is the active tab.
38763 * @return {Boolean}
38765 isActive : function(){
38766 return this.tabPanel.getActiveTab() == this;
38770 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38773 this.status_node.removeClass("active");
38775 this.fireEvent("deactivate", this.tabPanel, this);
38778 hideAction : function(){
38779 this.bodyEl.hide();
38780 this.bodyEl.setStyle("position", "absolute");
38781 this.bodyEl.setLeft("-20000px");
38782 this.bodyEl.setTop("-20000px");
38785 showAction : function(){
38786 this.bodyEl.setStyle("position", "relative");
38787 this.bodyEl.setTop("");
38788 this.bodyEl.setLeft("");
38789 this.bodyEl.show();
38793 * Set the tooltip for the tab.
38794 * @param {String} tooltip The tab's tooltip
38796 setTooltip : function(text){
38797 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38798 this.textEl.dom.qtip = text;
38799 this.textEl.dom.removeAttribute('title');
38801 this.textEl.dom.title = text;
38805 onTabClick : function(e){
38806 e.preventDefault();
38807 this.tabPanel.activate(this.id);
38810 onTabMouseDown : function(e){
38811 e.preventDefault();
38812 this.tabPanel.activate(this.id);
38815 getWidth : function(){
38816 return this.inner.getWidth();
38819 setWidth : function(width){
38820 var iwidth = width - this.linode.getPadding("lr");
38821 this.inner.setWidth(iwidth);
38822 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38823 this.linode.setWidth(width);
38827 * Show or hide the tab
38828 * @param {Boolean} hidden True to hide or false to show.
38830 setHidden : function(hidden){
38831 this.hidden = hidden;
38832 this.linode.setStyle("display", hidden ? "none" : "");
38836 * Returns true if this tab is "hidden"
38837 * @return {Boolean}
38839 isHidden : function(){
38840 return this.hidden;
38844 * Returns the text for this tab
38847 getText : function(){
38851 autoSize : function(){
38852 //this.el.beginMeasure();
38853 this.textEl.setWidth(1);
38855 * #2804 [new] Tabs in Roojs
38856 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38858 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38859 //this.el.endMeasure();
38863 * Sets the text for the tab (Note: this also sets the tooltip text)
38864 * @param {String} text The tab's text and tooltip
38866 setText : function(text){
38868 this.textEl.update(text);
38869 this.setTooltip(text);
38870 //if(!this.tabPanel.resizeTabs){
38871 // this.autoSize();
38875 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38877 activate : function(){
38878 this.tabPanel.activate(this.id);
38882 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38884 disable : function(){
38885 if(this.tabPanel.active != this){
38886 this.disabled = true;
38887 this.status_node.addClass("disabled");
38892 * Enables this TabPanelItem if it was previously disabled.
38894 enable : function(){
38895 this.disabled = false;
38896 this.status_node.removeClass("disabled");
38900 * Sets the content for this TabPanelItem.
38901 * @param {String} content The content
38902 * @param {Boolean} loadScripts true to look for and load scripts
38904 setContent : function(content, loadScripts){
38905 this.bodyEl.update(content, loadScripts);
38909 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38910 * @return {Roo.UpdateManager} The UpdateManager
38912 getUpdateManager : function(){
38913 return this.bodyEl.getUpdateManager();
38917 * Set a URL to be used to load the content for this TabPanelItem.
38918 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38919 * @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)
38920 * @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)
38921 * @return {Roo.UpdateManager} The UpdateManager
38923 setUrl : function(url, params, loadOnce){
38924 if(this.refreshDelegate){
38925 this.un('activate', this.refreshDelegate);
38927 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38928 this.on("activate", this.refreshDelegate);
38929 return this.bodyEl.getUpdateManager();
38933 _handleRefresh : function(url, params, loadOnce){
38934 if(!loadOnce || !this.loaded){
38935 var updater = this.bodyEl.getUpdateManager();
38936 updater.update(url, params, this._setLoaded.createDelegate(this));
38941 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38942 * Will fail silently if the setUrl method has not been called.
38943 * This does not activate the panel, just updates its content.
38945 refresh : function(){
38946 if(this.refreshDelegate){
38947 this.loaded = false;
38948 this.refreshDelegate();
38953 _setLoaded : function(){
38954 this.loaded = true;
38958 closeClick : function(e){
38961 this.fireEvent("beforeclose", this, o);
38962 if(o.cancel !== true){
38963 this.tabPanel.removeTab(this.id);
38967 * The text displayed in the tooltip for the close icon.
38970 closeText : "Close this tab"
38973 * This script refer to:
38974 * Title: International Telephone Input
38975 * Author: Jack O'Connor
38976 * Code version: v12.1.12
38977 * Availability: https://github.com/jackocnr/intl-tel-input.git
38980 Roo.bootstrap.PhoneInputData = function() {
38983 "Afghanistan (افغانستان)",
38988 "Albania (Shqipëri)",
38993 "Algeria (الجزائر)",
39018 "Antigua and Barbuda",
39028 "Armenia (Հայաստան)",
39044 "Austria (Österreich)",
39049 "Azerbaijan (Azərbaycan)",
39059 "Bahrain (البحرين)",
39064 "Bangladesh (বাংলাদেশ)",
39074 "Belarus (Беларусь)",
39079 "Belgium (België)",
39109 "Bosnia and Herzegovina (Босна и Херцеговина)",
39124 "British Indian Ocean Territory",
39129 "British Virgin Islands",
39139 "Bulgaria (България)",
39149 "Burundi (Uburundi)",
39154 "Cambodia (កម្ពុជា)",
39159 "Cameroon (Cameroun)",
39168 ["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"]
39171 "Cape Verde (Kabu Verdi)",
39176 "Caribbean Netherlands",
39187 "Central African Republic (République centrafricaine)",
39207 "Christmas Island",
39213 "Cocos (Keeling) Islands",
39224 "Comoros (جزر القمر)",
39229 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39234 "Congo (Republic) (Congo-Brazzaville)",
39254 "Croatia (Hrvatska)",
39275 "Czech Republic (Česká republika)",
39280 "Denmark (Danmark)",
39295 "Dominican Republic (República Dominicana)",
39299 ["809", "829", "849"]
39317 "Equatorial Guinea (Guinea Ecuatorial)",
39337 "Falkland Islands (Islas Malvinas)",
39342 "Faroe Islands (Føroyar)",
39363 "French Guiana (Guyane française)",
39368 "French Polynesia (Polynésie française)",
39383 "Georgia (საქართველო)",
39388 "Germany (Deutschland)",
39408 "Greenland (Kalaallit Nunaat)",
39445 "Guinea-Bissau (Guiné Bissau)",
39470 "Hungary (Magyarország)",
39475 "Iceland (Ísland)",
39495 "Iraq (العراق)",
39511 "Israel (ישראל)",
39538 "Jordan (الأردن)",
39543 "Kazakhstan (Казахстан)",
39564 "Kuwait (الكويت)",
39569 "Kyrgyzstan (Кыргызстан)",
39579 "Latvia (Latvija)",
39584 "Lebanon (لبنان)",
39599 "Libya (ليبيا)",
39609 "Lithuania (Lietuva)",
39624 "Macedonia (FYROM) (Македонија)",
39629 "Madagascar (Madagasikara)",
39659 "Marshall Islands",
39669 "Mauritania (موريتانيا)",
39674 "Mauritius (Moris)",
39695 "Moldova (Republica Moldova)",
39705 "Mongolia (Монгол)",
39710 "Montenegro (Crna Gora)",
39720 "Morocco (المغرب)",
39726 "Mozambique (Moçambique)",
39731 "Myanmar (Burma) (မြန်မာ)",
39736 "Namibia (Namibië)",
39751 "Netherlands (Nederland)",
39756 "New Caledonia (Nouvelle-Calédonie)",
39791 "North Korea (조선 민주주의 인민 공화국)",
39796 "Northern Mariana Islands",
39812 "Pakistan (پاکستان)",
39822 "Palestine (فلسطين)",
39832 "Papua New Guinea",
39874 "Réunion (La Réunion)",
39880 "Romania (România)",
39896 "Saint Barthélemy",
39907 "Saint Kitts and Nevis",
39917 "Saint Martin (Saint-Martin (partie française))",
39923 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39928 "Saint Vincent and the Grenadines",
39943 "São Tomé and Príncipe (São Tomé e Príncipe)",
39948 "Saudi Arabia (المملكة العربية السعودية)",
39953 "Senegal (Sénégal)",
39983 "Slovakia (Slovensko)",
39988 "Slovenia (Slovenija)",
39998 "Somalia (Soomaaliya)",
40008 "South Korea (대한민국)",
40013 "South Sudan (جنوب السودان)",
40023 "Sri Lanka (ශ්රී ලංකාව)",
40028 "Sudan (السودان)",
40038 "Svalbard and Jan Mayen",
40049 "Sweden (Sverige)",
40054 "Switzerland (Schweiz)",
40059 "Syria (سوريا)",
40104 "Trinidad and Tobago",
40109 "Tunisia (تونس)",
40114 "Turkey (Türkiye)",
40124 "Turks and Caicos Islands",
40134 "U.S. Virgin Islands",
40144 "Ukraine (Україна)",
40149 "United Arab Emirates (الإمارات العربية المتحدة)",
40171 "Uzbekistan (Oʻzbekiston)",
40181 "Vatican City (Città del Vaticano)",
40192 "Vietnam (Việt Nam)",
40197 "Wallis and Futuna (Wallis-et-Futuna)",
40202 "Western Sahara (الصحراء الغربية)",
40208 "Yemen (اليمن)",
40232 * This script refer to:
40233 * Title: International Telephone Input
40234 * Author: Jack O'Connor
40235 * Code version: v12.1.12
40236 * Availability: https://github.com/jackocnr/intl-tel-input.git
40240 * @class Roo.bootstrap.PhoneInput
40241 * @extends Roo.bootstrap.TriggerField
40242 * An input with International dial-code selection
40244 * @cfg {String} defaultDialCode default '+852'
40245 * @cfg {Array} preferedCountries default []
40248 * Create a new PhoneInput.
40249 * @param {Object} config Configuration options
40252 Roo.bootstrap.PhoneInput = function(config) {
40253 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40256 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40258 listWidth: undefined,
40260 selectedClass: 'active',
40262 invalidClass : "has-warning",
40264 validClass: 'has-success',
40266 allowed: '0123456789',
40271 * @cfg {String} defaultDialCode The default dial code when initializing the input
40273 defaultDialCode: '+852',
40276 * @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
40278 preferedCountries: false,
40280 getAutoCreate : function()
40282 var data = Roo.bootstrap.PhoneInputData();
40283 var align = this.labelAlign || this.parentLabelAlign();
40286 this.allCountries = [];
40287 this.dialCodeMapping = [];
40289 for (var i = 0; i < data.length; i++) {
40291 this.allCountries[i] = {
40295 priority: c[3] || 0,
40296 areaCodes: c[4] || null
40298 this.dialCodeMapping[c[2]] = {
40301 priority: c[3] || 0,
40302 areaCodes: c[4] || null
40314 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40315 maxlength: this.max_length,
40316 cls : 'form-control tel-input',
40317 autocomplete: 'new-password'
40320 var hiddenInput = {
40323 cls: 'hidden-tel-input'
40327 hiddenInput.name = this.name;
40330 if (this.disabled) {
40331 input.disabled = true;
40334 var flag_container = {
40351 cls: this.hasFeedback ? 'has-feedback' : '',
40357 cls: 'dial-code-holder',
40364 cls: 'roo-select2-container input-group',
40371 if (this.fieldLabel.length) {
40374 tooltip: 'This field is required'
40380 cls: 'control-label',
40386 html: this.fieldLabel
40389 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40395 if(this.indicatorpos == 'right') {
40396 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40403 if(align == 'left') {
40411 if(this.labelWidth > 12){
40412 label.style = "width: " + this.labelWidth + 'px';
40414 if(this.labelWidth < 13 && this.labelmd == 0){
40415 this.labelmd = this.labelWidth;
40417 if(this.labellg > 0){
40418 label.cls += ' col-lg-' + this.labellg;
40419 input.cls += ' col-lg-' + (12 - this.labellg);
40421 if(this.labelmd > 0){
40422 label.cls += ' col-md-' + this.labelmd;
40423 container.cls += ' col-md-' + (12 - this.labelmd);
40425 if(this.labelsm > 0){
40426 label.cls += ' col-sm-' + this.labelsm;
40427 container.cls += ' col-sm-' + (12 - this.labelsm);
40429 if(this.labelxs > 0){
40430 label.cls += ' col-xs-' + this.labelxs;
40431 container.cls += ' col-xs-' + (12 - this.labelxs);
40441 var settings = this;
40443 ['xs','sm','md','lg'].map(function(size){
40444 if (settings[size]) {
40445 cfg.cls += ' col-' + size + '-' + settings[size];
40449 this.store = new Roo.data.Store({
40450 proxy : new Roo.data.MemoryProxy({}),
40451 reader : new Roo.data.JsonReader({
40462 'name' : 'dialCode',
40466 'name' : 'priority',
40470 'name' : 'areaCodes',
40477 if(!this.preferedCountries) {
40478 this.preferedCountries = [
40485 var p = this.preferedCountries.reverse();
40488 for (var i = 0; i < p.length; i++) {
40489 for (var j = 0; j < this.allCountries.length; j++) {
40490 if(this.allCountries[j].iso2 == p[i]) {
40491 var t = this.allCountries[j];
40492 this.allCountries.splice(j,1);
40493 this.allCountries.unshift(t);
40499 this.store.proxy.data = {
40501 data: this.allCountries
40507 initEvents : function()
40510 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40512 this.indicator = this.indicatorEl();
40513 this.flag = this.flagEl();
40514 this.dialCodeHolder = this.dialCodeHolderEl();
40516 this.trigger = this.el.select('div.flag-box',true).first();
40517 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40522 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40523 _this.list.setWidth(lw);
40526 this.list.on('mouseover', this.onViewOver, this);
40527 this.list.on('mousemove', this.onViewMove, this);
40528 this.inputEl().on("keyup", this.onKeyUp, this);
40529 this.inputEl().on("keypress", this.onKeyPress, this);
40531 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40533 this.view = new Roo.View(this.list, this.tpl, {
40534 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40537 this.view.on('click', this.onViewClick, this);
40538 this.setValue(this.defaultDialCode);
40541 onTriggerClick : function(e)
40543 Roo.log('trigger click');
40548 if(this.isExpanded()){
40550 this.hasFocus = false;
40552 this.store.load({});
40553 this.hasFocus = true;
40558 isExpanded : function()
40560 return this.list.isVisible();
40563 collapse : function()
40565 if(!this.isExpanded()){
40569 Roo.get(document).un('mousedown', this.collapseIf, this);
40570 Roo.get(document).un('mousewheel', this.collapseIf, this);
40571 this.fireEvent('collapse', this);
40575 expand : function()
40579 if(this.isExpanded() || !this.hasFocus){
40583 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40584 this.list.setWidth(lw);
40587 this.restrictHeight();
40589 Roo.get(document).on('mousedown', this.collapseIf, this);
40590 Roo.get(document).on('mousewheel', this.collapseIf, this);
40592 this.fireEvent('expand', this);
40595 restrictHeight : function()
40597 this.list.alignTo(this.inputEl(), this.listAlign);
40598 this.list.alignTo(this.inputEl(), this.listAlign);
40601 onViewOver : function(e, t)
40603 if(this.inKeyMode){
40606 var item = this.view.findItemFromChild(t);
40609 var index = this.view.indexOf(item);
40610 this.select(index, false);
40615 onViewClick : function(view, doFocus, el, e)
40617 var index = this.view.getSelectedIndexes()[0];
40619 var r = this.store.getAt(index);
40622 this.onSelect(r, index);
40624 if(doFocus !== false && !this.blockFocus){
40625 this.inputEl().focus();
40629 onViewMove : function(e, t)
40631 this.inKeyMode = false;
40634 select : function(index, scrollIntoView)
40636 this.selectedIndex = index;
40637 this.view.select(index);
40638 if(scrollIntoView !== false){
40639 var el = this.view.getNode(index);
40641 this.list.scrollChildIntoView(el, false);
40646 createList : function()
40648 this.list = Roo.get(document.body).createChild({
40650 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40651 style: 'display:none'
40654 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40657 collapseIf : function(e)
40659 var in_combo = e.within(this.el);
40660 var in_list = e.within(this.list);
40661 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40663 if (in_combo || in_list || is_list) {
40669 onSelect : function(record, index)
40671 if(this.fireEvent('beforeselect', this, record, index) !== false){
40673 this.setFlagClass(record.data.iso2);
40674 this.setDialCode(record.data.dialCode);
40675 this.hasFocus = false;
40677 this.fireEvent('select', this, record, index);
40681 flagEl : function()
40683 var flag = this.el.select('div.flag',true).first();
40690 dialCodeHolderEl : function()
40692 var d = this.el.select('input.dial-code-holder',true).first();
40699 setDialCode : function(v)
40701 this.dialCodeHolder.dom.value = '+'+v;
40704 setFlagClass : function(n)
40706 this.flag.dom.className = 'flag '+n;
40709 getValue : function()
40711 var v = this.inputEl().getValue();
40712 if(this.dialCodeHolder) {
40713 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40718 setValue : function(v)
40720 var d = this.getDialCode(v);
40722 //invalid dial code
40723 if(v.length == 0 || !d || d.length == 0) {
40725 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40726 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40732 this.setFlagClass(this.dialCodeMapping[d].iso2);
40733 this.setDialCode(d);
40734 this.inputEl().dom.value = v.replace('+'+d,'');
40735 this.hiddenEl().dom.value = this.getValue();
40740 getDialCode : function(v)
40744 if (v.length == 0) {
40745 return this.dialCodeHolder.dom.value;
40749 if (v.charAt(0) != "+") {
40752 var numericChars = "";
40753 for (var i = 1; i < v.length; i++) {
40754 var c = v.charAt(i);
40757 if (this.dialCodeMapping[numericChars]) {
40758 dialCode = v.substr(1, i);
40760 if (numericChars.length == 4) {
40770 this.setValue(this.defaultDialCode);
40774 hiddenEl : function()
40776 return this.el.select('input.hidden-tel-input',true).first();
40779 // after setting val
40780 onKeyUp : function(e){
40781 this.setValue(this.getValue());
40784 onKeyPress : function(e){
40785 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40792 * @class Roo.bootstrap.MoneyField
40793 * @extends Roo.bootstrap.ComboBox
40794 * Bootstrap MoneyField class
40797 * Create a new MoneyField.
40798 * @param {Object} config Configuration options
40801 Roo.bootstrap.MoneyField = function(config) {
40803 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40807 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40810 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40812 allowDecimals : true,
40814 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40816 decimalSeparator : ".",
40818 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40820 decimalPrecision : 0,
40822 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40824 allowNegative : true,
40826 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40830 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40832 minValue : Number.NEGATIVE_INFINITY,
40834 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40836 maxValue : Number.MAX_VALUE,
40838 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40840 minText : "The minimum value for this field is {0}",
40842 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40844 maxText : "The maximum value for this field is {0}",
40846 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40847 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40849 nanText : "{0} is not a valid number",
40851 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40855 * @cfg {String} defaults currency of the MoneyField
40856 * value should be in lkey
40858 defaultCurrency : false,
40860 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40862 thousandsDelimiter : false,
40864 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40875 getAutoCreate : function()
40877 var align = this.labelAlign || this.parentLabelAlign();
40889 cls : 'form-control roo-money-amount-input',
40890 autocomplete: 'new-password'
40893 var hiddenInput = {
40897 cls: 'hidden-number-input'
40900 if(this.max_length) {
40901 input.maxlength = this.max_length;
40905 hiddenInput.name = this.name;
40908 if (this.disabled) {
40909 input.disabled = true;
40912 var clg = 12 - this.inputlg;
40913 var cmd = 12 - this.inputmd;
40914 var csm = 12 - this.inputsm;
40915 var cxs = 12 - this.inputxs;
40919 cls : 'row roo-money-field',
40923 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40927 cls: 'roo-select2-container input-group',
40931 cls : 'form-control roo-money-currency-input',
40932 autocomplete: 'new-password',
40934 name : this.currencyName
40938 cls : 'input-group-addon',
40952 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40956 cls: this.hasFeedback ? 'has-feedback' : '',
40967 if (this.fieldLabel.length) {
40970 tooltip: 'This field is required'
40976 cls: 'control-label',
40982 html: this.fieldLabel
40985 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40991 if(this.indicatorpos == 'right') {
40992 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40999 if(align == 'left') {
41007 if(this.labelWidth > 12){
41008 label.style = "width: " + this.labelWidth + 'px';
41010 if(this.labelWidth < 13 && this.labelmd == 0){
41011 this.labelmd = this.labelWidth;
41013 if(this.labellg > 0){
41014 label.cls += ' col-lg-' + this.labellg;
41015 input.cls += ' col-lg-' + (12 - this.labellg);
41017 if(this.labelmd > 0){
41018 label.cls += ' col-md-' + this.labelmd;
41019 container.cls += ' col-md-' + (12 - this.labelmd);
41021 if(this.labelsm > 0){
41022 label.cls += ' col-sm-' + this.labelsm;
41023 container.cls += ' col-sm-' + (12 - this.labelsm);
41025 if(this.labelxs > 0){
41026 label.cls += ' col-xs-' + this.labelxs;
41027 container.cls += ' col-xs-' + (12 - this.labelxs);
41038 var settings = this;
41040 ['xs','sm','md','lg'].map(function(size){
41041 if (settings[size]) {
41042 cfg.cls += ' col-' + size + '-' + settings[size];
41049 initEvents : function()
41051 this.indicator = this.indicatorEl();
41053 this.initCurrencyEvent();
41055 this.initNumberEvent();
41058 initCurrencyEvent : function()
41061 throw "can not find store for combo";
41064 this.store = Roo.factory(this.store, Roo.data);
41065 this.store.parent = this;
41069 this.triggerEl = this.el.select('.input-group-addon', true).first();
41071 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41076 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41077 _this.list.setWidth(lw);
41080 this.list.on('mouseover', this.onViewOver, this);
41081 this.list.on('mousemove', this.onViewMove, this);
41082 this.list.on('scroll', this.onViewScroll, this);
41085 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41088 this.view = new Roo.View(this.list, this.tpl, {
41089 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41092 this.view.on('click', this.onViewClick, this);
41094 this.store.on('beforeload', this.onBeforeLoad, this);
41095 this.store.on('load', this.onLoad, this);
41096 this.store.on('loadexception', this.onLoadException, this);
41098 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41099 "up" : function(e){
41100 this.inKeyMode = true;
41104 "down" : function(e){
41105 if(!this.isExpanded()){
41106 this.onTriggerClick();
41108 this.inKeyMode = true;
41113 "enter" : function(e){
41116 if(this.fireEvent("specialkey", this, e)){
41117 this.onViewClick(false);
41123 "esc" : function(e){
41127 "tab" : function(e){
41130 if(this.fireEvent("specialkey", this, e)){
41131 this.onViewClick(false);
41139 doRelay : function(foo, bar, hname){
41140 if(hname == 'down' || this.scope.isExpanded()){
41141 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41149 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41153 initNumberEvent : function(e)
41155 this.inputEl().on("keydown" , this.fireKey, this);
41156 this.inputEl().on("focus", this.onFocus, this);
41157 this.inputEl().on("blur", this.onBlur, this);
41159 this.inputEl().relayEvent('keyup', this);
41161 if(this.indicator){
41162 this.indicator.addClass('invisible');
41165 this.originalValue = this.getValue();
41167 if(this.validationEvent == 'keyup'){
41168 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41169 this.inputEl().on('keyup', this.filterValidation, this);
41171 else if(this.validationEvent !== false){
41172 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41175 if(this.selectOnFocus){
41176 this.on("focus", this.preFocus, this);
41179 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41180 this.inputEl().on("keypress", this.filterKeys, this);
41182 this.inputEl().relayEvent('keypress', this);
41185 var allowed = "0123456789";
41187 if(this.allowDecimals){
41188 allowed += this.decimalSeparator;
41191 if(this.allowNegative){
41195 if(this.thousandsDelimiter) {
41199 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41201 var keyPress = function(e){
41203 var k = e.getKey();
41205 var c = e.getCharCode();
41208 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41209 allowed.indexOf(String.fromCharCode(c)) === -1
41215 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41219 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41224 this.inputEl().on("keypress", keyPress, this);
41228 onTriggerClick : function(e)
41235 this.loadNext = false;
41237 if(this.isExpanded()){
41242 this.hasFocus = true;
41244 if(this.triggerAction == 'all') {
41245 this.doQuery(this.allQuery, true);
41249 this.doQuery(this.getRawValue());
41252 getCurrency : function()
41254 var v = this.currencyEl().getValue();
41259 restrictHeight : function()
41261 this.list.alignTo(this.currencyEl(), this.listAlign);
41262 this.list.alignTo(this.currencyEl(), this.listAlign);
41265 onViewClick : function(view, doFocus, el, e)
41267 var index = this.view.getSelectedIndexes()[0];
41269 var r = this.store.getAt(index);
41272 this.onSelect(r, index);
41276 onSelect : function(record, index){
41278 if(this.fireEvent('beforeselect', this, record, index) !== false){
41280 this.setFromCurrencyData(index > -1 ? record.data : false);
41284 this.fireEvent('select', this, record, index);
41288 setFromCurrencyData : function(o)
41292 this.lastCurrency = o;
41294 if (this.currencyField) {
41295 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41297 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41300 this.lastSelectionText = currency;
41302 //setting default currency
41303 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41304 this.setCurrency(this.defaultCurrency);
41308 this.setCurrency(currency);
41311 setFromData : function(o)
41315 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41317 this.setFromCurrencyData(c);
41322 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41324 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41327 this.setValue(value);
41331 setCurrency : function(v)
41333 this.currencyValue = v;
41336 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41341 setValue : function(v)
41343 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41349 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41351 this.inputEl().dom.value = (v == '') ? '' :
41352 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41354 if(!this.allowZero && v === '0') {
41355 this.hiddenEl().dom.value = '';
41356 this.inputEl().dom.value = '';
41363 getRawValue : function()
41365 var v = this.inputEl().getValue();
41370 getValue : function()
41372 return this.fixPrecision(this.parseValue(this.getRawValue()));
41375 parseValue : function(value)
41377 if(this.thousandsDelimiter) {
41379 r = new RegExp(",", "g");
41380 value = value.replace(r, "");
41383 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41384 return isNaN(value) ? '' : value;
41388 fixPrecision : function(value)
41390 if(this.thousandsDelimiter) {
41392 r = new RegExp(",", "g");
41393 value = value.replace(r, "");
41396 var nan = isNaN(value);
41398 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41399 return nan ? '' : value;
41401 return parseFloat(value).toFixed(this.decimalPrecision);
41404 decimalPrecisionFcn : function(v)
41406 return Math.floor(v);
41409 validateValue : function(value)
41411 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41415 var num = this.parseValue(value);
41418 this.markInvalid(String.format(this.nanText, value));
41422 if(num < this.minValue){
41423 this.markInvalid(String.format(this.minText, this.minValue));
41427 if(num > this.maxValue){
41428 this.markInvalid(String.format(this.maxText, this.maxValue));
41435 validate : function()
41437 if(this.disabled || this.allowBlank){
41442 var currency = this.getCurrency();
41444 if(this.validateValue(this.getRawValue()) && currency.length){
41449 this.markInvalid();
41453 getName: function()
41458 beforeBlur : function()
41464 var v = this.parseValue(this.getRawValue());
41471 onBlur : function()
41475 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41476 //this.el.removeClass(this.focusClass);
41479 this.hasFocus = false;
41481 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41485 var v = this.getValue();
41487 if(String(v) !== String(this.startValue)){
41488 this.fireEvent('change', this, v, this.startValue);
41491 this.fireEvent("blur", this);
41494 inputEl : function()
41496 return this.el.select('.roo-money-amount-input', true).first();
41499 currencyEl : function()
41501 return this.el.select('.roo-money-currency-input', true).first();
41504 hiddenEl : function()
41506 return this.el.select('input.hidden-number-input',true).first();