2 * set the version of bootstrap based on the stylesheet...
6 Roo.bootstrap.version = (
9 Roo.each(document.styleSheets[0], function(s) {
10 if (s.href.match(/css-bootstrap4/)) {
18 * base class for bootstrap elements.
22 Roo.bootstrap = Roo.bootstrap || {};
24 * @class Roo.bootstrap.Component
25 * @extends Roo.Component
26 * Bootstrap Component base class
27 * @cfg {String} cls css class
28 * @cfg {String} style any extra css
29 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
30 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
31 * @cfg {string} dataId cutomer id
32 * @cfg {string} name Specifies name attribute
33 * @cfg {string} tooltip Text for the tooltip
34 * @cfg {string} container_method method to fetch parents container element (used by NavHeaderbar - getHeaderChildContainer)
35 * @cfg {string|object} visibilityEl (el|parent) What element to use for visibility (@see getVisibilityEl())
38 * Do not use directly - it does not do anything..
39 * @param {Object} config The config object
44 Roo.bootstrap.Component = function(config){
45 Roo.bootstrap.Component.superclass.constructor.call(this, config);
49 * @event childrenrendered
50 * Fires when the children have been rendered..
51 * @param {Roo.bootstrap.Component} this
53 "childrenrendered" : true
62 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
65 allowDomMove : false, // to stop relocations in parent onRender...
75 * Initialize Events for the element
77 initEvents : function() { },
83 can_build_overlaid : true,
85 container_method : false,
92 // returns the parent component..
93 return Roo.ComponentMgr.get(this.parentId)
99 onRender : function(ct, position)
101 // Roo.log("Call onRender: " + this.xtype);
103 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
106 if (this.el.attr('xtype')) {
107 this.el.attr('xtypex', this.el.attr('xtype'));
108 this.el.dom.removeAttribute('xtype');
118 var cfg = Roo.apply({}, this.getAutoCreate());
120 cfg.id = this.id || Roo.id();
122 // fill in the extra attributes
123 if (this.xattr && typeof(this.xattr) =='object') {
124 for (var i in this.xattr) {
125 cfg[i] = this.xattr[i];
130 cfg.dataId = this.dataId;
134 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
137 if (this.style) { // fixme needs to support more complex style data.
138 cfg.style = this.style;
142 cfg.name = this.name;
145 this.el = ct.createChild(cfg, position);
148 this.tooltipEl().attr('tooltip', this.tooltip);
151 if(this.tabIndex !== undefined){
152 this.el.dom.setAttribute('tabIndex', this.tabIndex);
159 * Fetch the element to add children to
160 * @return {Roo.Element} defaults to this.el
162 getChildContainer : function()
167 * Fetch the element to display the tooltip on.
168 * @return {Roo.Element} defaults to this.el
170 tooltipEl : function()
175 addxtype : function(tree,cntr)
179 cn = Roo.factory(tree);
180 //Roo.log(['addxtype', cn]);
182 cn.parentType = this.xtype; //??
183 cn.parentId = this.id;
185 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
186 if (typeof(cn.container_method) == 'string') {
187 cntr = cn.container_method;
191 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
193 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
195 var build_from_html = Roo.XComponent.build_from_html;
197 var is_body = (tree.xtype == 'Body') ;
199 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
201 var self_cntr_el = Roo.get(this[cntr](false));
203 // do not try and build conditional elements
204 if ((has_flexy_each || has_flexy_if || this.can_build_overlaid == false ) && build_from_html) {
208 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
209 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
210 return this.addxtypeChild(tree,cntr, is_body);
213 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
216 return this.addxtypeChild(Roo.apply({}, tree),cntr);
219 Roo.log('skipping render');
225 if (!build_from_html) {
229 // this i think handles overlaying multiple children of the same type
230 // with the sam eelement.. - which might be buggy..
232 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
238 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
242 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
249 addxtypeChild : function (tree, cntr, is_body)
251 Roo.debug && Roo.log('addxtypeChild:' + cntr);
253 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
256 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
257 (typeof(tree['flexy:foreach']) != 'undefined');
261 skip_children = false;
262 // render the element if it's not BODY.
265 // if parent was disabled, then do not try and create the children..
266 if(!this[cntr](true)){
271 cn = Roo.factory(tree);
273 cn.parentType = this.xtype; //??
274 cn.parentId = this.id;
276 var build_from_html = Roo.XComponent.build_from_html;
279 // does the container contain child eleemnts with 'xtype' attributes.
280 // that match this xtype..
281 // note - when we render we create these as well..
282 // so we should check to see if body has xtype set.
283 if (build_from_html && Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
285 var self_cntr_el = Roo.get(this[cntr](false));
286 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
288 //Roo.log(Roo.XComponent.build_from_html);
289 //Roo.log("got echild:");
292 // there is a scenario where some of the child elements are flexy:if (and all of the same type)
293 // and are not displayed -this causes this to use up the wrong element when matching.
294 // at present the only work around for this is to nest flexy:if elements in another element that is always rendered.
297 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
298 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
304 //echild.dom.removeAttribute('xtype');
306 Roo.debug && Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
307 Roo.debug && Roo.log(self_cntr_el);
308 Roo.debug && Roo.log(echild);
309 Roo.debug && Roo.log(cn);
315 // if object has flexy:if - then it may or may not be rendered.
316 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
317 // skip a flexy if element.
318 Roo.debug && Roo.log('skipping render');
319 Roo.debug && Roo.log(tree);
321 Roo.debug && Roo.log('skipping all children');
322 skip_children = true;
327 // actually if flexy:foreach is found, we really want to create
328 // multiple copies here...
330 //Roo.log(this[cntr]());
331 // some elements do not have render methods.. like the layouts...
333 if(this[cntr](true) === false){
338 cn.render && cn.render(this[cntr](true));
341 // then add the element..
348 if (typeof (tree.menu) != 'undefined') {
349 tree.menu.parentType = cn.xtype;
350 tree.menu.triggerEl = cn.el;
351 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
355 if (!tree.items || !tree.items.length) {
357 //Roo.log(["no children", this]);
362 var items = tree.items;
365 //Roo.log(items.length);
367 if (!skip_children) {
368 for(var i =0;i < items.length;i++) {
369 // Roo.log(['add child', items[i]]);
370 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
376 //Roo.log("fire childrenrendered");
378 cn.fireEvent('childrenrendered', this);
384 * Set the element that will be used to show or hide
386 setVisibilityEl : function(el)
388 this.visibilityEl = el;
392 * Get the element that will be used to show or hide
394 getVisibilityEl : function()
396 if (typeof(this.visibilityEl) == 'object') {
397 return this.visibilityEl;
400 if (typeof(this.visibilityEl) == 'string') {
401 return this.visibilityEl == 'parent' ? this.parent().getEl() : this.getEl();
408 * Show a component - removes 'hidden' class
412 if(!this.getVisibilityEl()){
416 this.getVisibilityEl().removeClass(['hidden','d-none']);
418 this.fireEvent('show', this);
423 * Hide a component - adds 'hidden' class
427 if(!this.getVisibilityEl()){
431 this.getVisibilityEl().addClass(['hidden','d-none']);
433 this.fireEvent('hide', this);
446 * @class Roo.bootstrap.Body
447 * @extends Roo.bootstrap.Component
448 * Bootstrap Body class
452 * @param {Object} config The config object
455 Roo.bootstrap.Body = function(config){
457 config = config || {};
459 Roo.bootstrap.Body.superclass.constructor.call(this, config);
460 this.el = Roo.get(config.el ? config.el : document.body );
461 if (this.cls && this.cls.length) {
462 Roo.get(document.body).addClass(this.cls);
466 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
468 is_body : true,// just to make sure it's constructed?
473 onRender : function(ct, position)
475 /* Roo.log("Roo.bootstrap.Body - onRender");
476 if (this.cls && this.cls.length) {
477 Roo.get(document.body).addClass(this.cls);
496 * @class Roo.bootstrap.ButtonGroup
497 * @extends Roo.bootstrap.Component
498 * Bootstrap ButtonGroup class
499 * @cfg {String} size lg | sm | xs (default empty normal)
500 * @cfg {String} align vertical | justified (default none)
501 * @cfg {String} direction up | down (default down)
502 * @cfg {Boolean} toolbar false | true
503 * @cfg {Boolean} btn true | false
508 * @param {Object} config The config object
511 Roo.bootstrap.ButtonGroup = function(config){
512 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
515 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
523 getAutoCreate : function(){
529 cfg.html = this.html || cfg.html;
540 if (['vertical','justified'].indexOf(this.align)!==-1) {
541 cfg.cls = 'btn-group-' + this.align;
543 if (this.align == 'justified') {
544 console.log(this.items);
548 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
549 cfg.cls += ' btn-group-' + this.size;
552 if (this.direction == 'up') {
553 cfg.cls += ' dropup' ;
559 * Add a button to the group (similar to NavItem API.)
561 addItem : function(cfg)
563 var cn = new Roo.bootstrap.Button(cfg);
565 cn.parentId = this.id;
566 cn.onRender(this.el, null);
580 * @class Roo.bootstrap.Button
581 * @extends Roo.bootstrap.Component
582 * Bootstrap Button class
583 * @cfg {String} html The button content
584 * @cfg {String} weight (default | primary | secondary | success | info | warning | danger | link ) default
585 * @cfg {String} badge_weight (default | primary | secondary | success | info | warning | danger | link ) default (same as button)
586 * @cfg {Boolean} outline default false (except for weight=default which emulates old behaveiour with an outline)
587 * @cfg {String} size ( lg | sm | xs)
588 * @cfg {String} tag ( a | input | submit)
589 * @cfg {String} href empty or href
590 * @cfg {Boolean} disabled default false;
591 * @cfg {Boolean} isClose default false;
592 * @cfg {String} glyphicon depricated - use fa
593 * @cfg {String} fa fontawesome icon - eg. 'comment' - without the fa/fas etc..
594 * @cfg {String} badge text for badge
595 * @cfg {String} theme (default|glow)
596 * @cfg {Boolean} inverse dark themed version
597 * @cfg {Boolean} toggle is it a slidy toggle button
598 * @cfg {Boolean} pressed (true|false) default null - if the button ahs active state
599 * @cfg {String} ontext text for on slidy toggle state
600 * @cfg {String} offtext text for off slidy toggle state
601 * @cfg {Boolean} preventDefault default true (stop click event triggering the URL if it's a link.)
602 * @cfg {Boolean} removeClass remove the standard class..
603 * @cfg {String} target target for a href. (_self|_blank|_parent|_top| other)
606 * Create a new button
607 * @param {Object} config The config object
611 Roo.bootstrap.Button = function(config){
612 Roo.bootstrap.Button.superclass.constructor.call(this, config);
613 this.weightClass = ["btn-default btn-outline-secondary",
625 * When a butotn is pressed
626 * @param {Roo.bootstrap.Button} btn
627 * @param {Roo.EventObject} e
632 * After the button has been toggles
633 * @param {Roo.bootstrap.Button} btn
634 * @param {Roo.EventObject} e
635 * @param {boolean} pressed (also available as button.pressed)
641 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
662 preventDefault: true,
670 getAutoCreate : function(){
678 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
679 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
684 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
686 if (this.toggle == true) {
689 cls: 'slider-frame roo-button',
694 'data-off-text':'OFF',
695 cls: 'slider-button',
701 if (['default', 'secondary' , 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
702 cfg.cls += ' '+this.weight;
711 cfg["aria-hidden"] = true;
713 cfg.html = "×";
719 if (this.theme==='default') {
720 cfg.cls = 'btn roo-button';
722 //if (this.parentType != 'Navbar') {
723 this.weight = this.weight.length ? this.weight : 'default';
725 if (['default', 'primary', 'secondary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
727 var outline = this.outline || this.weight == 'default' ? 'outline-' : '';
728 var weight = this.weight == 'default' ? 'secondary' : this.weight;
729 cfg.cls += ' btn-' + outline + weight;
730 if (this.weight == 'default') {
732 cfg.cls += ' btn-' + this.weight;
735 } else if (this.theme==='glow') {
738 cfg.cls = 'btn-glow roo-button';
740 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
742 cfg.cls += ' ' + this.weight;
748 this.cls += ' inverse';
752 if (this.active || this.pressed === true) {
753 cfg.cls += ' active';
757 cfg.disabled = 'disabled';
761 Roo.log('changing to ul' );
763 this.glyphicon = 'caret';
764 if (Roo.bootstrap.version == 4) {
765 this.fa = 'caret-down';
770 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
772 //gsRoo.log(this.parentType);
773 if (this.parentType === 'Navbar' && !this.parent().bar) {
774 Roo.log('changing to li?');
783 href : this.href || '#'
786 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
787 cfg.cls += ' dropdown';
794 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
796 if (this.glyphicon) {
797 cfg.html = ' ' + cfg.html;
802 cls: 'glyphicon glyphicon-' + this.glyphicon
807 cfg.html = ' ' + cfg.html;
812 cls: 'fa fas fa-' + this.fa
822 // cfg.cls='btn roo-button';
826 var value = cfg.html;
831 cls: 'glyphicon glyphicon-' + this.glyphicon,
838 cls: 'fa fas fa-' + this.fa,
843 var bw = this.badge_weight.length ? this.badge_weight :
844 (this.weight.length ? this.weight : 'secondary');
845 bw = bw == 'default' ? 'secondary' : bw;
851 cls: 'badge badge-' + bw,
860 cfg.cls += ' dropdown';
861 cfg.html = typeof(cfg.html) != 'undefined' ?
862 cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
865 if (cfg.tag !== 'a' && this.href !== '') {
866 throw "Tag must be a to set href.";
867 } else if (this.href.length > 0) {
868 cfg.href = this.href;
871 if(this.removeClass){
876 cfg.target = this.target;
881 initEvents: function() {
882 // Roo.log('init events?');
883 // Roo.log(this.el.dom);
886 if (typeof (this.menu) != 'undefined') {
887 this.menu.parentType = this.xtype;
888 this.menu.triggerEl = this.el;
889 this.addxtype(Roo.apply({}, this.menu));
893 if (this.el.hasClass('roo-button')) {
894 this.el.on('click', this.onClick, this);
896 this.el.select('.roo-button').on('click', this.onClick, this);
899 if(this.removeClass){
900 this.el.on('click', this.onClick, this);
903 this.el.enableDisplayMode();
906 onClick : function(e)
912 Roo.log('button on click ');
913 if(this.preventDefault){
917 if (this.pressed === true || this.pressed === false) {
918 this.toggleActive(e);
922 this.fireEvent('click', this, e);
926 * Enables this button
930 this.disabled = false;
931 this.el.removeClass('disabled');
935 * Disable this button
939 this.disabled = true;
940 this.el.addClass('disabled');
943 * sets the active state on/off,
944 * @param {Boolean} state (optional) Force a particular state
946 setActive : function(v) {
948 this.el[v ? 'addClass' : 'removeClass']('active');
952 * toggles the current active state
954 toggleActive : function(e)
956 this.setActive(!this.pressed);
957 this.fireEvent('toggle', this, e, !this.pressed);
960 * get the current active state
961 * @return {boolean} true if it's active
963 isActive : function()
965 return this.el.hasClass('active');
968 * set the text of the first selected button
970 setText : function(str)
972 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
975 * get the text of the first selected button
979 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
982 setWeight : function(str)
984 this.el.removeClass(this.weightClass);
986 var outline = this.outline ? 'outline-' : '';
987 if (str == 'default') {
988 this.el.addClass('btn-default btn-outline-secondary');
991 this.el.addClass('btn-' + outline + str);
1005 * @class Roo.bootstrap.Column
1006 * @extends Roo.bootstrap.Component
1007 * Bootstrap Column class
1008 * @cfg {Number} xs colspan out of 12 for mobile-sized screens or 0 for hidden
1009 * @cfg {Number} sm colspan out of 12 for tablet-sized screens or 0 for hidden
1010 * @cfg {Number} md colspan out of 12 for computer-sized screens or 0 for hidden
1011 * @cfg {Number} lg colspan out of 12 for large computer-sized screens or 0 for hidden
1012 * @cfg {Number} xsoff colspan offset out of 12 for mobile-sized screens or 0 for hidden
1013 * @cfg {Number} smoff colspan offset out of 12 for tablet-sized screens or 0 for hidden
1014 * @cfg {Number} mdoff colspan offset out of 12 for computer-sized screens or 0 for hidden
1015 * @cfg {Number} lgoff colspan offset out of 12 for large computer-sized screens or 0 for hidden
1018 * @cfg {Boolean} hidden (true|false) hide the element
1019 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1020 * @cfg {String} fa (ban|check|...) font awesome icon
1021 * @cfg {Number} fasize (1|2|....) font awsome size
1023 * @cfg {String} icon (info-sign|check|...) glyphicon name
1025 * @cfg {String} html content of column.
1028 * Create a new Column
1029 * @param {Object} config The config object
1032 Roo.bootstrap.Column = function(config){
1033 Roo.bootstrap.Column.superclass.constructor.call(this, config);
1036 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
1054 getAutoCreate : function(){
1055 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
1063 ['xs','sm','md','lg'].map(function(size){
1064 //Roo.log( size + ':' + settings[size]);
1066 if (settings[size+'off'] !== false) {
1067 cfg.cls += ' col-' + size + '-offset-' + settings[size+'off'] ;
1070 if (settings[size] === false) {
1074 if (!settings[size]) { // 0 = hidden
1075 cfg.cls += ' hidden-' + size;
1078 cfg.cls += ' col-' + size + '-' + settings[size];
1083 cfg.cls += ' hidden';
1086 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1087 cfg.cls +=' alert alert-' + this.alert;
1091 if (this.html.length) {
1092 cfg.html = this.html;
1096 if (this.fasize > 1) {
1097 fasize = ' fa-' + this.fasize + 'x';
1099 cfg.html = '<i class="fa fa-'+this.fa + fasize + '"></i>' + (cfg.html || '');
1104 cfg.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + (cfg.html || '');
1123 * @class Roo.bootstrap.Container
1124 * @extends Roo.bootstrap.Component
1125 * Bootstrap Container class
1126 * @cfg {Boolean} jumbotron is it a jumbotron element
1127 * @cfg {String} html content of element
1128 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
1129 * @cfg {String} panel (default|primary|success|info|warning|danger) render as panel - type - primary/success.....
1130 * @cfg {String} header content of header (for panel)
1131 * @cfg {String} footer content of footer (for panel)
1132 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
1133 * @cfg {String} tag (header|aside|section) type of HTML tag.
1134 * @cfg {String} alert (success|info|warning|danger) type alert (changes background / border...)
1135 * @cfg {String} fa font awesome icon
1136 * @cfg {String} icon (info-sign|check|...) glyphicon name
1137 * @cfg {Boolean} hidden (true|false) hide the element
1138 * @cfg {Boolean} expandable (true|false) default false
1139 * @cfg {Boolean} expanded (true|false) default true
1140 * @cfg {String} rheader contet on the right of header
1141 * @cfg {Boolean} clickable (true|false) default false
1145 * Create a new Container
1146 * @param {Object} config The config object
1149 Roo.bootstrap.Container = function(config){
1150 Roo.bootstrap.Container.superclass.constructor.call(this, config);
1156 * After the panel has been expand
1158 * @param {Roo.bootstrap.Container} this
1163 * After the panel has been collapsed
1165 * @param {Roo.bootstrap.Container} this
1170 * When a element is chick
1171 * @param {Roo.bootstrap.Container} this
1172 * @param {Roo.EventObject} e
1178 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
1196 getChildContainer : function() {
1202 if (this.panel.length) {
1203 return this.el.select('.panel-body',true).first();
1210 getAutoCreate : function(){
1213 tag : this.tag || 'div',
1217 if (this.jumbotron) {
1218 cfg.cls = 'jumbotron';
1223 // - this is applied by the parent..
1225 // cfg.cls = this.cls + '';
1228 if (this.sticky.length) {
1230 var bd = Roo.get(document.body);
1231 if (!bd.hasClass('bootstrap-sticky')) {
1232 bd.addClass('bootstrap-sticky');
1233 Roo.select('html',true).setStyle('height', '100%');
1236 cfg.cls += 'bootstrap-sticky-' + this.sticky;
1240 if (this.well.length) {
1241 switch (this.well) {
1244 cfg.cls +=' well well-' +this.well;
1253 cfg.cls += ' hidden';
1257 if (this.alert && ["success","info","warning", "danger"].indexOf(this.alert) > -1) {
1258 cfg.cls +=' alert alert-' + this.alert;
1263 if (this.panel.length) {
1264 cfg.cls += ' panel panel-' + this.panel;
1266 if (this.header.length) {
1270 if(this.expandable){
1272 cfg.cls = cfg.cls + ' expandable';
1276 cls: (this.expanded ? 'fa fa-minus' : 'fa fa-plus')
1284 cls : 'panel-title',
1285 html : (this.expandable ? ' ' : '') + this.header
1289 cls: 'panel-header-right',
1295 cls : 'panel-heading',
1296 style : this.expandable ? 'cursor: pointer' : '',
1304 cls : 'panel-body' + (this.expanded ? '' : ' hide'),
1309 if (this.footer.length) {
1311 cls : 'panel-footer',
1320 body.html = this.html || cfg.html;
1321 // prefix with the icons..
1323 body.html = '<i class="fa fa-'+this.fa + '"></i>' + body.html ;
1326 body.html = '<i class="glyphicon glyphicon-'+this.icon + '"></i>' + body.html ;
1331 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
1332 cfg.cls = 'container';
1338 initEvents: function()
1340 if(this.expandable){
1341 var headerEl = this.headerEl();
1344 headerEl.on('click', this.onToggleClick, this);
1349 this.el.on('click', this.onClick, this);
1354 onToggleClick : function()
1356 var headerEl = this.headerEl();
1372 if(this.fireEvent('expand', this)) {
1374 this.expanded = true;
1376 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).show();
1378 this.el.select('.panel-body',true).first().removeClass('hide');
1380 var toggleEl = this.toggleEl();
1386 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-minus']);
1391 collapse : function()
1393 if(this.fireEvent('collapse', this)) {
1395 this.expanded = false;
1397 //this.el.select('.panel-body',true).first().setVisibilityMode(Roo.Element.DISPLAY).hide();
1398 this.el.select('.panel-body',true).first().addClass('hide');
1400 var toggleEl = this.toggleEl();
1406 toggleEl.removeClass(['fa-minus', 'fa-plus']).addClass(['fa-plus']);
1410 toggleEl : function()
1412 if(!this.el || !this.panel.length || !this.header.length || !this.expandable){
1416 return this.el.select('.panel-heading .fa',true).first();
1419 headerEl : function()
1421 if(!this.el || !this.panel.length || !this.header.length){
1425 return this.el.select('.panel-heading',true).first()
1430 if(!this.el || !this.panel.length){
1434 return this.el.select('.panel-body',true).first()
1437 titleEl : function()
1439 if(!this.el || !this.panel.length || !this.header.length){
1443 return this.el.select('.panel-title',true).first();
1446 setTitle : function(v)
1448 var titleEl = this.titleEl();
1454 titleEl.dom.innerHTML = v;
1457 getTitle : function()
1460 var titleEl = this.titleEl();
1466 return titleEl.dom.innerHTML;
1469 setRightTitle : function(v)
1471 var t = this.el.select('.panel-header-right',true).first();
1477 t.dom.innerHTML = v;
1480 onClick : function(e)
1484 this.fireEvent('click', this, e);
1497 * @class Roo.bootstrap.Img
1498 * @extends Roo.bootstrap.Component
1499 * Bootstrap Img class
1500 * @cfg {Boolean} imgResponsive false | true
1501 * @cfg {String} border rounded | circle | thumbnail
1502 * @cfg {String} src image source
1503 * @cfg {String} alt image alternative text
1504 * @cfg {String} href a tag href
1505 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1506 * @cfg {String} xsUrl xs image source
1507 * @cfg {String} smUrl sm image source
1508 * @cfg {String} mdUrl md image source
1509 * @cfg {String} lgUrl lg image source
1512 * Create a new Input
1513 * @param {Object} config The config object
1516 Roo.bootstrap.Img = function(config){
1517 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1523 * The img click event for the img.
1524 * @param {Roo.EventObject} e
1530 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1532 imgResponsive: true,
1542 getAutoCreate : function()
1544 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1545 return this.createSingleImg();
1550 cls: 'roo-image-responsive-group',
1555 Roo.each(['xs', 'sm', 'md', 'lg'], function(size){
1557 if(!_this[size + 'Url']){
1563 cls: (_this.imgResponsive) ? 'img-responsive' : '',
1564 html: _this.html || cfg.html,
1565 src: _this[size + 'Url']
1568 img.cls += ' roo-image-responsive-' + size;
1570 var s = ['xs', 'sm', 'md', 'lg'];
1572 s.splice(s.indexOf(size), 1);
1574 Roo.each(s, function(ss){
1575 img.cls += ' hidden-' + ss;
1578 if (['rounded','circle','thumbnail'].indexOf(_this.border)>-1) {
1579 cfg.cls += ' img-' + _this.border;
1583 cfg.alt = _this.alt;
1596 a.target = _this.target;
1600 cfg.cn.push((_this.href) ? a : img);
1607 createSingleImg : function()
1611 cls: (this.imgResponsive) ? 'img-responsive' : '',
1613 src : 'about:blank' // just incase src get's set to undefined?!?
1616 cfg.html = this.html || cfg.html;
1618 cfg.src = this.src || cfg.src;
1620 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1621 cfg.cls += ' img-' + this.border;
1638 a.target = this.target;
1643 return (this.href) ? a : cfg;
1646 initEvents: function()
1649 this.el.on('click', this.onClick, this);
1654 onClick : function(e)
1656 Roo.log('img onclick');
1657 this.fireEvent('click', this, e);
1660 * Sets the url of the image - used to update it
1661 * @param {String} url the url of the image
1664 setSrc : function(url)
1668 if(this.src || (!this.xsUrl && !this.smUrl && !this.mdUrl && !this.lgUrl)){
1669 this.el.dom.src = url;
1673 this.el.select('img', true).first().dom.src = url;
1689 * @class Roo.bootstrap.Link
1690 * @extends Roo.bootstrap.Component
1691 * Bootstrap Link Class
1692 * @cfg {String} alt image alternative text
1693 * @cfg {String} href a tag href
1694 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1695 * @cfg {String} html the content of the link.
1696 * @cfg {String} anchor name for the anchor link
1697 * @cfg {String} fa - favicon
1699 * @cfg {Boolean} preventDefault (true | false) default false
1703 * Create a new Input
1704 * @param {Object} config The config object
1707 Roo.bootstrap.Link = function(config){
1708 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1714 * The img click event for the img.
1715 * @param {Roo.EventObject} e
1721 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1725 preventDefault: false,
1731 getAutoCreate : function()
1733 var html = this.html || '';
1735 if (this.fa !== false) {
1736 html = '<i class="fa fa-' + this.fa + '"></i>';
1741 // anchor's do not require html/href...
1742 if (this.anchor === false) {
1744 cfg.href = this.href || '#';
1746 cfg.name = this.anchor;
1747 if (this.html !== false || this.fa !== false) {
1750 if (this.href !== false) {
1751 cfg.href = this.href;
1755 if(this.alt !== false){
1760 if(this.target !== false) {
1761 cfg.target = this.target;
1767 initEvents: function() {
1769 if(!this.href || this.preventDefault){
1770 this.el.on('click', this.onClick, this);
1774 onClick : function(e)
1776 if(this.preventDefault){
1779 //Roo.log('img onclick');
1780 this.fireEvent('click', this, e);
1793 * @class Roo.bootstrap.Header
1794 * @extends Roo.bootstrap.Component
1795 * Bootstrap Header class
1796 * @cfg {String} html content of header
1797 * @cfg {Number} level (1|2|3|4|5|6) default 1
1800 * Create a new Header
1801 * @param {Object} config The config object
1805 Roo.bootstrap.Header = function(config){
1806 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1809 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1817 getAutoCreate : function(){
1822 tag: 'h' + (1 *this.level),
1823 html: this.html || ''
1835 * Ext JS Library 1.1.1
1836 * Copyright(c) 2006-2007, Ext JS, LLC.
1838 * Originally Released Under LGPL - original licence link has changed is not relivant.
1841 * <script type="text/javascript">
1845 * @class Roo.bootstrap.MenuMgr
1846 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1849 Roo.bootstrap.MenuMgr = function(){
1850 var menus, active, groups = {}, attached = false, lastShow = new Date();
1852 // private - called when first menu is created
1855 active = new Roo.util.MixedCollection();
1856 Roo.get(document).addKeyListener(27, function(){
1857 if(active.length > 0){
1865 if(active && active.length > 0){
1866 var c = active.clone();
1876 if(active.length < 1){
1877 Roo.get(document).un("mouseup", onMouseDown);
1885 var last = active.last();
1886 lastShow = new Date();
1889 Roo.get(document).on("mouseup", onMouseDown);
1894 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1895 m.parentMenu.activeChild = m;
1896 }else if(last && last.isVisible()){
1897 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1902 function onBeforeHide(m){
1904 m.activeChild.hide();
1906 if(m.autoHideTimer){
1907 clearTimeout(m.autoHideTimer);
1908 delete m.autoHideTimer;
1913 function onBeforeShow(m){
1914 var pm = m.parentMenu;
1915 if(!pm && !m.allowOtherMenus){
1917 }else if(pm && pm.activeChild && active != m){
1918 pm.activeChild.hide();
1922 // private this should really trigger on mouseup..
1923 function onMouseDown(e){
1924 Roo.log("on Mouse Up");
1926 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".dropdown-menu") && !e.getTarget('.user-menu')){
1927 Roo.log("MenuManager hideAll");
1936 function onBeforeCheck(mi, state){
1938 var g = groups[mi.group];
1939 for(var i = 0, l = g.length; i < l; i++){
1941 g[i].setChecked(false);
1950 * Hides all menus that are currently visible
1952 hideAll : function(){
1957 register : function(menu){
1961 menus[menu.id] = menu;
1962 menu.on("beforehide", onBeforeHide);
1963 menu.on("hide", onHide);
1964 menu.on("beforeshow", onBeforeShow);
1965 menu.on("show", onShow);
1967 if(g && menu.events["checkchange"]){
1971 groups[g].push(menu);
1972 menu.on("checkchange", onCheck);
1977 * Returns a {@link Roo.menu.Menu} object
1978 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1979 * be used to generate and return a new Menu instance.
1981 get : function(menu){
1982 if(typeof menu == "string"){ // menu id
1984 }else if(menu.events){ // menu instance
1987 /*else if(typeof menu.length == 'number'){ // array of menu items?
1988 return new Roo.bootstrap.Menu({items:menu});
1989 }else{ // otherwise, must be a config
1990 return new Roo.bootstrap.Menu(menu);
1997 unregister : function(menu){
1998 delete menus[menu.id];
1999 menu.un("beforehide", onBeforeHide);
2000 menu.un("hide", onHide);
2001 menu.un("beforeshow", onBeforeShow);
2002 menu.un("show", onShow);
2004 if(g && menu.events["checkchange"]){
2005 groups[g].remove(menu);
2006 menu.un("checkchange", onCheck);
2011 registerCheckable : function(menuItem){
2012 var g = menuItem.group;
2017 groups[g].push(menuItem);
2018 menuItem.on("beforecheckchange", onBeforeCheck);
2023 unregisterCheckable : function(menuItem){
2024 var g = menuItem.group;
2026 groups[g].remove(menuItem);
2027 menuItem.un("beforecheckchange", onBeforeCheck);
2039 * @class Roo.bootstrap.Menu
2040 * @extends Roo.bootstrap.Component
2041 * Bootstrap Menu class - container for MenuItems
2042 * @cfg {String} type (dropdown|treeview|submenu) type of menu
2043 * @cfg {bool} hidden if the menu should be hidden when rendered.
2044 * @cfg {bool} stopEvent (true|false) Stop event after trigger press (default true)
2045 * @cfg {bool} isLink (true|false) the menu has link disable auto expand and collaspe (default false)
2049 * @param {Object} config The config object
2053 Roo.bootstrap.Menu = function(config){
2054 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
2055 if (this.registerMenu && this.type != 'treeview') {
2056 Roo.bootstrap.MenuMgr.register(this);
2063 * Fires before this menu is displayed
2064 * @param {Roo.menu.Menu} this
2069 * Fires before this menu is hidden
2070 * @param {Roo.menu.Menu} this
2075 * Fires after this menu is displayed
2076 * @param {Roo.menu.Menu} this
2081 * Fires after this menu is hidden
2082 * @param {Roo.menu.Menu} this
2087 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
2088 * @param {Roo.menu.Menu} this
2089 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2090 * @param {Roo.EventObject} e
2095 * Fires when the mouse is hovering over this menu
2096 * @param {Roo.menu.Menu} this
2097 * @param {Roo.EventObject} e
2098 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2103 * Fires when the mouse exits this menu
2104 * @param {Roo.menu.Menu} this
2105 * @param {Roo.EventObject} e
2106 * @param {Roo.menu.Item} menuItem The menu item that was clicked
2111 * Fires when a menu item contained in this menu is clicked
2112 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
2113 * @param {Roo.EventObject} e
2117 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
2120 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
2124 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
2127 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
2129 registerMenu : true,
2131 menuItems :false, // stores the menu items..
2141 getChildContainer : function() {
2145 getAutoCreate : function(){
2147 //if (['right'].indexOf(this.align)!==-1) {
2148 // cfg.cn[1].cls += ' pull-right'
2154 cls : 'dropdown-menu' ,
2155 style : 'z-index:1000'
2159 if (this.type === 'submenu') {
2160 cfg.cls = 'submenu active';
2162 if (this.type === 'treeview') {
2163 cfg.cls = 'treeview-menu';
2168 initEvents : function() {
2170 // Roo.log("ADD event");
2171 // Roo.log(this.triggerEl.dom);
2173 this.triggerEl.on('click', this.onTriggerClick, this);
2175 this.triggerEl.on(Roo.isTouch ? 'touchstart' : 'mouseup', this.onTriggerPress, this);
2178 if (this.triggerEl.hasClass('nav-item')) {
2179 // dropdown toggle on the 'a' in BS4?
2180 this.triggerEl.select('.nav-link',true).first().addClass('dropdown-toggle');
2182 this.triggerEl.addClass('dropdown-toggle');
2185 this.el.on('touchstart' , this.onTouch, this);
2187 this.el.on('click' , this.onClick, this);
2189 this.el.on("mouseover", this.onMouseOver, this);
2190 this.el.on("mouseout", this.onMouseOut, this);
2194 findTargetItem : function(e)
2196 var t = e.getTarget(".dropdown-menu-item", this.el, true);
2200 //Roo.log(t); Roo.log(t.id);
2202 //Roo.log(this.menuitems);
2203 return this.menuitems.get(t.id);
2205 //return this.items.get(t.menuItemId);
2211 onTouch : function(e)
2213 Roo.log("menu.onTouch");
2214 //e.stopEvent(); this make the user popdown broken
2218 onClick : function(e)
2220 Roo.log("menu.onClick");
2222 var t = this.findTargetItem(e);
2223 if(!t || t.isContainer){
2228 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
2229 if(t == this.activeItem && t.shouldDeactivate(e)){
2230 this.activeItem.deactivate();
2231 delete this.activeItem;
2235 this.setActiveItem(t, true);
2243 Roo.log('pass click event');
2247 this.fireEvent("click", this, t, e);
2251 if(!t.href.length || t.href == '#'){
2252 (function() { _this.hide(); }).defer(100);
2257 onMouseOver : function(e){
2258 var t = this.findTargetItem(e);
2261 // if(t.canActivate && !t.disabled){
2262 // this.setActiveItem(t, true);
2266 this.fireEvent("mouseover", this, e, t);
2268 isVisible : function(){
2269 return !this.hidden;
2271 onMouseOut : function(e){
2272 var t = this.findTargetItem(e);
2275 // if(t == this.activeItem && t.shouldDeactivate(e)){
2276 // this.activeItem.deactivate();
2277 // delete this.activeItem;
2280 this.fireEvent("mouseout", this, e, t);
2285 * Displays this menu relative to another element
2286 * @param {String/HTMLElement/Roo.Element} element The element to align to
2287 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
2288 * the element (defaults to this.defaultAlign)
2289 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2291 show : function(el, pos, parentMenu){
2292 this.parentMenu = parentMenu;
2296 this.fireEvent("beforeshow", this);
2297 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2300 * Displays this menu at a specific xy position
2301 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2302 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2304 showAt : function(xy, parentMenu, /* private: */_e){
2305 this.parentMenu = parentMenu;
2310 this.fireEvent("beforeshow", this);
2311 //xy = this.el.adjustForConstraints(xy);
2315 this.hideMenuItems();
2316 this.hidden = false;
2317 this.triggerEl.addClass('open');
2318 this.el.addClass('show');
2320 // reassign x when hitting right
2321 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2322 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2325 // reassign y when hitting bottom
2326 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2327 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2330 // but the list may align on trigger left or trigger top... should it be a properity?
2332 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2337 this.fireEvent("show", this);
2343 this.doFocus.defer(50, this);
2347 doFocus : function(){
2349 this.focusEl.focus();
2354 * Hides this menu and optionally all parent menus
2355 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2357 hide : function(deep)
2360 this.hideMenuItems();
2361 if(this.el && this.isVisible()){
2362 this.fireEvent("beforehide", this);
2363 if(this.activeItem){
2364 this.activeItem.deactivate();
2365 this.activeItem = null;
2367 this.triggerEl.removeClass('open');;
2368 this.el.removeClass('show');
2370 this.fireEvent("hide", this);
2372 if(deep === true && this.parentMenu){
2373 this.parentMenu.hide(true);
2377 onTriggerClick : function(e)
2379 Roo.log('trigger click');
2381 var target = e.getTarget();
2383 Roo.log(target.nodeName.toLowerCase());
2385 if(target.nodeName.toLowerCase() === 'i'){
2391 onTriggerPress : function(e)
2393 Roo.log('trigger press');
2394 //Roo.log(e.getTarget());
2395 // Roo.log(this.triggerEl.dom);
2397 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2398 var pel = Roo.get(e.getTarget());
2399 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2400 Roo.log('is treeview or dropdown?');
2404 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2408 if (this.isVisible()) {
2413 this.show(this.triggerEl, '?', false);
2416 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2423 hideMenuItems : function()
2425 Roo.log("hide Menu Items");
2429 //$(backdrop).remove()
2430 this.el.select('.open',true).each(function(aa) {
2432 aa.removeClass('open');
2433 //var parent = getParent($(this))
2434 //var relatedTarget = { relatedTarget: this }
2436 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
2437 //if (e.isDefaultPrevented()) return
2438 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
2441 addxtypeChild : function (tree, cntr) {
2442 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2444 this.menuitems.add(comp);
2456 this.getEl().dom.innerHTML = '';
2457 this.menuitems.clear();
2471 * @class Roo.bootstrap.MenuItem
2472 * @extends Roo.bootstrap.Component
2473 * Bootstrap MenuItem class
2474 * @cfg {String} html the menu label
2475 * @cfg {String} href the link
2476 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2477 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2478 * @cfg {Boolean} active used on sidebars to highlight active itesm
2479 * @cfg {String} fa favicon to show on left of menu item.
2480 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2484 * Create a new MenuItem
2485 * @param {Object} config The config object
2489 Roo.bootstrap.MenuItem = function(config){
2490 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2495 * The raw click event for the entire grid.
2496 * @param {Roo.bootstrap.MenuItem} this
2497 * @param {Roo.EventObject} e
2503 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2507 preventDefault: false,
2508 isContainer : false,
2512 getAutoCreate : function(){
2514 if(this.isContainer){
2517 cls: 'dropdown-menu-item '
2527 cls : 'dropdown-item',
2532 if (this.fa !== false) {
2535 cls : 'fa fa-' + this.fa
2544 cls: 'dropdown-menu-item',
2547 if (this.parent().type == 'treeview') {
2548 cfg.cls = 'treeview-menu';
2551 cfg.cls += ' active';
2556 anc.href = this.href || cfg.cn[0].href ;
2557 ctag.html = this.html || cfg.cn[0].html ;
2561 initEvents: function()
2563 if (this.parent().type == 'treeview') {
2564 this.el.select('a').on('click', this.onClick, this);
2568 this.menu.parentType = this.xtype;
2569 this.menu.triggerEl = this.el;
2570 this.menu = this.addxtype(Roo.apply({}, this.menu));
2574 onClick : function(e)
2576 Roo.log('item on click ');
2578 if(this.preventDefault){
2581 //this.parent().hideMenuItems();
2583 this.fireEvent('click', this, e);
2602 * @class Roo.bootstrap.MenuSeparator
2603 * @extends Roo.bootstrap.Component
2604 * Bootstrap MenuSeparator class
2607 * Create a new MenuItem
2608 * @param {Object} config The config object
2612 Roo.bootstrap.MenuSeparator = function(config){
2613 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2616 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2618 getAutoCreate : function(){
2637 * @class Roo.bootstrap.Modal
2638 * @extends Roo.bootstrap.Component
2639 * Bootstrap Modal class
2640 * @cfg {String} title Title of dialog
2641 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2642 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2643 * @cfg {Boolean} specificTitle default false
2644 * @cfg {Array} buttons Array of buttons or standard button set..
2645 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2646 * @cfg {Boolean} animate default true
2647 * @cfg {Boolean} allow_close default true
2648 * @cfg {Boolean} fitwindow default false
2649 * @cfg {String} size (sm|lg) default empty
2650 * @cfg {Number} max_width set the max width of modal
2654 * Create a new Modal Dialog
2655 * @param {Object} config The config object
2658 Roo.bootstrap.Modal = function(config){
2659 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2664 * The raw btnclick event for the button
2665 * @param {Roo.EventObject} e
2670 * Fire when dialog resize
2671 * @param {Roo.bootstrap.Modal} this
2672 * @param {Roo.EventObject} e
2676 this.buttons = this.buttons || [];
2679 this.tmpl = Roo.factory(this.tmpl);
2684 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2686 title : 'test dialog',
2696 specificTitle: false,
2698 buttonPosition: 'right',
2721 onRender : function(ct, position)
2723 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2726 var cfg = Roo.apply({}, this.getAutoCreate());
2729 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2731 //if (!cfg.name.length) {
2735 cfg.cls += ' ' + this.cls;
2738 cfg.style = this.style;
2740 this.el = Roo.get(document.body).createChild(cfg, position);
2742 //var type = this.el.dom.type;
2745 if(this.tabIndex !== undefined){
2746 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2749 this.dialogEl = this.el.select('.modal-dialog',true).first();
2750 this.bodyEl = this.el.select('.modal-body',true).first();
2751 this.closeEl = this.el.select('.modal-header .close', true).first();
2752 this.headerEl = this.el.select('.modal-header',true).first();
2753 this.titleEl = this.el.select('.modal-title',true).first();
2754 this.footerEl = this.el.select('.modal-footer',true).first();
2756 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2758 //this.el.addClass("x-dlg-modal");
2760 if (this.buttons.length) {
2761 Roo.each(this.buttons, function(bb) {
2762 var b = Roo.apply({}, bb);
2763 b.xns = b.xns || Roo.bootstrap;
2764 b.xtype = b.xtype || 'Button';
2765 if (typeof(b.listeners) == 'undefined') {
2766 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2769 var btn = Roo.factory(b);
2771 btn.render(this.getButtonContainer());
2775 // render the children.
2778 if(typeof(this.items) != 'undefined'){
2779 var items = this.items;
2782 for(var i =0;i < items.length;i++) {
2783 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2787 this.items = nitems;
2789 // where are these used - they used to be body/close/footer
2793 //this.el.addClass([this.fieldClass, this.cls]);
2797 getAutoCreate : function()
2801 html : this.html || ''
2806 cls : 'modal-title',
2810 if(this.specificTitle){
2816 if (this.allow_close && Roo.bootstrap.version == 3) {
2826 if (this.allow_close && Roo.bootstrap.version == 4) {
2836 if(this.size.length){
2837 size = 'modal-' + this.size;
2840 var footer = Roo.bootstrap.version == 3 ?
2842 cls : 'modal-footer',
2846 cls: 'btn-' + this.buttonPosition
2851 { // BS4 uses mr-auto on left buttons....
2852 cls : 'modal-footer'
2863 cls: "modal-dialog " + size,
2866 cls : "modal-content",
2869 cls : 'modal-header',
2884 modal.cls += ' fade';
2890 getChildContainer : function() {
2895 getButtonContainer : function() {
2897 return Roo.bootstrap.version == 4 ?
2898 this.el.select('.modal-footer',true).first()
2899 : this.el.select('.modal-footer div',true).first();
2902 initEvents : function()
2904 if (this.allow_close) {
2905 this.closeEl.on('click', this.hide, this);
2907 Roo.EventManager.onWindowResize(this.resize, this, true);
2915 this.maskEl.setSize(
2916 Roo.lib.Dom.getViewWidth(true),
2917 Roo.lib.Dom.getViewHeight(true)
2920 if (this.fitwindow) {
2924 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2925 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
2930 if(this.max_width !== 0) {
2932 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2935 this.setSize(w, this.height);
2939 if(this.max_height) {
2940 this.setSize(w,Math.min(
2942 Roo.lib.Dom.getViewportHeight(true) - 60
2948 if(!this.fit_content) {
2949 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2953 this.setSize(w, Math.min(
2955 this.headerEl.getHeight() +
2956 this.footerEl.getHeight() +
2957 this.getChildHeight(this.bodyEl.dom.childNodes),
2958 Roo.lib.Dom.getViewportHeight(true) - 60)
2964 setSize : function(w,h)
2975 if (!this.rendered) {
2979 //this.el.setStyle('display', 'block');
2980 this.el.removeClass('hideing');
2981 this.el.dom.style.display='block';
2983 Roo.get(document.body).addClass('modal-open');
2985 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2988 this.el.addClass('show');
2989 this.el.addClass('in');
2992 this.el.addClass('show');
2993 this.el.addClass('in');
2996 // not sure how we can show data in here..
2998 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3001 Roo.get(document.body).addClass("x-body-masked");
3003 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3004 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3005 this.maskEl.dom.style.display = 'block';
3006 this.maskEl.addClass('show');
3011 this.fireEvent('show', this);
3013 // set zindex here - otherwise it appears to be ignored...
3014 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3017 this.items.forEach( function(e) {
3018 e.layout ? e.layout() : false;
3026 if(this.fireEvent("beforehide", this) !== false){
3028 this.maskEl.removeClass('show');
3030 this.maskEl.dom.style.display = '';
3031 Roo.get(document.body).removeClass("x-body-masked");
3032 this.el.removeClass('in');
3033 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3035 if(this.animate){ // why
3036 this.el.addClass('hideing');
3037 this.el.removeClass('show');
3039 if (!this.el.hasClass('hideing')) {
3040 return; // it's been shown again...
3043 this.el.dom.style.display='';
3045 Roo.get(document.body).removeClass('modal-open');
3046 this.el.removeClass('hideing');
3050 this.el.removeClass('show');
3051 this.el.dom.style.display='';
3052 Roo.get(document.body).removeClass('modal-open');
3055 this.fireEvent('hide', this);
3058 isVisible : function()
3061 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3065 addButton : function(str, cb)
3069 var b = Roo.apply({}, { html : str } );
3070 b.xns = b.xns || Roo.bootstrap;
3071 b.xtype = b.xtype || 'Button';
3072 if (typeof(b.listeners) == 'undefined') {
3073 b.listeners = { click : cb.createDelegate(this) };
3076 var btn = Roo.factory(b);
3078 btn.render(this.getButtonContainer());
3084 setDefaultButton : function(btn)
3086 //this.el.select('.modal-footer').()
3089 resizeTo: function(w,h)
3091 this.dialogEl.setWidth(w);
3093 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
3095 this.bodyEl.setHeight(h - diff);
3097 this.fireEvent('resize', this);
3100 setContentSize : function(w, h)
3104 onButtonClick: function(btn,e)
3107 this.fireEvent('btnclick', btn.name, e);
3110 * Set the title of the Dialog
3111 * @param {String} str new Title
3113 setTitle: function(str) {
3114 this.titleEl.dom.innerHTML = str;
3117 * Set the body of the Dialog
3118 * @param {String} str new Title
3120 setBody: function(str) {
3121 this.bodyEl.dom.innerHTML = str;
3124 * Set the body of the Dialog using the template
3125 * @param {Obj} data - apply this data to the template and replace the body contents.
3127 applyBody: function(obj)
3130 Roo.log("Error - using apply Body without a template");
3133 this.tmpl.overwrite(this.bodyEl, obj);
3136 getChildHeight : function(child_nodes)
3140 child_nodes.length == 0
3145 var child_height = 0;
3147 for(var i = 0; i < child_nodes.length; i++) {
3150 * for modal with tabs...
3151 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3153 var layout_childs = child_nodes[i].childNodes;
3155 for(var j = 0; j < layout_childs.length; j++) {
3157 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3159 var layout_body_childs = layout_childs[j].childNodes;
3161 for(var k = 0; k < layout_body_childs.length; k++) {
3163 if(layout_body_childs[k].classList.contains('navbar')) {
3164 child_height += layout_body_childs[k].offsetHeight;
3168 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3170 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3172 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3174 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3175 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3190 child_height += child_nodes[i].offsetHeight;
3191 // Roo.log(child_nodes[i].offsetHeight);
3194 return child_height;
3200 Roo.apply(Roo.bootstrap.Modal, {
3202 * Button config that displays a single OK button
3211 * Button config that displays Yes and No buttons
3227 * Button config that displays OK and Cancel buttons
3242 * Button config that displays Yes, No and Cancel buttons
3266 * messagebox - can be used as a replace
3270 * @class Roo.MessageBox
3271 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3275 Roo.Msg.alert('Status', 'Changes saved successfully.');
3277 // Prompt for user data:
3278 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3280 // process text value...
3284 // Show a dialog using config options:
3286 title:'Save Changes?',
3287 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3288 buttons: Roo.Msg.YESNOCANCEL,
3295 Roo.bootstrap.MessageBox = function(){
3296 var dlg, opt, mask, waitTimer;
3297 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3298 var buttons, activeTextEl, bwidth;
3302 var handleButton = function(button){
3304 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3308 var handleHide = function(){
3310 dlg.el.removeClass(opt.cls);
3313 // Roo.TaskMgr.stop(waitTimer);
3314 // waitTimer = null;
3319 var updateButtons = function(b){
3322 buttons["ok"].hide();
3323 buttons["cancel"].hide();
3324 buttons["yes"].hide();
3325 buttons["no"].hide();
3326 dlg.footerEl.hide();
3330 dlg.footerEl.show();
3331 for(var k in buttons){
3332 if(typeof buttons[k] != "function"){
3335 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3336 width += buttons[k].el.getWidth()+15;
3346 var handleEsc = function(d, k, e){
3347 if(opt && opt.closable !== false){
3357 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3358 * @return {Roo.BasicDialog} The BasicDialog element
3360 getDialog : function(){
3362 dlg = new Roo.bootstrap.Modal( {
3365 //constraintoviewport:false,
3367 //collapsible : false,
3372 //buttonAlign:"center",
3373 closeClick : function(){
3374 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3377 handleButton("cancel");
3382 dlg.on("hide", handleHide);
3384 //dlg.addKeyListener(27, handleEsc);
3386 this.buttons = buttons;
3387 var bt = this.buttonText;
3388 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3389 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3390 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3391 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3393 bodyEl = dlg.bodyEl.createChild({
3395 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3396 '<textarea class="roo-mb-textarea"></textarea>' +
3397 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3399 msgEl = bodyEl.dom.firstChild;
3400 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3401 textboxEl.enableDisplayMode();
3402 textboxEl.addKeyListener([10,13], function(){
3403 if(dlg.isVisible() && opt && opt.buttons){
3406 }else if(opt.buttons.yes){
3407 handleButton("yes");
3411 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3412 textareaEl.enableDisplayMode();
3413 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3414 progressEl.enableDisplayMode();
3416 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3417 var pf = progressEl.dom.firstChild;
3419 pp = Roo.get(pf.firstChild);
3420 pp.setHeight(pf.offsetHeight);
3428 * Updates the message box body text
3429 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3430 * the XHTML-compliant non-breaking space character '&#160;')
3431 * @return {Roo.MessageBox} This message box
3433 updateText : function(text)
3435 if(!dlg.isVisible() && !opt.width){
3436 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3437 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3439 msgEl.innerHTML = text || ' ';
3441 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3442 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3444 Math.min(opt.width || cw , this.maxWidth),
3445 Math.max(opt.minWidth || this.minWidth, bwidth)
3448 activeTextEl.setWidth(w);
3450 if(dlg.isVisible()){
3451 dlg.fixedcenter = false;
3453 // to big, make it scroll. = But as usual stupid IE does not support
3456 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3457 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3458 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3460 bodyEl.dom.style.height = '';
3461 bodyEl.dom.style.overflowY = '';
3464 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3466 bodyEl.dom.style.overflowX = '';
3469 dlg.setContentSize(w, bodyEl.getHeight());
3470 if(dlg.isVisible()){
3471 dlg.fixedcenter = true;
3477 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3478 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3479 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3480 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3481 * @return {Roo.MessageBox} This message box
3483 updateProgress : function(value, text){
3485 this.updateText(text);
3488 if (pp) { // weird bug on my firefox - for some reason this is not defined
3489 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3490 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3496 * Returns true if the message box is currently displayed
3497 * @return {Boolean} True if the message box is visible, else false
3499 isVisible : function(){
3500 return dlg && dlg.isVisible();
3504 * Hides the message box if it is displayed
3507 if(this.isVisible()){
3513 * Displays a new message box, or reinitializes an existing message box, based on the config options
3514 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3515 * The following config object properties are supported:
3517 Property Type Description
3518 ---------- --------------- ------------------------------------------------------------------------------------
3519 animEl String/Element An id or Element from which the message box should animate as it opens and
3520 closes (defaults to undefined)
3521 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3522 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3523 closable Boolean False to hide the top-right close button (defaults to true). Note that
3524 progress and wait dialogs will ignore this property and always hide the
3525 close button as they can only be closed programmatically.
3526 cls String A custom CSS class to apply to the message box element
3527 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3528 displayed (defaults to 75)
3529 fn Function A callback function to execute after closing the dialog. The arguments to the
3530 function will be btn (the name of the button that was clicked, if applicable,
3531 e.g. "ok"), and text (the value of the active text field, if applicable).
3532 Progress and wait dialogs will ignore this option since they do not respond to
3533 user actions and can only be closed programmatically, so any required function
3534 should be called by the same code after it closes the dialog.
3535 icon String A CSS class that provides a background image to be used as an icon for
3536 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3537 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3538 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3539 modal Boolean False to allow user interaction with the page while the message box is
3540 displayed (defaults to true)
3541 msg String A string that will replace the existing message box body text (defaults
3542 to the XHTML-compliant non-breaking space character ' ')
3543 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3544 progress Boolean True to display a progress bar (defaults to false)
3545 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3546 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3547 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3548 title String The title text
3549 value String The string value to set into the active textbox element if displayed
3550 wait Boolean True to display a progress bar (defaults to false)
3551 width Number The width of the dialog in pixels
3558 msg: 'Please enter your address:',
3560 buttons: Roo.MessageBox.OKCANCEL,
3563 animEl: 'addAddressBtn'
3566 * @param {Object} config Configuration options
3567 * @return {Roo.MessageBox} This message box
3569 show : function(options)
3572 // this causes nightmares if you show one dialog after another
3573 // especially on callbacks..
3575 if(this.isVisible()){
3578 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3579 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3580 Roo.log("New Dialog Message:" + options.msg )
3581 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3582 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3585 var d = this.getDialog();
3587 d.setTitle(opt.title || " ");
3588 d.closeEl.setDisplayed(opt.closable !== false);
3589 activeTextEl = textboxEl;
3590 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3595 textareaEl.setHeight(typeof opt.multiline == "number" ?
3596 opt.multiline : this.defaultTextHeight);
3597 activeTextEl = textareaEl;
3606 progressEl.setDisplayed(opt.progress === true);
3608 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3610 this.updateProgress(0);
3611 activeTextEl.dom.value = opt.value || "";
3613 dlg.setDefaultButton(activeTextEl);
3615 var bs = opt.buttons;
3619 }else if(bs && bs.yes){
3620 db = buttons["yes"];
3622 dlg.setDefaultButton(db);
3624 bwidth = updateButtons(opt.buttons);
3625 this.updateText(opt.msg);
3627 d.el.addClass(opt.cls);
3629 d.proxyDrag = opt.proxyDrag === true;
3630 d.modal = opt.modal !== false;
3631 d.mask = opt.modal !== false ? mask : false;
3633 // force it to the end of the z-index stack so it gets a cursor in FF
3634 document.body.appendChild(dlg.el.dom);
3635 d.animateTarget = null;
3636 d.show(options.animEl);
3642 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3643 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3644 * and closing the message box when the process is complete.
3645 * @param {String} title The title bar text
3646 * @param {String} msg The message box body text
3647 * @return {Roo.MessageBox} This message box
3649 progress : function(title, msg){
3656 minWidth: this.minProgressWidth,
3663 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3664 * If a callback function is passed it will be called after the user clicks the button, and the
3665 * id of the button that was clicked will be passed as the only parameter to the callback
3666 * (could also be the top-right close button).
3667 * @param {String} title The title bar text
3668 * @param {String} msg The message box body text
3669 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3670 * @param {Object} scope (optional) The scope of the callback function
3671 * @return {Roo.MessageBox} This message box
3673 alert : function(title, msg, fn, scope)
3688 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3689 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3690 * You are responsible for closing the message box when the process is complete.
3691 * @param {String} msg The message box body text
3692 * @param {String} title (optional) The title bar text
3693 * @return {Roo.MessageBox} This message box
3695 wait : function(msg, title){
3706 waitTimer = Roo.TaskMgr.start({
3708 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3716 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3717 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3718 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3719 * @param {String} title The title bar text
3720 * @param {String} msg The message box body text
3721 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3722 * @param {Object} scope (optional) The scope of the callback function
3723 * @return {Roo.MessageBox} This message box
3725 confirm : function(title, msg, fn, scope){
3729 buttons: this.YESNO,
3738 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3739 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3740 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3741 * (could also be the top-right close button) and the text that was entered will be passed as the two
3742 * parameters to the callback.
3743 * @param {String} title The title bar text
3744 * @param {String} msg The message box body text
3745 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3746 * @param {Object} scope (optional) The scope of the callback function
3747 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3748 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3749 * @return {Roo.MessageBox} This message box
3751 prompt : function(title, msg, fn, scope, multiline){
3755 buttons: this.OKCANCEL,
3760 multiline: multiline,
3767 * Button config that displays a single OK button
3772 * Button config that displays Yes and No buttons
3775 YESNO : {yes:true, no:true},
3777 * Button config that displays OK and Cancel buttons
3780 OKCANCEL : {ok:true, cancel:true},
3782 * Button config that displays Yes, No and Cancel buttons
3785 YESNOCANCEL : {yes:true, no:true, cancel:true},
3788 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3791 defaultTextHeight : 75,
3793 * The maximum width in pixels of the message box (defaults to 600)
3798 * The minimum width in pixels of the message box (defaults to 100)
3803 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3804 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3807 minProgressWidth : 250,
3809 * An object containing the default button text strings that can be overriden for localized language support.
3810 * Supported properties are: ok, cancel, yes and no.
3811 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3824 * Shorthand for {@link Roo.MessageBox}
3826 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3827 Roo.Msg = Roo.Msg || Roo.MessageBox;
3836 * @class Roo.bootstrap.Navbar
3837 * @extends Roo.bootstrap.Component
3838 * Bootstrap Navbar class
3841 * Create a new Navbar
3842 * @param {Object} config The config object
3846 Roo.bootstrap.Navbar = function(config){
3847 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3851 * @event beforetoggle
3852 * Fire before toggle the menu
3853 * @param {Roo.EventObject} e
3855 "beforetoggle" : true
3859 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3868 getAutoCreate : function(){
3871 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3875 initEvents :function ()
3877 //Roo.log(this.el.select('.navbar-toggle',true));
3878 this.el.select('.navbar-toggle',true).on('click', function() {
3879 if(this.fireEvent('beforetoggle', this) !== false){
3880 var ce = this.el.select('.navbar-collapse',true).first();
3881 ce.toggleClass('in'); // old...
3882 if (ce.hasClass('collapse')) {
3884 ce.removeClass('collapse');
3885 ce.addClass('show');
3886 var h = ce.getHeight();
3888 ce.removeClass('show');
3889 // at this point we should be able to see it..
3890 ce.addClass('collapsing');
3892 ce.setHeight(0); // resize it ...
3893 ce.on('transitionend', function() {
3894 Roo.log('done transition');
3895 ce.removeClass('collapsing');
3896 ce.addClass('show');
3897 ce.removeClass('collapse');
3899 ce.dom.style.height = '';
3900 }, this, { single: true} );
3904 ce.setHeight(ce.getHeight());
3905 ce.removeClass('show');
3906 ce.addClass('collapsing');
3908 ce.on('transitionend', function() {
3909 ce.dom.style.height = '';
3910 ce.removeClass('collapsing');
3911 ce.addClass('collapse');
3912 }, this, { single: true} );
3924 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3926 var size = this.el.getSize();
3927 this.maskEl.setSize(size.width, size.height);
3928 this.maskEl.enableDisplayMode("block");
3937 getChildContainer : function()
3939 if (this.el && this.el.select('.collapse').getCount()) {
3940 return this.el.select('.collapse',true).first();
3973 * @class Roo.bootstrap.NavSimplebar
3974 * @extends Roo.bootstrap.Navbar
3975 * Bootstrap Sidebar class
3977 * @cfg {Boolean} inverse is inverted color
3979 * @cfg {String} type (nav | pills | tabs)
3980 * @cfg {Boolean} arrangement stacked | justified
3981 * @cfg {String} align (left | right) alignment
3983 * @cfg {Boolean} main (true|false) main nav bar? default false
3984 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
3986 * @cfg {String} tag (header|footer|nav|div) default is nav
3988 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
3992 * Create a new Sidebar
3993 * @param {Object} config The config object
3997 Roo.bootstrap.NavSimplebar = function(config){
3998 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4001 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4017 getAutoCreate : function(){
4021 tag : this.tag || 'div',
4022 cls : 'navbar navbar-expand-lg roo-navbar-simple'
4024 if (['light','white'].indexOf(this.weight) > -1) {
4025 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4027 cfg.cls += ' bg-' + this.weight;
4030 cfg.cls += ' navbar-inverse';
4034 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4036 //if (Roo.bootstrap.version == 4) {
4048 this.type = this.type || 'nav';
4049 if (['tabs','pills'].indexOf(this.type) != -1) {
4050 cfg.cn[0].cls += ' nav-' + this.type
4054 if (this.type!=='nav') {
4055 Roo.log('nav type must be nav/tabs/pills')
4057 cfg.cn[0].cls += ' navbar-nav'
4063 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4064 cfg.cn[0].cls += ' nav-' + this.arrangement;
4068 if (this.align === 'right') {
4069 cfg.cn[0].cls += ' navbar-right';
4094 * navbar-expand-md fixed-top
4098 * @class Roo.bootstrap.NavHeaderbar
4099 * @extends Roo.bootstrap.NavSimplebar
4100 * Bootstrap Sidebar class
4102 * @cfg {String} brand what is brand
4103 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4104 * @cfg {String} brand_href href of the brand
4105 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4106 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4107 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4108 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4111 * Create a new Sidebar
4112 * @param {Object} config The config object
4116 Roo.bootstrap.NavHeaderbar = function(config){
4117 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4121 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4128 desktopCenter : false,
4131 getAutoCreate : function(){
4134 tag: this.nav || 'nav',
4135 cls: 'navbar navbar-expand-md',
4141 if (this.desktopCenter) {
4142 cn.push({cls : 'container', cn : []});
4150 cls: 'navbar-toggle navbar-toggler',
4151 'data-toggle': 'collapse',
4156 html: 'Toggle navigation'
4160 cls: 'icon-bar navbar-toggler-icon'
4173 cn.push( Roo.bootstrap.version == 4 ? btn : {
4175 cls: 'navbar-header',
4184 cls: 'collapse navbar-collapse',
4188 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4190 if (['light','white'].indexOf(this.weight) > -1) {
4191 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4193 cfg.cls += ' bg-' + this.weight;
4196 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4197 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4199 // tag can override this..
4201 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4204 if (this.brand !== '') {
4205 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4206 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4208 href: this.brand_href ? this.brand_href : '#',
4209 cls: 'navbar-brand',
4217 cfg.cls += ' main-nav';
4225 getHeaderChildContainer : function()
4227 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4228 return this.el.select('.navbar-header',true).first();
4231 return this.getChildContainer();
4235 initEvents : function()
4237 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4239 if (this.autohide) {
4244 Roo.get(document).on('scroll',function(e) {
4245 var ns = Roo.get(document).getScroll().top;
4246 var os = prevScroll;
4250 ft.removeClass('slideDown');
4251 ft.addClass('slideUp');
4254 ft.removeClass('slideUp');
4255 ft.addClass('slideDown');
4276 * @class Roo.bootstrap.NavSidebar
4277 * @extends Roo.bootstrap.Navbar
4278 * Bootstrap Sidebar class
4281 * Create a new Sidebar
4282 * @param {Object} config The config object
4286 Roo.bootstrap.NavSidebar = function(config){
4287 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4290 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4292 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4294 getAutoCreate : function(){
4299 cls: 'sidebar sidebar-nav'
4321 * @class Roo.bootstrap.NavGroup
4322 * @extends Roo.bootstrap.Component
4323 * Bootstrap NavGroup class
4324 * @cfg {String} align (left|right)
4325 * @cfg {Boolean} inverse
4326 * @cfg {String} type (nav|pills|tab) default nav
4327 * @cfg {String} navId - reference Id for navbar.
4331 * Create a new nav group
4332 * @param {Object} config The config object
4335 Roo.bootstrap.NavGroup = function(config){
4336 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4339 Roo.bootstrap.NavGroup.register(this);
4343 * Fires when the active item changes
4344 * @param {Roo.bootstrap.NavGroup} this
4345 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4346 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4353 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4364 getAutoCreate : function()
4366 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4372 if (Roo.bootstrap.version == 4) {
4373 if (['tabs','pills'].indexOf(this.type) != -1) {
4374 cfg.cls += ' nav-' + this.type;
4376 cfg.cls += ' navbar-nav';
4379 if (['tabs','pills'].indexOf(this.type) != -1) {
4380 cfg.cls += ' nav-' + this.type
4382 if (this.type !== 'nav') {
4383 Roo.log('nav type must be nav/tabs/pills')
4385 cfg.cls += ' navbar-nav'
4389 if (this.parent() && this.parent().sidebar) {
4392 cls: 'dashboard-menu sidebar-menu'
4398 if (this.form === true) {
4401 cls: 'navbar-form form-inline'
4404 if (this.align === 'right') {
4405 cfg.cls += ' navbar-right ml-md-auto';
4407 cfg.cls += ' navbar-left';
4411 if (this.align === 'right') {
4412 cfg.cls += ' navbar-right ml-md-auto';
4414 cfg.cls += ' mr-auto';
4418 cfg.cls += ' navbar-inverse';
4426 * sets the active Navigation item
4427 * @param {Roo.bootstrap.NavItem} the new current navitem
4429 setActiveItem : function(item)
4432 Roo.each(this.navItems, function(v){
4437 v.setActive(false, true);
4444 item.setActive(true, true);
4445 this.fireEvent('changed', this, item, prev);
4450 * gets the active Navigation item
4451 * @return {Roo.bootstrap.NavItem} the current navitem
4453 getActive : function()
4457 Roo.each(this.navItems, function(v){
4468 indexOfNav : function()
4472 Roo.each(this.navItems, function(v,i){
4483 * adds a Navigation item
4484 * @param {Roo.bootstrap.NavItem} the navitem to add
4486 addItem : function(cfg)
4488 if (this.form && Roo.bootstrap.version == 4) {
4491 var cn = new Roo.bootstrap.NavItem(cfg);
4493 cn.parentId = this.id;
4494 cn.onRender(this.el, null);
4498 * register a Navigation item
4499 * @param {Roo.bootstrap.NavItem} the navitem to add
4501 register : function(item)
4503 this.navItems.push( item);
4504 item.navId = this.navId;
4509 * clear all the Navigation item
4512 clearAll : function()
4515 this.el.dom.innerHTML = '';
4518 getNavItem: function(tabId)
4521 Roo.each(this.navItems, function(e) {
4522 if (e.tabId == tabId) {
4532 setActiveNext : function()
4534 var i = this.indexOfNav(this.getActive());
4535 if (i > this.navItems.length) {
4538 this.setActiveItem(this.navItems[i+1]);
4540 setActivePrev : function()
4542 var i = this.indexOfNav(this.getActive());
4546 this.setActiveItem(this.navItems[i-1]);
4548 clearWasActive : function(except) {
4549 Roo.each(this.navItems, function(e) {
4550 if (e.tabId != except.tabId && e.was_active) {
4551 e.was_active = false;
4558 getWasActive : function ()
4561 Roo.each(this.navItems, function(e) {
4576 Roo.apply(Roo.bootstrap.NavGroup, {
4580 * register a Navigation Group
4581 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4583 register : function(navgrp)
4585 this.groups[navgrp.navId] = navgrp;
4589 * fetch a Navigation Group based on the navigation ID
4590 * @param {string} the navgroup to add
4591 * @returns {Roo.bootstrap.NavGroup} the navgroup
4593 get: function(navId) {
4594 if (typeof(this.groups[navId]) == 'undefined') {
4596 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4598 return this.groups[navId] ;
4613 * @class Roo.bootstrap.NavItem
4614 * @extends Roo.bootstrap.Component
4615 * Bootstrap Navbar.NavItem class
4616 * @cfg {String} href link to
4617 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4619 * @cfg {String} html content of button
4620 * @cfg {String} badge text inside badge
4621 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4622 * @cfg {String} glyphicon DEPRICATED - use fa
4623 * @cfg {String} icon DEPRICATED - use fa
4624 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4625 * @cfg {Boolean} active Is item active
4626 * @cfg {Boolean} disabled Is item disabled
4628 * @cfg {Boolean} preventDefault (true | false) default false
4629 * @cfg {String} tabId the tab that this item activates.
4630 * @cfg {String} tagtype (a|span) render as a href or span?
4631 * @cfg {Boolean} animateRef (true|false) link to element default false
4634 * Create a new Navbar Item
4635 * @param {Object} config The config object
4637 Roo.bootstrap.NavItem = function(config){
4638 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4643 * The raw click event for the entire grid.
4644 * @param {Roo.EventObject} e
4649 * Fires when the active item active state changes
4650 * @param {Roo.bootstrap.NavItem} this
4651 * @param {boolean} state the new state
4657 * Fires when scroll to element
4658 * @param {Roo.bootstrap.NavItem} this
4659 * @param {Object} options
4660 * @param {Roo.EventObject} e
4668 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4677 preventDefault : false,
4685 button_outline : false,
4689 getAutoCreate : function(){
4697 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4699 if (this.disabled) {
4700 cfg.cls += ' disabled';
4704 if (this.button_weight.length) {
4705 cfg.tag = this.href ? 'a' : 'button';
4706 cfg.html = this.html || '';
4707 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4709 cfg.href = this.href;
4712 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4715 // menu .. should add dropdown-menu class - so no need for carat..
4717 if (this.badge !== '') {
4719 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4724 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4728 href : this.href || "#",
4729 html: this.html || ''
4732 if (this.tagtype == 'a') {
4733 cfg.cn[0].cls = 'nav-link';
4736 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4739 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4741 if(this.glyphicon) {
4742 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4747 cfg.cn[0].html += " <span class='caret'></span>";
4751 if (this.badge !== '') {
4753 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4761 onRender : function(ct, position)
4763 // Roo.log("Call onRender: " + this.xtype);
4764 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4768 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4769 this.navLink = this.el.select('.nav-link',true).first();
4774 initEvents: function()
4776 if (typeof (this.menu) != 'undefined') {
4777 this.menu.parentType = this.xtype;
4778 this.menu.triggerEl = this.el;
4779 this.menu = this.addxtype(Roo.apply({}, this.menu));
4782 this.el.select('a',true).on('click', this.onClick, this);
4784 if(this.tagtype == 'span'){
4785 this.el.select('span',true).on('click', this.onClick, this);
4788 // at this point parent should be available..
4789 this.parent().register(this);
4792 onClick : function(e)
4794 if (e.getTarget('.dropdown-menu-item')) {
4795 // did you click on a menu itemm.... - then don't trigger onclick..
4800 this.preventDefault ||
4803 Roo.log("NavItem - prevent Default?");
4807 if (this.disabled) {
4811 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4812 if (tg && tg.transition) {
4813 Roo.log("waiting for the transitionend");
4819 //Roo.log("fire event clicked");
4820 if(this.fireEvent('click', this, e) === false){
4824 if(this.tagtype == 'span'){
4828 //Roo.log(this.href);
4829 var ael = this.el.select('a',true).first();
4832 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4833 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4834 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4835 return; // ignore... - it's a 'hash' to another page.
4837 Roo.log("NavItem - prevent Default?");
4839 this.scrollToElement(e);
4843 var p = this.parent();
4845 if (['tabs','pills'].indexOf(p.type)!==-1) {
4846 if (typeof(p.setActiveItem) !== 'undefined') {
4847 p.setActiveItem(this);
4851 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4852 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4853 // remove the collapsed menu expand...
4854 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4858 isActive: function () {
4861 setActive : function(state, fire, is_was_active)
4863 if (this.active && !state && this.navId) {
4864 this.was_active = true;
4865 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4867 nv.clearWasActive(this);
4871 this.active = state;
4874 this.el.removeClass('active');
4875 this.navLink ? this.navLink.removeClass('active') : false;
4876 } else if (!this.el.hasClass('active')) {
4878 this.el.addClass('active');
4879 if (Roo.bootstrap.version == 4 && this.navLink ) {
4880 this.navLink.addClass('active');
4885 this.fireEvent('changed', this, state);
4888 // show a panel if it's registered and related..
4890 if (!this.navId || !this.tabId || !state || is_was_active) {
4894 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4898 var pan = tg.getPanelByName(this.tabId);
4902 // if we can not flip to new panel - go back to old nav highlight..
4903 if (false == tg.showPanel(pan)) {
4904 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4906 var onav = nv.getWasActive();
4908 onav.setActive(true, false, true);
4917 // this should not be here...
4918 setDisabled : function(state)
4920 this.disabled = state;
4922 this.el.removeClass('disabled');
4923 } else if (!this.el.hasClass('disabled')) {
4924 this.el.addClass('disabled');
4930 * Fetch the element to display the tooltip on.
4931 * @return {Roo.Element} defaults to this.el
4933 tooltipEl : function()
4935 return this.el.select('' + this.tagtype + '', true).first();
4938 scrollToElement : function(e)
4940 var c = document.body;
4943 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4945 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4946 c = document.documentElement;
4949 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4955 var o = target.calcOffsetsTo(c);
4962 this.fireEvent('scrollto', this, options, e);
4964 Roo.get(c).scrollTo('top', options.value, true);
4977 * <span> icon </span>
4978 * <span> text </span>
4979 * <span>badge </span>
4983 * @class Roo.bootstrap.NavSidebarItem
4984 * @extends Roo.bootstrap.NavItem
4985 * Bootstrap Navbar.NavSidebarItem class
4986 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
4987 * {Boolean} open is the menu open
4988 * {Boolean} buttonView use button as the tigger el rather that a (default false)
4989 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
4990 * {String} buttonSize (sm|md|lg)the extra classes for the button
4991 * {Boolean} showArrow show arrow next to the text (default true)
4993 * Create a new Navbar Button
4994 * @param {Object} config The config object
4996 Roo.bootstrap.NavSidebarItem = function(config){
4997 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5002 * The raw click event for the entire grid.
5003 * @param {Roo.EventObject} e
5008 * Fires when the active item active state changes
5009 * @param {Roo.bootstrap.NavSidebarItem} this
5010 * @param {boolean} state the new state
5018 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5020 badgeWeight : 'default',
5026 buttonWeight : 'default',
5032 getAutoCreate : function(){
5037 href : this.href || '#',
5043 if(this.buttonView){
5046 href : this.href || '#',
5047 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5060 cfg.cls += ' active';
5063 if (this.disabled) {
5064 cfg.cls += ' disabled';
5067 cfg.cls += ' open x-open';
5070 if (this.glyphicon || this.icon) {
5071 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5072 a.cn.push({ tag : 'i', cls : c }) ;
5075 if(!this.buttonView){
5078 html : this.html || ''
5085 if (this.badge !== '') {
5086 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5092 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5095 a.cls += ' dropdown-toggle treeview' ;
5101 initEvents : function()
5103 if (typeof (this.menu) != 'undefined') {
5104 this.menu.parentType = this.xtype;
5105 this.menu.triggerEl = this.el;
5106 this.menu = this.addxtype(Roo.apply({}, this.menu));
5109 this.el.on('click', this.onClick, this);
5111 if(this.badge !== ''){
5112 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5117 onClick : function(e)
5124 if(this.preventDefault){
5128 this.fireEvent('click', this);
5131 disable : function()
5133 this.setDisabled(true);
5138 this.setDisabled(false);
5141 setDisabled : function(state)
5143 if(this.disabled == state){
5147 this.disabled = state;
5150 this.el.addClass('disabled');
5154 this.el.removeClass('disabled');
5159 setActive : function(state)
5161 if(this.active == state){
5165 this.active = state;
5168 this.el.addClass('active');
5172 this.el.removeClass('active');
5177 isActive: function ()
5182 setBadge : function(str)
5188 this.badgeEl.dom.innerHTML = str;
5205 * @class Roo.bootstrap.Row
5206 * @extends Roo.bootstrap.Component
5207 * Bootstrap Row class (contains columns...)
5211 * @param {Object} config The config object
5214 Roo.bootstrap.Row = function(config){
5215 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5218 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5220 getAutoCreate : function(){
5239 * @class Roo.bootstrap.Element
5240 * @extends Roo.bootstrap.Component
5241 * Bootstrap Element class
5242 * @cfg {String} html contents of the element
5243 * @cfg {String} tag tag of the element
5244 * @cfg {String} cls class of the element
5245 * @cfg {Boolean} preventDefault (true|false) default false
5246 * @cfg {Boolean} clickable (true|false) default false
5249 * Create a new Element
5250 * @param {Object} config The config object
5253 Roo.bootstrap.Element = function(config){
5254 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5260 * When a element is chick
5261 * @param {Roo.bootstrap.Element} this
5262 * @param {Roo.EventObject} e
5268 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5273 preventDefault: false,
5276 getAutoCreate : function(){
5280 // cls: this.cls, double assign in parent class Component.js :: onRender
5287 initEvents: function()
5289 Roo.bootstrap.Element.superclass.initEvents.call(this);
5292 this.el.on('click', this.onClick, this);
5297 onClick : function(e)
5299 if(this.preventDefault){
5303 this.fireEvent('click', this, e);
5306 getValue : function()
5308 return this.el.dom.innerHTML;
5311 setValue : function(value)
5313 this.el.dom.innerHTML = value;
5328 * @class Roo.bootstrap.Pagination
5329 * @extends Roo.bootstrap.Component
5330 * Bootstrap Pagination class
5331 * @cfg {String} size xs | sm | md | lg
5332 * @cfg {Boolean} inverse false | true
5335 * Create a new Pagination
5336 * @param {Object} config The config object
5339 Roo.bootstrap.Pagination = function(config){
5340 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5343 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5349 getAutoCreate : function(){
5355 cfg.cls += ' inverse';
5361 cfg.cls += " " + this.cls;
5379 * @class Roo.bootstrap.PaginationItem
5380 * @extends Roo.bootstrap.Component
5381 * Bootstrap PaginationItem class
5382 * @cfg {String} html text
5383 * @cfg {String} href the link
5384 * @cfg {Boolean} preventDefault (true | false) default true
5385 * @cfg {Boolean} active (true | false) default false
5386 * @cfg {Boolean} disabled default false
5390 * Create a new PaginationItem
5391 * @param {Object} config The config object
5395 Roo.bootstrap.PaginationItem = function(config){
5396 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5401 * The raw click event for the entire grid.
5402 * @param {Roo.EventObject} e
5408 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5412 preventDefault: true,
5417 getAutoCreate : function(){
5423 href : this.href ? this.href : '#',
5424 html : this.html ? this.html : ''
5434 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5438 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5444 initEvents: function() {
5446 this.el.on('click', this.onClick, this);
5449 onClick : function(e)
5451 Roo.log('PaginationItem on click ');
5452 if(this.preventDefault){
5460 this.fireEvent('click', this, e);
5476 * @class Roo.bootstrap.Slider
5477 * @extends Roo.bootstrap.Component
5478 * Bootstrap Slider class
5481 * Create a new Slider
5482 * @param {Object} config The config object
5485 Roo.bootstrap.Slider = function(config){
5486 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5489 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5491 getAutoCreate : function(){
5495 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5499 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5511 * Ext JS Library 1.1.1
5512 * Copyright(c) 2006-2007, Ext JS, LLC.
5514 * Originally Released Under LGPL - original licence link has changed is not relivant.
5517 * <script type="text/javascript">
5522 * @class Roo.grid.ColumnModel
5523 * @extends Roo.util.Observable
5524 * This is the default implementation of a ColumnModel used by the Grid. It defines
5525 * the columns in the grid.
5528 var colModel = new Roo.grid.ColumnModel([
5529 {header: "Ticker", width: 60, sortable: true, locked: true},
5530 {header: "Company Name", width: 150, sortable: true},
5531 {header: "Market Cap.", width: 100, sortable: true},
5532 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5533 {header: "Employees", width: 100, sortable: true, resizable: false}
5538 * The config options listed for this class are options which may appear in each
5539 * individual column definition.
5540 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5542 * @param {Object} config An Array of column config objects. See this class's
5543 * config objects for details.
5545 Roo.grid.ColumnModel = function(config){
5547 * The config passed into the constructor
5549 this.config = config;
5552 // if no id, create one
5553 // if the column does not have a dataIndex mapping,
5554 // map it to the order it is in the config
5555 for(var i = 0, len = config.length; i < len; i++){
5557 if(typeof c.dataIndex == "undefined"){
5560 if(typeof c.renderer == "string"){
5561 c.renderer = Roo.util.Format[c.renderer];
5563 if(typeof c.id == "undefined"){
5566 if(c.editor && c.editor.xtype){
5567 c.editor = Roo.factory(c.editor, Roo.grid);
5569 if(c.editor && c.editor.isFormField){
5570 c.editor = new Roo.grid.GridEditor(c.editor);
5572 this.lookup[c.id] = c;
5576 * The width of columns which have no width specified (defaults to 100)
5579 this.defaultWidth = 100;
5582 * Default sortable of columns which have no sortable specified (defaults to false)
5585 this.defaultSortable = false;
5589 * @event widthchange
5590 * Fires when the width of a column changes.
5591 * @param {ColumnModel} this
5592 * @param {Number} columnIndex The column index
5593 * @param {Number} newWidth The new width
5595 "widthchange": true,
5597 * @event headerchange
5598 * Fires when the text of a header changes.
5599 * @param {ColumnModel} this
5600 * @param {Number} columnIndex The column index
5601 * @param {Number} newText The new header text
5603 "headerchange": true,
5605 * @event hiddenchange
5606 * Fires when a column is hidden or "unhidden".
5607 * @param {ColumnModel} this
5608 * @param {Number} columnIndex The column index
5609 * @param {Boolean} hidden true if hidden, false otherwise
5611 "hiddenchange": true,
5613 * @event columnmoved
5614 * Fires when a column is moved.
5615 * @param {ColumnModel} this
5616 * @param {Number} oldIndex
5617 * @param {Number} newIndex
5619 "columnmoved" : true,
5621 * @event columlockchange
5622 * Fires when a column's locked state is changed
5623 * @param {ColumnModel} this
5624 * @param {Number} colIndex
5625 * @param {Boolean} locked true if locked
5627 "columnlockchange" : true
5629 Roo.grid.ColumnModel.superclass.constructor.call(this);
5631 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5633 * @cfg {String} header The header text to display in the Grid view.
5636 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5637 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5638 * specified, the column's index is used as an index into the Record's data Array.
5641 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5642 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5645 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5646 * Defaults to the value of the {@link #defaultSortable} property.
5647 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5650 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5653 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5656 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5659 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5662 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5663 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5664 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5665 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5668 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5671 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5674 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5677 * @cfg {String} cursor (Optional)
5680 * @cfg {String} tooltip (Optional)
5683 * @cfg {Number} xs (Optional)
5686 * @cfg {Number} sm (Optional)
5689 * @cfg {Number} md (Optional)
5692 * @cfg {Number} lg (Optional)
5695 * Returns the id of the column at the specified index.
5696 * @param {Number} index The column index
5697 * @return {String} the id
5699 getColumnId : function(index){
5700 return this.config[index].id;
5704 * Returns the column for a specified id.
5705 * @param {String} id The column id
5706 * @return {Object} the column
5708 getColumnById : function(id){
5709 return this.lookup[id];
5714 * Returns the column for a specified dataIndex.
5715 * @param {String} dataIndex The column dataIndex
5716 * @return {Object|Boolean} the column or false if not found
5718 getColumnByDataIndex: function(dataIndex){
5719 var index = this.findColumnIndex(dataIndex);
5720 return index > -1 ? this.config[index] : false;
5724 * Returns the index for a specified column id.
5725 * @param {String} id The column id
5726 * @return {Number} the index, or -1 if not found
5728 getIndexById : function(id){
5729 for(var i = 0, len = this.config.length; i < len; i++){
5730 if(this.config[i].id == id){
5738 * Returns the index for a specified column dataIndex.
5739 * @param {String} dataIndex The column dataIndex
5740 * @return {Number} the index, or -1 if not found
5743 findColumnIndex : function(dataIndex){
5744 for(var i = 0, len = this.config.length; i < len; i++){
5745 if(this.config[i].dataIndex == dataIndex){
5753 moveColumn : function(oldIndex, newIndex){
5754 var c = this.config[oldIndex];
5755 this.config.splice(oldIndex, 1);
5756 this.config.splice(newIndex, 0, c);
5757 this.dataMap = null;
5758 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5761 isLocked : function(colIndex){
5762 return this.config[colIndex].locked === true;
5765 setLocked : function(colIndex, value, suppressEvent){
5766 if(this.isLocked(colIndex) == value){
5769 this.config[colIndex].locked = value;
5771 this.fireEvent("columnlockchange", this, colIndex, value);
5775 getTotalLockedWidth : function(){
5777 for(var i = 0; i < this.config.length; i++){
5778 if(this.isLocked(i) && !this.isHidden(i)){
5779 this.totalWidth += this.getColumnWidth(i);
5785 getLockedCount : function(){
5786 for(var i = 0, len = this.config.length; i < len; i++){
5787 if(!this.isLocked(i)){
5792 return this.config.length;
5796 * Returns the number of columns.
5799 getColumnCount : function(visibleOnly){
5800 if(visibleOnly === true){
5802 for(var i = 0, len = this.config.length; i < len; i++){
5803 if(!this.isHidden(i)){
5809 return this.config.length;
5813 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5814 * @param {Function} fn
5815 * @param {Object} scope (optional)
5816 * @return {Array} result
5818 getColumnsBy : function(fn, scope){
5820 for(var i = 0, len = this.config.length; i < len; i++){
5821 var c = this.config[i];
5822 if(fn.call(scope||this, c, i) === true){
5830 * Returns true if the specified column is sortable.
5831 * @param {Number} col The column index
5834 isSortable : function(col){
5835 if(typeof this.config[col].sortable == "undefined"){
5836 return this.defaultSortable;
5838 return this.config[col].sortable;
5842 * Returns the rendering (formatting) function defined for the column.
5843 * @param {Number} col The column index.
5844 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5846 getRenderer : function(col){
5847 if(!this.config[col].renderer){
5848 return Roo.grid.ColumnModel.defaultRenderer;
5850 return this.config[col].renderer;
5854 * Sets the rendering (formatting) function for a column.
5855 * @param {Number} col The column index
5856 * @param {Function} fn The function to use to process the cell's raw data
5857 * to return HTML markup for the grid view. The render function is called with
5858 * the following parameters:<ul>
5859 * <li>Data value.</li>
5860 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5861 * <li>css A CSS style string to apply to the table cell.</li>
5862 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5863 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5864 * <li>Row index</li>
5865 * <li>Column index</li>
5866 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5868 setRenderer : function(col, fn){
5869 this.config[col].renderer = fn;
5873 * Returns the width for the specified column.
5874 * @param {Number} col The column index
5877 getColumnWidth : function(col){
5878 return this.config[col].width * 1 || this.defaultWidth;
5882 * Sets the width for a column.
5883 * @param {Number} col The column index
5884 * @param {Number} width The new width
5886 setColumnWidth : function(col, width, suppressEvent){
5887 this.config[col].width = width;
5888 this.totalWidth = null;
5890 this.fireEvent("widthchange", this, col, width);
5895 * Returns the total width of all columns.
5896 * @param {Boolean} includeHidden True to include hidden column widths
5899 getTotalWidth : function(includeHidden){
5900 if(!this.totalWidth){
5901 this.totalWidth = 0;
5902 for(var i = 0, len = this.config.length; i < len; i++){
5903 if(includeHidden || !this.isHidden(i)){
5904 this.totalWidth += this.getColumnWidth(i);
5908 return this.totalWidth;
5912 * Returns the header for the specified column.
5913 * @param {Number} col The column index
5916 getColumnHeader : function(col){
5917 return this.config[col].header;
5921 * Sets the header for a column.
5922 * @param {Number} col The column index
5923 * @param {String} header The new header
5925 setColumnHeader : function(col, header){
5926 this.config[col].header = header;
5927 this.fireEvent("headerchange", this, col, header);
5931 * Returns the tooltip for the specified column.
5932 * @param {Number} col The column index
5935 getColumnTooltip : function(col){
5936 return this.config[col].tooltip;
5939 * Sets the tooltip for a column.
5940 * @param {Number} col The column index
5941 * @param {String} tooltip The new tooltip
5943 setColumnTooltip : function(col, tooltip){
5944 this.config[col].tooltip = tooltip;
5948 * Returns the dataIndex for the specified column.
5949 * @param {Number} col The column index
5952 getDataIndex : function(col){
5953 return this.config[col].dataIndex;
5957 * Sets the dataIndex for a column.
5958 * @param {Number} col The column index
5959 * @param {Number} dataIndex The new dataIndex
5961 setDataIndex : function(col, dataIndex){
5962 this.config[col].dataIndex = dataIndex;
5968 * Returns true if the cell is editable.
5969 * @param {Number} colIndex The column index
5970 * @param {Number} rowIndex The row index - this is nto actually used..?
5973 isCellEditable : function(colIndex, rowIndex){
5974 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
5978 * Returns the editor defined for the cell/column.
5979 * return false or null to disable editing.
5980 * @param {Number} colIndex The column index
5981 * @param {Number} rowIndex The row index
5984 getCellEditor : function(colIndex, rowIndex){
5985 return this.config[colIndex].editor;
5989 * Sets if a column is editable.
5990 * @param {Number} col The column index
5991 * @param {Boolean} editable True if the column is editable
5993 setEditable : function(col, editable){
5994 this.config[col].editable = editable;
5999 * Returns true if the column is hidden.
6000 * @param {Number} colIndex The column index
6003 isHidden : function(colIndex){
6004 return this.config[colIndex].hidden;
6009 * Returns true if the column width cannot be changed
6011 isFixed : function(colIndex){
6012 return this.config[colIndex].fixed;
6016 * Returns true if the column can be resized
6019 isResizable : function(colIndex){
6020 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6023 * Sets if a column is hidden.
6024 * @param {Number} colIndex The column index
6025 * @param {Boolean} hidden True if the column is hidden
6027 setHidden : function(colIndex, hidden){
6028 this.config[colIndex].hidden = hidden;
6029 this.totalWidth = null;
6030 this.fireEvent("hiddenchange", this, colIndex, hidden);
6034 * Sets the editor for a column.
6035 * @param {Number} col The column index
6036 * @param {Object} editor The editor object
6038 setEditor : function(col, editor){
6039 this.config[col].editor = editor;
6043 Roo.grid.ColumnModel.defaultRenderer = function(value)
6045 if(typeof value == "object") {
6048 if(typeof value == "string" && value.length < 1){
6052 return String.format("{0}", value);
6055 // Alias for backwards compatibility
6056 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6059 * Ext JS Library 1.1.1
6060 * Copyright(c) 2006-2007, Ext JS, LLC.
6062 * Originally Released Under LGPL - original licence link has changed is not relivant.
6065 * <script type="text/javascript">
6069 * @class Roo.LoadMask
6070 * A simple utility class for generically masking elements while loading data. If the element being masked has
6071 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6072 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6073 * element's UpdateManager load indicator and will be destroyed after the initial load.
6075 * Create a new LoadMask
6076 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6077 * @param {Object} config The config object
6079 Roo.LoadMask = function(el, config){
6080 this.el = Roo.get(el);
6081 Roo.apply(this, config);
6083 this.store.on('beforeload', this.onBeforeLoad, this);
6084 this.store.on('load', this.onLoad, this);
6085 this.store.on('loadexception', this.onLoadException, this);
6086 this.removeMask = false;
6088 var um = this.el.getUpdateManager();
6089 um.showLoadIndicator = false; // disable the default indicator
6090 um.on('beforeupdate', this.onBeforeLoad, this);
6091 um.on('update', this.onLoad, this);
6092 um.on('failure', this.onLoad, this);
6093 this.removeMask = true;
6097 Roo.LoadMask.prototype = {
6099 * @cfg {Boolean} removeMask
6100 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6101 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6105 * The text to display in a centered loading message box (defaults to 'Loading...')
6109 * @cfg {String} msgCls
6110 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6112 msgCls : 'x-mask-loading',
6115 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6121 * Disables the mask to prevent it from being displayed
6123 disable : function(){
6124 this.disabled = true;
6128 * Enables the mask so that it can be displayed
6130 enable : function(){
6131 this.disabled = false;
6134 onLoadException : function()
6138 if (typeof(arguments[3]) != 'undefined') {
6139 Roo.MessageBox.alert("Error loading",arguments[3]);
6143 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6144 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6151 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6156 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6160 onBeforeLoad : function(){
6162 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6167 destroy : function(){
6169 this.store.un('beforeload', this.onBeforeLoad, this);
6170 this.store.un('load', this.onLoad, this);
6171 this.store.un('loadexception', this.onLoadException, this);
6173 var um = this.el.getUpdateManager();
6174 um.un('beforeupdate', this.onBeforeLoad, this);
6175 um.un('update', this.onLoad, this);
6176 um.un('failure', this.onLoad, this);
6187 * @class Roo.bootstrap.Table
6188 * @extends Roo.bootstrap.Component
6189 * Bootstrap Table class
6190 * @cfg {String} cls table class
6191 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6192 * @cfg {String} bgcolor Specifies the background color for a table
6193 * @cfg {Number} border Specifies whether the table cells should have borders or not
6194 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6195 * @cfg {Number} cellspacing Specifies the space between cells
6196 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6197 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6198 * @cfg {String} sortable Specifies that the table should be sortable
6199 * @cfg {String} summary Specifies a summary of the content of a table
6200 * @cfg {Number} width Specifies the width of a table
6201 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6203 * @cfg {boolean} striped Should the rows be alternative striped
6204 * @cfg {boolean} bordered Add borders to the table
6205 * @cfg {boolean} hover Add hover highlighting
6206 * @cfg {boolean} condensed Format condensed
6207 * @cfg {boolean} responsive Format condensed
6208 * @cfg {Boolean} loadMask (true|false) default false
6209 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6210 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6211 * @cfg {Boolean} rowSelection (true|false) default false
6212 * @cfg {Boolean} cellSelection (true|false) default false
6213 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6214 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6215 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6216 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6220 * Create a new Table
6221 * @param {Object} config The config object
6224 Roo.bootstrap.Table = function(config){
6225 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6230 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6231 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6232 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6233 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6235 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6237 this.sm.grid = this;
6238 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6239 this.sm = this.selModel;
6240 this.sm.xmodule = this.xmodule || false;
6243 if (this.cm && typeof(this.cm.config) == 'undefined') {
6244 this.colModel = new Roo.grid.ColumnModel(this.cm);
6245 this.cm = this.colModel;
6246 this.cm.xmodule = this.xmodule || false;
6249 this.store= Roo.factory(this.store, Roo.data);
6250 this.ds = this.store;
6251 this.ds.xmodule = this.xmodule || false;
6254 if (this.footer && this.store) {
6255 this.footer.dataSource = this.ds;
6256 this.footer = Roo.factory(this.footer);
6263 * Fires when a cell is clicked
6264 * @param {Roo.bootstrap.Table} this
6265 * @param {Roo.Element} el
6266 * @param {Number} rowIndex
6267 * @param {Number} columnIndex
6268 * @param {Roo.EventObject} e
6272 * @event celldblclick
6273 * Fires when a cell is double clicked
6274 * @param {Roo.bootstrap.Table} this
6275 * @param {Roo.Element} el
6276 * @param {Number} rowIndex
6277 * @param {Number} columnIndex
6278 * @param {Roo.EventObject} e
6280 "celldblclick" : true,
6283 * Fires when a row is clicked
6284 * @param {Roo.bootstrap.Table} this
6285 * @param {Roo.Element} el
6286 * @param {Number} rowIndex
6287 * @param {Roo.EventObject} e
6291 * @event rowdblclick
6292 * Fires when a row is double clicked
6293 * @param {Roo.bootstrap.Table} this
6294 * @param {Roo.Element} el
6295 * @param {Number} rowIndex
6296 * @param {Roo.EventObject} e
6298 "rowdblclick" : true,
6301 * Fires when a mouseover occur
6302 * @param {Roo.bootstrap.Table} this
6303 * @param {Roo.Element} el
6304 * @param {Number} rowIndex
6305 * @param {Number} columnIndex
6306 * @param {Roo.EventObject} e
6311 * Fires when a mouseout occur
6312 * @param {Roo.bootstrap.Table} this
6313 * @param {Roo.Element} el
6314 * @param {Number} rowIndex
6315 * @param {Number} columnIndex
6316 * @param {Roo.EventObject} e
6321 * Fires when a row is rendered, so you can change add a style to it.
6322 * @param {Roo.bootstrap.Table} this
6323 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6327 * @event rowsrendered
6328 * Fires when all the rows have been rendered
6329 * @param {Roo.bootstrap.Table} this
6331 'rowsrendered' : true,
6333 * @event contextmenu
6334 * The raw contextmenu event for the entire grid.
6335 * @param {Roo.EventObject} e
6337 "contextmenu" : true,
6339 * @event rowcontextmenu
6340 * Fires when a row is right clicked
6341 * @param {Roo.bootstrap.Table} this
6342 * @param {Number} rowIndex
6343 * @param {Roo.EventObject} e
6345 "rowcontextmenu" : true,
6347 * @event cellcontextmenu
6348 * Fires when a cell is right clicked
6349 * @param {Roo.bootstrap.Table} this
6350 * @param {Number} rowIndex
6351 * @param {Number} cellIndex
6352 * @param {Roo.EventObject} e
6354 "cellcontextmenu" : true,
6356 * @event headercontextmenu
6357 * Fires when a header is right clicked
6358 * @param {Roo.bootstrap.Table} this
6359 * @param {Number} columnIndex
6360 * @param {Roo.EventObject} e
6362 "headercontextmenu" : true
6366 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6392 rowSelection : false,
6393 cellSelection : false,
6396 // Roo.Element - the tbody
6398 // Roo.Element - thead element
6401 container: false, // used by gridpanel...
6407 auto_hide_footer : false,
6409 getAutoCreate : function()
6411 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6418 if (this.scrollBody) {
6419 cfg.cls += ' table-body-fixed';
6422 cfg.cls += ' table-striped';
6426 cfg.cls += ' table-hover';
6428 if (this.bordered) {
6429 cfg.cls += ' table-bordered';
6431 if (this.condensed) {
6432 cfg.cls += ' table-condensed';
6434 if (this.responsive) {
6435 cfg.cls += ' table-responsive';
6439 cfg.cls+= ' ' +this.cls;
6442 // this lot should be simplifed...
6455 ].forEach(function(k) {
6463 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6466 if(this.store || this.cm){
6467 if(this.headerShow){
6468 cfg.cn.push(this.renderHeader());
6471 cfg.cn.push(this.renderBody());
6473 if(this.footerShow){
6474 cfg.cn.push(this.renderFooter());
6476 // where does this come from?
6477 //cfg.cls+= ' TableGrid';
6480 return { cn : [ cfg ] };
6483 initEvents : function()
6485 if(!this.store || !this.cm){
6488 if (this.selModel) {
6489 this.selModel.initEvents();
6493 //Roo.log('initEvents with ds!!!!');
6495 this.mainBody = this.el.select('tbody', true).first();
6496 this.mainHead = this.el.select('thead', true).first();
6497 this.mainFoot = this.el.select('tfoot', true).first();
6503 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6504 e.on('click', _this.sort, _this);
6507 this.mainBody.on("click", this.onClick, this);
6508 this.mainBody.on("dblclick", this.onDblClick, this);
6510 // why is this done????? = it breaks dialogs??
6511 //this.parent().el.setStyle('position', 'relative');
6515 this.footer.parentId = this.id;
6516 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6519 this.el.select('tfoot tr td').first().addClass('hide');
6524 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6527 this.store.on('load', this.onLoad, this);
6528 this.store.on('beforeload', this.onBeforeLoad, this);
6529 this.store.on('update', this.onUpdate, this);
6530 this.store.on('add', this.onAdd, this);
6531 this.store.on("clear", this.clear, this);
6533 this.el.on("contextmenu", this.onContextMenu, this);
6535 this.mainBody.on('scroll', this.onBodyScroll, this);
6537 this.cm.on("headerchange", this.onHeaderChange, this);
6539 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6543 onContextMenu : function(e, t)
6545 this.processEvent("contextmenu", e);
6548 processEvent : function(name, e)
6550 if (name != 'touchstart' ) {
6551 this.fireEvent(name, e);
6554 var t = e.getTarget();
6556 var cell = Roo.get(t);
6562 if(cell.findParent('tfoot', false, true)){
6566 if(cell.findParent('thead', false, true)){
6568 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6569 cell = Roo.get(t).findParent('th', false, true);
6571 Roo.log("failed to find th in thead?");
6572 Roo.log(e.getTarget());
6577 var cellIndex = cell.dom.cellIndex;
6579 var ename = name == 'touchstart' ? 'click' : name;
6580 this.fireEvent("header" + ename, this, cellIndex, e);
6585 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6586 cell = Roo.get(t).findParent('td', false, true);
6588 Roo.log("failed to find th in tbody?");
6589 Roo.log(e.getTarget());
6594 var row = cell.findParent('tr', false, true);
6595 var cellIndex = cell.dom.cellIndex;
6596 var rowIndex = row.dom.rowIndex - 1;
6600 this.fireEvent("row" + name, this, rowIndex, e);
6604 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6610 onMouseover : function(e, el)
6612 var cell = Roo.get(el);
6618 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6619 cell = cell.findParent('td', false, true);
6622 var row = cell.findParent('tr', false, true);
6623 var cellIndex = cell.dom.cellIndex;
6624 var rowIndex = row.dom.rowIndex - 1; // start from 0
6626 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6630 onMouseout : function(e, el)
6632 var cell = Roo.get(el);
6638 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6639 cell = cell.findParent('td', false, true);
6642 var row = cell.findParent('tr', false, true);
6643 var cellIndex = cell.dom.cellIndex;
6644 var rowIndex = row.dom.rowIndex - 1; // start from 0
6646 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6650 onClick : function(e, el)
6652 var cell = Roo.get(el);
6654 if(!cell || (!this.cellSelection && !this.rowSelection)){
6658 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6659 cell = cell.findParent('td', false, true);
6662 if(!cell || typeof(cell) == 'undefined'){
6666 var row = cell.findParent('tr', false, true);
6668 if(!row || typeof(row) == 'undefined'){
6672 var cellIndex = cell.dom.cellIndex;
6673 var rowIndex = this.getRowIndex(row);
6675 // why??? - should these not be based on SelectionModel?
6676 if(this.cellSelection){
6677 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6680 if(this.rowSelection){
6681 this.fireEvent('rowclick', this, row, rowIndex, e);
6687 onDblClick : function(e,el)
6689 var cell = Roo.get(el);
6691 if(!cell || (!this.cellSelection && !this.rowSelection)){
6695 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6696 cell = cell.findParent('td', false, true);
6699 if(!cell || typeof(cell) == 'undefined'){
6703 var row = cell.findParent('tr', false, true);
6705 if(!row || typeof(row) == 'undefined'){
6709 var cellIndex = cell.dom.cellIndex;
6710 var rowIndex = this.getRowIndex(row);
6712 if(this.cellSelection){
6713 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6716 if(this.rowSelection){
6717 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6721 sort : function(e,el)
6723 var col = Roo.get(el);
6725 if(!col.hasClass('sortable')){
6729 var sort = col.attr('sort');
6732 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6736 this.store.sortInfo = {field : sort, direction : dir};
6739 Roo.log("calling footer first");
6740 this.footer.onClick('first');
6743 this.store.load({ params : { start : 0 } });
6747 renderHeader : function()
6755 this.totalWidth = 0;
6757 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6759 var config = cm.config[i];
6763 cls : 'x-hcol-' + i,
6765 html: cm.getColumnHeader(i)
6770 if(typeof(config.sortable) != 'undefined' && config.sortable){
6772 c.html = '<i class="glyphicon"></i>' + c.html;
6775 if(typeof(config.lgHeader) != 'undefined'){
6776 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6779 if(typeof(config.mdHeader) != 'undefined'){
6780 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6783 if(typeof(config.smHeader) != 'undefined'){
6784 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6787 if(typeof(config.xsHeader) != 'undefined'){
6788 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6795 if(typeof(config.tooltip) != 'undefined'){
6796 c.tooltip = config.tooltip;
6799 if(typeof(config.colspan) != 'undefined'){
6800 c.colspan = config.colspan;
6803 if(typeof(config.hidden) != 'undefined' && config.hidden){
6804 c.style += ' display:none;';
6807 if(typeof(config.dataIndex) != 'undefined'){
6808 c.sort = config.dataIndex;
6813 if(typeof(config.align) != 'undefined' && config.align.length){
6814 c.style += ' text-align:' + config.align + ';';
6817 if(typeof(config.width) != 'undefined'){
6818 c.style += ' width:' + config.width + 'px;';
6819 this.totalWidth += config.width;
6821 this.totalWidth += 100; // assume minimum of 100 per column?
6824 if(typeof(config.cls) != 'undefined'){
6825 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6828 ['xs','sm','md','lg'].map(function(size){
6830 if(typeof(config[size]) == 'undefined'){
6834 if (!config[size]) { // 0 = hidden
6835 c.cls += ' hidden-' + size;
6839 c.cls += ' col-' + size + '-' + config[size];
6849 renderBody : function()
6859 colspan : this.cm.getColumnCount()
6869 renderFooter : function()
6879 colspan : this.cm.getColumnCount()
6893 // Roo.log('ds onload');
6898 var ds = this.store;
6900 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6901 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6902 if (_this.store.sortInfo) {
6904 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6905 e.select('i', true).addClass(['glyphicon-arrow-up']);
6908 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6909 e.select('i', true).addClass(['glyphicon-arrow-down']);
6914 var tbody = this.mainBody;
6916 if(ds.getCount() > 0){
6917 ds.data.each(function(d,rowIndex){
6918 var row = this.renderRow(cm, ds, rowIndex);
6920 tbody.createChild(row);
6924 if(row.cellObjects.length){
6925 Roo.each(row.cellObjects, function(r){
6926 _this.renderCellObject(r);
6933 var tfoot = this.el.select('tfoot', true).first();
6935 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6937 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6939 var total = this.ds.getTotalCount();
6941 if(this.footer.pageSize < total){
6942 this.mainFoot.show();
6946 Roo.each(this.el.select('tbody td', true).elements, function(e){
6947 e.on('mouseover', _this.onMouseover, _this);
6950 Roo.each(this.el.select('tbody td', true).elements, function(e){
6951 e.on('mouseout', _this.onMouseout, _this);
6953 this.fireEvent('rowsrendered', this);
6959 onUpdate : function(ds,record)
6961 this.refreshRow(record);
6965 onRemove : function(ds, record, index, isUpdate){
6966 if(isUpdate !== true){
6967 this.fireEvent("beforerowremoved", this, index, record);
6969 var bt = this.mainBody.dom;
6971 var rows = this.el.select('tbody > tr', true).elements;
6973 if(typeof(rows[index]) != 'undefined'){
6974 bt.removeChild(rows[index].dom);
6977 // if(bt.rows[index]){
6978 // bt.removeChild(bt.rows[index]);
6981 if(isUpdate !== true){
6982 //this.stripeRows(index);
6983 //this.syncRowHeights(index, index);
6985 this.fireEvent("rowremoved", this, index, record);
6989 onAdd : function(ds, records, rowIndex)
6991 //Roo.log('on Add called');
6992 // - note this does not handle multiple adding very well..
6993 var bt = this.mainBody.dom;
6994 for (var i =0 ; i < records.length;i++) {
6995 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
6996 //Roo.log(records[i]);
6997 //Roo.log(this.store.getAt(rowIndex+i));
6998 this.insertRow(this.store, rowIndex + i, false);
7005 refreshRow : function(record){
7006 var ds = this.store, index;
7007 if(typeof record == 'number'){
7009 record = ds.getAt(index);
7011 index = ds.indexOf(record);
7013 this.insertRow(ds, index, true);
7015 this.onRemove(ds, record, index+1, true);
7017 //this.syncRowHeights(index, index);
7019 this.fireEvent("rowupdated", this, index, record);
7022 insertRow : function(dm, rowIndex, isUpdate){
7025 this.fireEvent("beforerowsinserted", this, rowIndex);
7027 //var s = this.getScrollState();
7028 var row = this.renderRow(this.cm, this.store, rowIndex);
7029 // insert before rowIndex..
7030 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7034 if(row.cellObjects.length){
7035 Roo.each(row.cellObjects, function(r){
7036 _this.renderCellObject(r);
7041 this.fireEvent("rowsinserted", this, rowIndex);
7042 //this.syncRowHeights(firstRow, lastRow);
7043 //this.stripeRows(firstRow);
7050 getRowDom : function(rowIndex)
7052 var rows = this.el.select('tbody > tr', true).elements;
7054 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7057 // returns the object tree for a tr..
7060 renderRow : function(cm, ds, rowIndex)
7062 var d = ds.getAt(rowIndex);
7066 cls : 'x-row-' + rowIndex,
7070 var cellObjects = [];
7072 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7073 var config = cm.config[i];
7075 var renderer = cm.getRenderer(i);
7079 if(typeof(renderer) !== 'undefined'){
7080 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7082 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7083 // and are rendered into the cells after the row is rendered - using the id for the element.
7085 if(typeof(value) === 'object'){
7095 rowIndex : rowIndex,
7100 this.fireEvent('rowclass', this, rowcfg);
7104 cls : rowcfg.rowClass + ' x-col-' + i,
7106 html: (typeof(value) === 'object') ? '' : value
7113 if(typeof(config.colspan) != 'undefined'){
7114 td.colspan = config.colspan;
7117 if(typeof(config.hidden) != 'undefined' && config.hidden){
7118 td.style += ' display:none;';
7121 if(typeof(config.align) != 'undefined' && config.align.length){
7122 td.style += ' text-align:' + config.align + ';';
7124 if(typeof(config.valign) != 'undefined' && config.valign.length){
7125 td.style += ' vertical-align:' + config.valign + ';';
7128 if(typeof(config.width) != 'undefined'){
7129 td.style += ' width:' + config.width + 'px;';
7132 if(typeof(config.cursor) != 'undefined'){
7133 td.style += ' cursor:' + config.cursor + ';';
7136 if(typeof(config.cls) != 'undefined'){
7137 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7140 ['xs','sm','md','lg'].map(function(size){
7142 if(typeof(config[size]) == 'undefined'){
7146 if (!config[size]) { // 0 = hidden
7147 td.cls += ' hidden-' + size;
7151 td.cls += ' col-' + size + '-' + config[size];
7159 row.cellObjects = cellObjects;
7167 onBeforeLoad : function()
7176 this.el.select('tbody', true).first().dom.innerHTML = '';
7179 * Show or hide a row.
7180 * @param {Number} rowIndex to show or hide
7181 * @param {Boolean} state hide
7183 setRowVisibility : function(rowIndex, state)
7185 var bt = this.mainBody.dom;
7187 var rows = this.el.select('tbody > tr', true).elements;
7189 if(typeof(rows[rowIndex]) == 'undefined'){
7192 rows[rowIndex].dom.style.display = state ? '' : 'none';
7196 getSelectionModel : function(){
7198 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7200 return this.selModel;
7203 * Render the Roo.bootstrap object from renderder
7205 renderCellObject : function(r)
7209 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7211 var t = r.cfg.render(r.container);
7214 Roo.each(r.cfg.cn, function(c){
7216 container: t.getChildContainer(),
7219 _this.renderCellObject(child);
7224 getRowIndex : function(row)
7228 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7239 * Returns the grid's underlying element = used by panel.Grid
7240 * @return {Element} The element
7242 getGridEl : function(){
7246 * Forces a resize - used by panel.Grid
7247 * @return {Element} The element
7249 autoSize : function()
7251 //var ctr = Roo.get(this.container.dom.parentElement);
7252 var ctr = Roo.get(this.el.dom);
7254 var thd = this.getGridEl().select('thead',true).first();
7255 var tbd = this.getGridEl().select('tbody', true).first();
7256 var tfd = this.getGridEl().select('tfoot', true).first();
7258 var cw = ctr.getWidth();
7262 tbd.setSize(ctr.getWidth(),
7263 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7265 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7268 cw = Math.max(cw, this.totalWidth);
7269 this.getGridEl().select('tr',true).setWidth(cw);
7270 // resize 'expandable coloumn?
7272 return; // we doe not have a view in this design..
7275 onBodyScroll: function()
7277 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7279 this.mainHead.setStyle({
7280 'position' : 'relative',
7281 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7287 var scrollHeight = this.mainBody.dom.scrollHeight;
7289 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7291 var height = this.mainBody.getHeight();
7293 if(scrollHeight - height == scrollTop) {
7295 var total = this.ds.getTotalCount();
7297 if(this.footer.cursor + this.footer.pageSize < total){
7299 this.footer.ds.load({
7301 start : this.footer.cursor + this.footer.pageSize,
7302 limit : this.footer.pageSize
7312 onHeaderChange : function()
7314 var header = this.renderHeader();
7315 var table = this.el.select('table', true).first();
7317 this.mainHead.remove();
7318 this.mainHead = table.createChild(header, this.mainBody, false);
7321 onHiddenChange : function(colModel, colIndex, hidden)
7323 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7324 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7326 this.CSS.updateRule(thSelector, "display", "");
7327 this.CSS.updateRule(tdSelector, "display", "");
7330 this.CSS.updateRule(thSelector, "display", "none");
7331 this.CSS.updateRule(tdSelector, "display", "none");
7334 this.onHeaderChange();
7338 setColumnWidth: function(col_index, width)
7340 // width = "md-2 xs-2..."
7341 if(!this.colModel.config[col_index]) {
7345 var w = width.split(" ");
7347 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7349 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7352 for(var j = 0; j < w.length; j++) {
7358 var size_cls = w[j].split("-");
7360 if(!Number.isInteger(size_cls[1] * 1)) {
7364 if(!this.colModel.config[col_index][size_cls[0]]) {
7368 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7372 h_row[0].classList.replace(
7373 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7374 "col-"+size_cls[0]+"-"+size_cls[1]
7377 for(var i = 0; i < rows.length; i++) {
7379 var size_cls = w[j].split("-");
7381 if(!Number.isInteger(size_cls[1] * 1)) {
7385 if(!this.colModel.config[col_index][size_cls[0]]) {
7389 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7393 rows[i].classList.replace(
7394 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7395 "col-"+size_cls[0]+"-"+size_cls[1]
7399 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7414 * @class Roo.bootstrap.TableCell
7415 * @extends Roo.bootstrap.Component
7416 * Bootstrap TableCell class
7417 * @cfg {String} html cell contain text
7418 * @cfg {String} cls cell class
7419 * @cfg {String} tag cell tag (td|th) default td
7420 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7421 * @cfg {String} align Aligns the content in a cell
7422 * @cfg {String} axis Categorizes cells
7423 * @cfg {String} bgcolor Specifies the background color of a cell
7424 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7425 * @cfg {Number} colspan Specifies the number of columns a cell should span
7426 * @cfg {String} headers Specifies one or more header cells a cell is related to
7427 * @cfg {Number} height Sets the height of a cell
7428 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7429 * @cfg {Number} rowspan Sets the number of rows a cell should span
7430 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7431 * @cfg {String} valign Vertical aligns the content in a cell
7432 * @cfg {Number} width Specifies the width of a cell
7435 * Create a new TableCell
7436 * @param {Object} config The config object
7439 Roo.bootstrap.TableCell = function(config){
7440 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7443 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7463 getAutoCreate : function(){
7464 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7484 cfg.align=this.align
7490 cfg.bgcolor=this.bgcolor
7493 cfg.charoff=this.charoff
7496 cfg.colspan=this.colspan
7499 cfg.headers=this.headers
7502 cfg.height=this.height
7505 cfg.nowrap=this.nowrap
7508 cfg.rowspan=this.rowspan
7511 cfg.scope=this.scope
7514 cfg.valign=this.valign
7517 cfg.width=this.width
7536 * @class Roo.bootstrap.TableRow
7537 * @extends Roo.bootstrap.Component
7538 * Bootstrap TableRow class
7539 * @cfg {String} cls row class
7540 * @cfg {String} align Aligns the content in a table row
7541 * @cfg {String} bgcolor Specifies a background color for a table row
7542 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7543 * @cfg {String} valign Vertical aligns the content in a table row
7546 * Create a new TableRow
7547 * @param {Object} config The config object
7550 Roo.bootstrap.TableRow = function(config){
7551 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7554 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7562 getAutoCreate : function(){
7563 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7573 cfg.align = this.align;
7576 cfg.bgcolor = this.bgcolor;
7579 cfg.charoff = this.charoff;
7582 cfg.valign = this.valign;
7600 * @class Roo.bootstrap.TableBody
7601 * @extends Roo.bootstrap.Component
7602 * Bootstrap TableBody class
7603 * @cfg {String} cls element class
7604 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7605 * @cfg {String} align Aligns the content inside the element
7606 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7607 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7610 * Create a new TableBody
7611 * @param {Object} config The config object
7614 Roo.bootstrap.TableBody = function(config){
7615 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7618 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7626 getAutoCreate : function(){
7627 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7641 cfg.align = this.align;
7644 cfg.charoff = this.charoff;
7647 cfg.valign = this.valign;
7654 // initEvents : function()
7661 // this.store = Roo.factory(this.store, Roo.data);
7662 // this.store.on('load', this.onLoad, this);
7664 // this.store.load();
7668 // onLoad: function ()
7670 // this.fireEvent('load', this);
7680 * Ext JS Library 1.1.1
7681 * Copyright(c) 2006-2007, Ext JS, LLC.
7683 * Originally Released Under LGPL - original licence link has changed is not relivant.
7686 * <script type="text/javascript">
7689 // as we use this in bootstrap.
7690 Roo.namespace('Roo.form');
7692 * @class Roo.form.Action
7693 * Internal Class used to handle form actions
7695 * @param {Roo.form.BasicForm} el The form element or its id
7696 * @param {Object} config Configuration options
7701 // define the action interface
7702 Roo.form.Action = function(form, options){
7704 this.options = options || {};
7707 * Client Validation Failed
7710 Roo.form.Action.CLIENT_INVALID = 'client';
7712 * Server Validation Failed
7715 Roo.form.Action.SERVER_INVALID = 'server';
7717 * Connect to Server Failed
7720 Roo.form.Action.CONNECT_FAILURE = 'connect';
7722 * Reading Data from Server Failed
7725 Roo.form.Action.LOAD_FAILURE = 'load';
7727 Roo.form.Action.prototype = {
7729 failureType : undefined,
7730 response : undefined,
7734 run : function(options){
7739 success : function(response){
7744 handleResponse : function(response){
7748 // default connection failure
7749 failure : function(response){
7751 this.response = response;
7752 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7753 this.form.afterAction(this, false);
7756 processResponse : function(response){
7757 this.response = response;
7758 if(!response.responseText){
7761 this.result = this.handleResponse(response);
7765 // utility functions used internally
7766 getUrl : function(appendParams){
7767 var url = this.options.url || this.form.url || this.form.el.dom.action;
7769 var p = this.getParams();
7771 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7777 getMethod : function(){
7778 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7781 getParams : function(){
7782 var bp = this.form.baseParams;
7783 var p = this.options.params;
7785 if(typeof p == "object"){
7786 p = Roo.urlEncode(Roo.applyIf(p, bp));
7787 }else if(typeof p == 'string' && bp){
7788 p += '&' + Roo.urlEncode(bp);
7791 p = Roo.urlEncode(bp);
7796 createCallback : function(){
7798 success: this.success,
7799 failure: this.failure,
7801 timeout: (this.form.timeout*1000),
7802 upload: this.form.fileUpload ? this.success : undefined
7807 Roo.form.Action.Submit = function(form, options){
7808 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7811 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7814 haveProgress : false,
7815 uploadComplete : false,
7817 // uploadProgress indicator.
7818 uploadProgress : function()
7820 if (!this.form.progressUrl) {
7824 if (!this.haveProgress) {
7825 Roo.MessageBox.progress("Uploading", "Uploading");
7827 if (this.uploadComplete) {
7828 Roo.MessageBox.hide();
7832 this.haveProgress = true;
7834 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7836 var c = new Roo.data.Connection();
7838 url : this.form.progressUrl,
7843 success : function(req){
7844 //console.log(data);
7848 rdata = Roo.decode(req.responseText)
7850 Roo.log("Invalid data from server..");
7854 if (!rdata || !rdata.success) {
7856 Roo.MessageBox.alert(Roo.encode(rdata));
7859 var data = rdata.data;
7861 if (this.uploadComplete) {
7862 Roo.MessageBox.hide();
7867 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7868 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7871 this.uploadProgress.defer(2000,this);
7874 failure: function(data) {
7875 Roo.log('progress url failed ');
7886 // run get Values on the form, so it syncs any secondary forms.
7887 this.form.getValues();
7889 var o = this.options;
7890 var method = this.getMethod();
7891 var isPost = method == 'POST';
7892 if(o.clientValidation === false || this.form.isValid()){
7894 if (this.form.progressUrl) {
7895 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7896 (new Date() * 1) + '' + Math.random());
7901 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7902 form:this.form.el.dom,
7903 url:this.getUrl(!isPost),
7905 params:isPost ? this.getParams() : null,
7906 isUpload: this.form.fileUpload,
7907 formData : this.form.formData
7910 this.uploadProgress();
7912 }else if (o.clientValidation !== false){ // client validation failed
7913 this.failureType = Roo.form.Action.CLIENT_INVALID;
7914 this.form.afterAction(this, false);
7918 success : function(response)
7920 this.uploadComplete= true;
7921 if (this.haveProgress) {
7922 Roo.MessageBox.hide();
7926 var result = this.processResponse(response);
7927 if(result === true || result.success){
7928 this.form.afterAction(this, true);
7932 this.form.markInvalid(result.errors);
7933 this.failureType = Roo.form.Action.SERVER_INVALID;
7935 this.form.afterAction(this, false);
7937 failure : function(response)
7939 this.uploadComplete= true;
7940 if (this.haveProgress) {
7941 Roo.MessageBox.hide();
7944 this.response = response;
7945 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7946 this.form.afterAction(this, false);
7949 handleResponse : function(response){
7950 if(this.form.errorReader){
7951 var rs = this.form.errorReader.read(response);
7954 for(var i = 0, len = rs.records.length; i < len; i++) {
7955 var r = rs.records[i];
7959 if(errors.length < 1){
7963 success : rs.success,
7969 ret = Roo.decode(response.responseText);
7973 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7983 Roo.form.Action.Load = function(form, options){
7984 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7985 this.reader = this.form.reader;
7988 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7993 Roo.Ajax.request(Roo.apply(
7994 this.createCallback(), {
7995 method:this.getMethod(),
7996 url:this.getUrl(false),
7997 params:this.getParams()
8001 success : function(response){
8003 var result = this.processResponse(response);
8004 if(result === true || !result.success || !result.data){
8005 this.failureType = Roo.form.Action.LOAD_FAILURE;
8006 this.form.afterAction(this, false);
8009 this.form.clearInvalid();
8010 this.form.setValues(result.data);
8011 this.form.afterAction(this, true);
8014 handleResponse : function(response){
8015 if(this.form.reader){
8016 var rs = this.form.reader.read(response);
8017 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8019 success : rs.success,
8023 return Roo.decode(response.responseText);
8027 Roo.form.Action.ACTION_TYPES = {
8028 'load' : Roo.form.Action.Load,
8029 'submit' : Roo.form.Action.Submit
8038 * @class Roo.bootstrap.Form
8039 * @extends Roo.bootstrap.Component
8040 * Bootstrap Form class
8041 * @cfg {String} method GET | POST (default POST)
8042 * @cfg {String} labelAlign top | left (default top)
8043 * @cfg {String} align left | right - for navbars
8044 * @cfg {Boolean} loadMask load mask when submit (default true)
8049 * @param {Object} config The config object
8053 Roo.bootstrap.Form = function(config){
8055 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8057 Roo.bootstrap.Form.popover.apply();
8061 * @event clientvalidation
8062 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8063 * @param {Form} this
8064 * @param {Boolean} valid true if the form has passed client-side validation
8066 clientvalidation: true,
8068 * @event beforeaction
8069 * Fires before any action is performed. Return false to cancel the action.
8070 * @param {Form} this
8071 * @param {Action} action The action to be performed
8075 * @event actionfailed
8076 * Fires when an action fails.
8077 * @param {Form} this
8078 * @param {Action} action The action that failed
8080 actionfailed : true,
8082 * @event actioncomplete
8083 * Fires when an action is completed.
8084 * @param {Form} this
8085 * @param {Action} action The action that completed
8087 actioncomplete : true
8091 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8094 * @cfg {String} method
8095 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8100 * The URL to use for form actions if one isn't supplied in the action options.
8103 * @cfg {Boolean} fileUpload
8104 * Set to true if this form is a file upload.
8108 * @cfg {Object} baseParams
8109 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8113 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8117 * @cfg {Sting} align (left|right) for navbar forms
8122 activeAction : null,
8125 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8126 * element by passing it or its id or mask the form itself by passing in true.
8129 waitMsgTarget : false,
8134 * @cfg {Boolean} errorMask (true|false) default false
8139 * @cfg {Number} maskOffset Default 100
8144 * @cfg {Boolean} maskBody
8148 getAutoCreate : function(){
8152 method : this.method || 'POST',
8153 id : this.id || Roo.id(),
8156 if (this.parent().xtype.match(/^Nav/)) {
8157 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8161 if (this.labelAlign == 'left' ) {
8162 cfg.cls += ' form-horizontal';
8168 initEvents : function()
8170 this.el.on('submit', this.onSubmit, this);
8171 // this was added as random key presses on the form where triggering form submit.
8172 this.el.on('keypress', function(e) {
8173 if (e.getCharCode() != 13) {
8176 // we might need to allow it for textareas.. and some other items.
8177 // check e.getTarget().
8179 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8183 Roo.log("keypress blocked");
8191 onSubmit : function(e){
8196 * Returns true if client-side validation on the form is successful.
8199 isValid : function(){
8200 var items = this.getItems();
8204 items.each(function(f){
8210 Roo.log('invalid field: ' + f.name);
8214 if(!target && f.el.isVisible(true)){
8220 if(this.errorMask && !valid){
8221 Roo.bootstrap.Form.popover.mask(this, target);
8228 * Returns true if any fields in this form have changed since their original load.
8231 isDirty : function(){
8233 var items = this.getItems();
8234 items.each(function(f){
8244 * Performs a predefined action (submit or load) or custom actions you define on this form.
8245 * @param {String} actionName The name of the action type
8246 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8247 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8248 * accept other config options):
8250 Property Type Description
8251 ---------------- --------------- ----------------------------------------------------------------------------------
8252 url String The url for the action (defaults to the form's url)
8253 method String The form method to use (defaults to the form's method, or POST if not defined)
8254 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8255 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8256 validate the form on the client (defaults to false)
8258 * @return {BasicForm} this
8260 doAction : function(action, options){
8261 if(typeof action == 'string'){
8262 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8264 if(this.fireEvent('beforeaction', this, action) !== false){
8265 this.beforeAction(action);
8266 action.run.defer(100, action);
8272 beforeAction : function(action){
8273 var o = action.options;
8278 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8280 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8283 // not really supported yet.. ??
8285 //if(this.waitMsgTarget === true){
8286 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8287 //}else if(this.waitMsgTarget){
8288 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8289 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8291 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8297 afterAction : function(action, success){
8298 this.activeAction = null;
8299 var o = action.options;
8304 Roo.get(document.body).unmask();
8310 //if(this.waitMsgTarget === true){
8311 // this.el.unmask();
8312 //}else if(this.waitMsgTarget){
8313 // this.waitMsgTarget.unmask();
8315 // Roo.MessageBox.updateProgress(1);
8316 // Roo.MessageBox.hide();
8323 Roo.callback(o.success, o.scope, [this, action]);
8324 this.fireEvent('actioncomplete', this, action);
8328 // failure condition..
8329 // we have a scenario where updates need confirming.
8330 // eg. if a locking scenario exists..
8331 // we look for { errors : { needs_confirm : true }} in the response.
8333 (typeof(action.result) != 'undefined') &&
8334 (typeof(action.result.errors) != 'undefined') &&
8335 (typeof(action.result.errors.needs_confirm) != 'undefined')
8338 Roo.log("not supported yet");
8341 Roo.MessageBox.confirm(
8342 "Change requires confirmation",
8343 action.result.errorMsg,
8348 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8358 Roo.callback(o.failure, o.scope, [this, action]);
8359 // show an error message if no failed handler is set..
8360 if (!this.hasListener('actionfailed')) {
8361 Roo.log("need to add dialog support");
8363 Roo.MessageBox.alert("Error",
8364 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8365 action.result.errorMsg :
8366 "Saving Failed, please check your entries or try again"
8371 this.fireEvent('actionfailed', this, action);
8376 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8377 * @param {String} id The value to search for
8380 findField : function(id){
8381 var items = this.getItems();
8382 var field = items.get(id);
8384 items.each(function(f){
8385 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8392 return field || null;
8395 * Mark fields in this form invalid in bulk.
8396 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8397 * @return {BasicForm} this
8399 markInvalid : function(errors){
8400 if(errors instanceof Array){
8401 for(var i = 0, len = errors.length; i < len; i++){
8402 var fieldError = errors[i];
8403 var f = this.findField(fieldError.id);
8405 f.markInvalid(fieldError.msg);
8411 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8412 field.markInvalid(errors[id]);
8416 //Roo.each(this.childForms || [], function (f) {
8417 // f.markInvalid(errors);
8424 * Set values for fields in this form in bulk.
8425 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8426 * @return {BasicForm} this
8428 setValues : function(values){
8429 if(values instanceof Array){ // array of objects
8430 for(var i = 0, len = values.length; i < len; i++){
8432 var f = this.findField(v.id);
8434 f.setValue(v.value);
8435 if(this.trackResetOnLoad){
8436 f.originalValue = f.getValue();
8440 }else{ // object hash
8443 if(typeof values[id] != 'function' && (field = this.findField(id))){
8445 if (field.setFromData &&
8447 field.displayField &&
8448 // combos' with local stores can
8449 // be queried via setValue()
8450 // to set their value..
8451 (field.store && !field.store.isLocal)
8455 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8456 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8457 field.setFromData(sd);
8459 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8461 field.setFromData(values);
8464 field.setValue(values[id]);
8468 if(this.trackResetOnLoad){
8469 field.originalValue = field.getValue();
8475 //Roo.each(this.childForms || [], function (f) {
8476 // f.setValues(values);
8483 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8484 * they are returned as an array.
8485 * @param {Boolean} asString
8488 getValues : function(asString){
8489 //if (this.childForms) {
8490 // copy values from the child forms
8491 // Roo.each(this.childForms, function (f) {
8492 // this.setValues(f.getValues());
8498 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8499 if(asString === true){
8502 return Roo.urlDecode(fs);
8506 * Returns the fields in this form as an object with key/value pairs.
8507 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8510 getFieldValues : function(with_hidden)
8512 var items = this.getItems();
8514 items.each(function(f){
8520 var v = f.getValue();
8522 if (f.inputType =='radio') {
8523 if (typeof(ret[f.getName()]) == 'undefined') {
8524 ret[f.getName()] = ''; // empty..
8527 if (!f.el.dom.checked) {
8535 if(f.xtype == 'MoneyField'){
8536 ret[f.currencyName] = f.getCurrency();
8539 // not sure if this supported any more..
8540 if ((typeof(v) == 'object') && f.getRawValue) {
8541 v = f.getRawValue() ; // dates..
8543 // combo boxes where name != hiddenName...
8544 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8545 ret[f.name] = f.getRawValue();
8547 ret[f.getName()] = v;
8554 * Clears all invalid messages in this form.
8555 * @return {BasicForm} this
8557 clearInvalid : function(){
8558 var items = this.getItems();
8560 items.each(function(f){
8569 * @return {BasicForm} this
8572 var items = this.getItems();
8573 items.each(function(f){
8577 Roo.each(this.childForms || [], function (f) {
8585 getItems : function()
8587 var r=new Roo.util.MixedCollection(false, function(o){
8588 return o.id || (o.id = Roo.id());
8590 var iter = function(el) {
8597 Roo.each(el.items,function(e) {
8606 hideFields : function(items)
8608 Roo.each(items, function(i){
8610 var f = this.findField(i);
8621 showFields : function(items)
8623 Roo.each(items, function(i){
8625 var f = this.findField(i);
8638 Roo.apply(Roo.bootstrap.Form, {
8665 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8666 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8667 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8668 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8671 this.maskEl.top.enableDisplayMode("block");
8672 this.maskEl.left.enableDisplayMode("block");
8673 this.maskEl.bottom.enableDisplayMode("block");
8674 this.maskEl.right.enableDisplayMode("block");
8676 this.toolTip = new Roo.bootstrap.Tooltip({
8677 cls : 'roo-form-error-popover',
8679 'left' : ['r-l', [-2,0], 'right'],
8680 'right' : ['l-r', [2,0], 'left'],
8681 'bottom' : ['tl-bl', [0,2], 'top'],
8682 'top' : [ 'bl-tl', [0,-2], 'bottom']
8686 this.toolTip.render(Roo.get(document.body));
8688 this.toolTip.el.enableDisplayMode("block");
8690 Roo.get(document.body).on('click', function(){
8694 Roo.get(document.body).on('touchstart', function(){
8698 this.isApplied = true
8701 mask : function(form, target)
8705 this.target = target;
8707 if(!this.form.errorMask || !target.el){
8711 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8713 Roo.log(scrollable);
8715 var ot = this.target.el.calcOffsetsTo(scrollable);
8717 var scrollTo = ot[1] - this.form.maskOffset;
8719 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8721 scrollable.scrollTo('top', scrollTo);
8723 var box = this.target.el.getBox();
8725 var zIndex = Roo.bootstrap.Modal.zIndex++;
8728 this.maskEl.top.setStyle('position', 'absolute');
8729 this.maskEl.top.setStyle('z-index', zIndex);
8730 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8731 this.maskEl.top.setLeft(0);
8732 this.maskEl.top.setTop(0);
8733 this.maskEl.top.show();
8735 this.maskEl.left.setStyle('position', 'absolute');
8736 this.maskEl.left.setStyle('z-index', zIndex);
8737 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8738 this.maskEl.left.setLeft(0);
8739 this.maskEl.left.setTop(box.y - this.padding);
8740 this.maskEl.left.show();
8742 this.maskEl.bottom.setStyle('position', 'absolute');
8743 this.maskEl.bottom.setStyle('z-index', zIndex);
8744 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8745 this.maskEl.bottom.setLeft(0);
8746 this.maskEl.bottom.setTop(box.bottom + this.padding);
8747 this.maskEl.bottom.show();
8749 this.maskEl.right.setStyle('position', 'absolute');
8750 this.maskEl.right.setStyle('z-index', zIndex);
8751 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8752 this.maskEl.right.setLeft(box.right + this.padding);
8753 this.maskEl.right.setTop(box.y - this.padding);
8754 this.maskEl.right.show();
8756 this.toolTip.bindEl = this.target.el;
8758 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8760 var tip = this.target.blankText;
8762 if(this.target.getValue() !== '' ) {
8764 if (this.target.invalidText.length) {
8765 tip = this.target.invalidText;
8766 } else if (this.target.regexText.length){
8767 tip = this.target.regexText;
8771 this.toolTip.show(tip);
8773 this.intervalID = window.setInterval(function() {
8774 Roo.bootstrap.Form.popover.unmask();
8777 window.onwheel = function(){ return false;};
8779 (function(){ this.isMasked = true; }).defer(500, this);
8785 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8789 this.maskEl.top.setStyle('position', 'absolute');
8790 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8791 this.maskEl.top.hide();
8793 this.maskEl.left.setStyle('position', 'absolute');
8794 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8795 this.maskEl.left.hide();
8797 this.maskEl.bottom.setStyle('position', 'absolute');
8798 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8799 this.maskEl.bottom.hide();
8801 this.maskEl.right.setStyle('position', 'absolute');
8802 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8803 this.maskEl.right.hide();
8805 this.toolTip.hide();
8807 this.toolTip.el.hide();
8809 window.onwheel = function(){ return true;};
8811 if(this.intervalID){
8812 window.clearInterval(this.intervalID);
8813 this.intervalID = false;
8816 this.isMasked = false;
8826 * Ext JS Library 1.1.1
8827 * Copyright(c) 2006-2007, Ext JS, LLC.
8829 * Originally Released Under LGPL - original licence link has changed is not relivant.
8832 * <script type="text/javascript">
8835 * @class Roo.form.VTypes
8836 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8839 Roo.form.VTypes = function(){
8840 // closure these in so they are only created once.
8841 var alpha = /^[a-zA-Z_]+$/;
8842 var alphanum = /^[a-zA-Z0-9_]+$/;
8843 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8844 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8846 // All these messages and functions are configurable
8849 * The function used to validate email addresses
8850 * @param {String} value The email address
8852 'email' : function(v){
8853 return email.test(v);
8856 * The error text to display when the email validation function returns false
8859 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8861 * The keystroke filter mask to be applied on email input
8864 'emailMask' : /[a-z0-9_\.\-@]/i,
8867 * The function used to validate URLs
8868 * @param {String} value The URL
8870 'url' : function(v){
8874 * The error text to display when the url validation function returns false
8877 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8880 * The function used to validate alpha values
8881 * @param {String} value The value
8883 'alpha' : function(v){
8884 return alpha.test(v);
8887 * The error text to display when the alpha validation function returns false
8890 'alphaText' : 'This field should only contain letters and _',
8892 * The keystroke filter mask to be applied on alpha input
8895 'alphaMask' : /[a-z_]/i,
8898 * The function used to validate alphanumeric values
8899 * @param {String} value The value
8901 'alphanum' : function(v){
8902 return alphanum.test(v);
8905 * The error text to display when the alphanumeric validation function returns false
8908 'alphanumText' : 'This field should only contain letters, numbers and _',
8910 * The keystroke filter mask to be applied on alphanumeric input
8913 'alphanumMask' : /[a-z0-9_]/i
8923 * @class Roo.bootstrap.Input
8924 * @extends Roo.bootstrap.Component
8925 * Bootstrap Input class
8926 * @cfg {Boolean} disabled is it disabled
8927 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8928 * @cfg {String} name name of the input
8929 * @cfg {string} fieldLabel - the label associated
8930 * @cfg {string} placeholder - placeholder to put in text.
8931 * @cfg {string} before - input group add on before
8932 * @cfg {string} after - input group add on after
8933 * @cfg {string} size - (lg|sm) or leave empty..
8934 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8935 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8936 * @cfg {Number} md colspan out of 12 for computer-sized screens
8937 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8938 * @cfg {string} value default value of the input
8939 * @cfg {Number} labelWidth set the width of label
8940 * @cfg {Number} labellg set the width of label (1-12)
8941 * @cfg {Number} labelmd set the width of label (1-12)
8942 * @cfg {Number} labelsm set the width of label (1-12)
8943 * @cfg {Number} labelxs set the width of label (1-12)
8944 * @cfg {String} labelAlign (top|left)
8945 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8946 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8947 * @cfg {String} indicatorpos (left|right) default left
8948 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8949 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8951 * @cfg {String} align (left|center|right) Default left
8952 * @cfg {Boolean} forceFeedback (true|false) Default false
8955 * Create a new Input
8956 * @param {Object} config The config object
8959 Roo.bootstrap.Input = function(config){
8961 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8966 * Fires when this field receives input focus.
8967 * @param {Roo.form.Field} this
8972 * Fires when this field loses input focus.
8973 * @param {Roo.form.Field} this
8978 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8979 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8980 * @param {Roo.form.Field} this
8981 * @param {Roo.EventObject} e The event object
8986 * Fires just before the field blurs if the field value has changed.
8987 * @param {Roo.form.Field} this
8988 * @param {Mixed} newValue The new value
8989 * @param {Mixed} oldValue The original value
8994 * Fires after the field has been marked as invalid.
8995 * @param {Roo.form.Field} this
8996 * @param {String} msg The validation message
9001 * Fires after the field has been validated with no errors.
9002 * @param {Roo.form.Field} this
9007 * Fires after the key up
9008 * @param {Roo.form.Field} this
9009 * @param {Roo.EventObject} e The event Object
9015 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9017 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9018 automatic validation (defaults to "keyup").
9020 validationEvent : "keyup",
9022 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9024 validateOnBlur : true,
9026 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9028 validationDelay : 250,
9030 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9032 focusClass : "x-form-focus", // not needed???
9036 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9038 invalidClass : "has-warning",
9041 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9043 validClass : "has-success",
9046 * @cfg {Boolean} hasFeedback (true|false) default true
9051 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9053 invalidFeedbackClass : "glyphicon-warning-sign",
9056 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9058 validFeedbackClass : "glyphicon-ok",
9061 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9063 selectOnFocus : false,
9066 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9070 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9075 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9077 disableKeyFilter : false,
9080 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9084 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9088 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9090 blankText : "Please complete this mandatory field",
9093 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9097 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9099 maxLength : Number.MAX_VALUE,
9101 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9103 minLengthText : "The minimum length for this field is {0}",
9105 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9107 maxLengthText : "The maximum length for this field is {0}",
9111 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9112 * If available, this function will be called only after the basic validators all return true, and will be passed the
9113 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9117 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9118 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9119 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9123 * @cfg {String} regexText -- Depricated - use Invalid Text
9128 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9134 autocomplete: false,
9153 formatedValue : false,
9154 forceFeedback : false,
9156 indicatorpos : 'left',
9166 parentLabelAlign : function()
9169 while (parent.parent()) {
9170 parent = parent.parent();
9171 if (typeof(parent.labelAlign) !='undefined') {
9172 return parent.labelAlign;
9179 getAutoCreate : function()
9181 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9187 if(this.inputType != 'hidden'){
9188 cfg.cls = 'form-group' //input-group
9194 type : this.inputType,
9196 cls : 'form-control',
9197 placeholder : this.placeholder || '',
9198 autocomplete : this.autocomplete || 'new-password'
9201 if(this.capture.length){
9202 input.capture = this.capture;
9205 if(this.accept.length){
9206 input.accept = this.accept + "/*";
9210 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9213 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9214 input.maxLength = this.maxLength;
9217 if (this.disabled) {
9218 input.disabled=true;
9221 if (this.readOnly) {
9222 input.readonly=true;
9226 input.name = this.name;
9230 input.cls += ' input-' + this.size;
9234 ['xs','sm','md','lg'].map(function(size){
9235 if (settings[size]) {
9236 cfg.cls += ' col-' + size + '-' + settings[size];
9240 var inputblock = input;
9244 cls: 'glyphicon form-control-feedback'
9247 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9250 cls : 'has-feedback',
9258 if (this.before || this.after) {
9261 cls : 'input-group',
9265 if (this.before && typeof(this.before) == 'string') {
9267 inputblock.cn.push({
9269 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9273 if (this.before && typeof(this.before) == 'object') {
9274 this.before = Roo.factory(this.before);
9276 inputblock.cn.push({
9278 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9279 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9283 inputblock.cn.push(input);
9285 if (this.after && typeof(this.after) == 'string') {
9286 inputblock.cn.push({
9288 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9292 if (this.after && typeof(this.after) == 'object') {
9293 this.after = Roo.factory(this.after);
9295 inputblock.cn.push({
9297 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9298 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9302 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9303 inputblock.cls += ' has-feedback';
9304 inputblock.cn.push(feedback);
9309 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9310 tooltip : 'This field is required'
9312 if (Roo.bootstrap.version == 4) {
9315 style : 'display-none'
9318 if (align ==='left' && this.fieldLabel.length) {
9320 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9327 cls : 'control-label col-form-label',
9328 html : this.fieldLabel
9339 var labelCfg = cfg.cn[1];
9340 var contentCfg = cfg.cn[2];
9342 if(this.indicatorpos == 'right'){
9347 cls : 'control-label col-form-label',
9351 html : this.fieldLabel
9365 labelCfg = cfg.cn[0];
9366 contentCfg = cfg.cn[1];
9370 if(this.labelWidth > 12){
9371 labelCfg.style = "width: " + this.labelWidth + 'px';
9374 if(this.labelWidth < 13 && this.labelmd == 0){
9375 this.labelmd = this.labelWidth;
9378 if(this.labellg > 0){
9379 labelCfg.cls += ' col-lg-' + this.labellg;
9380 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9383 if(this.labelmd > 0){
9384 labelCfg.cls += ' col-md-' + this.labelmd;
9385 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9388 if(this.labelsm > 0){
9389 labelCfg.cls += ' col-sm-' + this.labelsm;
9390 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9393 if(this.labelxs > 0){
9394 labelCfg.cls += ' col-xs-' + this.labelxs;
9395 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9399 } else if ( this.fieldLabel.length) {
9404 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9405 tooltip : 'This field is required'
9409 //cls : 'input-group-addon',
9410 html : this.fieldLabel
9418 if(this.indicatorpos == 'right'){
9423 //cls : 'input-group-addon',
9424 html : this.fieldLabel
9429 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9430 tooltip : 'This field is required'
9450 if (this.parentType === 'Navbar' && this.parent().bar) {
9451 cfg.cls += ' navbar-form';
9454 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9455 // on BS4 we do this only if not form
9456 cfg.cls += ' navbar-form';
9464 * return the real input element.
9466 inputEl: function ()
9468 return this.el.select('input.form-control',true).first();
9471 tooltipEl : function()
9473 return this.inputEl();
9476 indicatorEl : function()
9478 if (Roo.bootstrap.version == 4) {
9479 return false; // not enabled in v4 yet.
9482 var indicator = this.el.select('i.roo-required-indicator',true).first();
9492 setDisabled : function(v)
9494 var i = this.inputEl().dom;
9496 i.removeAttribute('disabled');
9500 i.setAttribute('disabled','true');
9502 initEvents : function()
9505 this.inputEl().on("keydown" , this.fireKey, this);
9506 this.inputEl().on("focus", this.onFocus, this);
9507 this.inputEl().on("blur", this.onBlur, this);
9509 this.inputEl().relayEvent('keyup', this);
9511 this.indicator = this.indicatorEl();
9514 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9517 // reference to original value for reset
9518 this.originalValue = this.getValue();
9519 //Roo.form.TextField.superclass.initEvents.call(this);
9520 if(this.validationEvent == 'keyup'){
9521 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9522 this.inputEl().on('keyup', this.filterValidation, this);
9524 else if(this.validationEvent !== false){
9525 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9528 if(this.selectOnFocus){
9529 this.on("focus", this.preFocus, this);
9532 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9533 this.inputEl().on("keypress", this.filterKeys, this);
9535 this.inputEl().relayEvent('keypress', this);
9538 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9539 this.el.on("click", this.autoSize, this);
9542 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9543 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9546 if (typeof(this.before) == 'object') {
9547 this.before.render(this.el.select('.roo-input-before',true).first());
9549 if (typeof(this.after) == 'object') {
9550 this.after.render(this.el.select('.roo-input-after',true).first());
9553 this.inputEl().on('change', this.onChange, this);
9556 filterValidation : function(e){
9557 if(!e.isNavKeyPress()){
9558 this.validationTask.delay(this.validationDelay);
9562 * Validates the field value
9563 * @return {Boolean} True if the value is valid, else false
9565 validate : function(){
9566 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9567 if(this.disabled || this.validateValue(this.getRawValue())){
9578 * Validates a value according to the field's validation rules and marks the field as invalid
9579 * if the validation fails
9580 * @param {Mixed} value The value to validate
9581 * @return {Boolean} True if the value is valid, else false
9583 validateValue : function(value)
9585 if(this.getVisibilityEl().hasClass('hidden')){
9589 if(value.length < 1) { // if it's blank
9590 if(this.allowBlank){
9596 if(value.length < this.minLength){
9599 if(value.length > this.maxLength){
9603 var vt = Roo.form.VTypes;
9604 if(!vt[this.vtype](value, this)){
9608 if(typeof this.validator == "function"){
9609 var msg = this.validator(value);
9613 if (typeof(msg) == 'string') {
9614 this.invalidText = msg;
9618 if(this.regex && !this.regex.test(value)){
9626 fireKey : function(e){
9627 //Roo.log('field ' + e.getKey());
9628 if(e.isNavKeyPress()){
9629 this.fireEvent("specialkey", this, e);
9632 focus : function (selectText){
9634 this.inputEl().focus();
9635 if(selectText === true){
9636 this.inputEl().dom.select();
9642 onFocus : function(){
9643 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9644 // this.el.addClass(this.focusClass);
9647 this.hasFocus = true;
9648 this.startValue = this.getValue();
9649 this.fireEvent("focus", this);
9653 beforeBlur : Roo.emptyFn,
9657 onBlur : function(){
9659 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9660 //this.el.removeClass(this.focusClass);
9662 this.hasFocus = false;
9663 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9666 var v = this.getValue();
9667 if(String(v) !== String(this.startValue)){
9668 this.fireEvent('change', this, v, this.startValue);
9670 this.fireEvent("blur", this);
9673 onChange : function(e)
9675 var v = this.getValue();
9676 if(String(v) !== String(this.startValue)){
9677 this.fireEvent('change', this, v, this.startValue);
9683 * Resets the current field value to the originally loaded value and clears any validation messages
9686 this.setValue(this.originalValue);
9690 * Returns the name of the field
9691 * @return {Mixed} name The name field
9693 getName: function(){
9697 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9698 * @return {Mixed} value The field value
9700 getValue : function(){
9702 var v = this.inputEl().getValue();
9707 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9708 * @return {Mixed} value The field value
9710 getRawValue : function(){
9711 var v = this.inputEl().getValue();
9717 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9718 * @param {Mixed} value The value to set
9720 setRawValue : function(v){
9721 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9724 selectText : function(start, end){
9725 var v = this.getRawValue();
9727 start = start === undefined ? 0 : start;
9728 end = end === undefined ? v.length : end;
9729 var d = this.inputEl().dom;
9730 if(d.setSelectionRange){
9731 d.setSelectionRange(start, end);
9732 }else if(d.createTextRange){
9733 var range = d.createTextRange();
9734 range.moveStart("character", start);
9735 range.moveEnd("character", v.length-end);
9742 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9743 * @param {Mixed} value The value to set
9745 setValue : function(v){
9748 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9754 processValue : function(value){
9755 if(this.stripCharsRe){
9756 var newValue = value.replace(this.stripCharsRe, '');
9757 if(newValue !== value){
9758 this.setRawValue(newValue);
9765 preFocus : function(){
9767 if(this.selectOnFocus){
9768 this.inputEl().dom.select();
9771 filterKeys : function(e){
9773 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9776 var c = e.getCharCode(), cc = String.fromCharCode(c);
9777 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9780 if(!this.maskRe.test(cc)){
9785 * Clear any invalid styles/messages for this field
9787 clearInvalid : function(){
9789 if(!this.el || this.preventMark){ // not rendered
9794 this.el.removeClass([this.invalidClass, 'is-invalid']);
9796 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9798 var feedback = this.el.select('.form-control-feedback', true).first();
9801 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9807 this.indicator.removeClass('visible');
9808 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9811 this.fireEvent('valid', this);
9815 * Mark this field as valid
9817 markValid : function()
9819 if(!this.el || this.preventMark){ // not rendered...
9823 this.el.removeClass([this.invalidClass, this.validClass]);
9824 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9826 var feedback = this.el.select('.form-control-feedback', true).first();
9829 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9833 this.indicator.removeClass('visible');
9834 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9841 if(this.allowBlank && !this.getRawValue().length){
9844 if (Roo.bootstrap.version == 3) {
9845 this.el.addClass(this.validClass);
9847 this.inputEl().addClass('is-valid');
9850 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9852 var feedback = this.el.select('.form-control-feedback', true).first();
9855 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9856 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9861 this.fireEvent('valid', this);
9865 * Mark this field as invalid
9866 * @param {String} msg The validation message
9868 markInvalid : function(msg)
9870 if(!this.el || this.preventMark){ // not rendered
9874 this.el.removeClass([this.invalidClass, this.validClass]);
9875 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9877 var feedback = this.el.select('.form-control-feedback', true).first();
9880 this.el.select('.form-control-feedback', true).first().removeClass(
9881 [this.invalidFeedbackClass, this.validFeedbackClass]);
9888 if(this.allowBlank && !this.getRawValue().length){
9893 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9894 this.indicator.addClass('visible');
9896 if (Roo.bootstrap.version == 3) {
9897 this.el.addClass(this.invalidClass);
9899 this.inputEl().addClass('is-invalid');
9904 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9906 var feedback = this.el.select('.form-control-feedback', true).first();
9909 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9911 if(this.getValue().length || this.forceFeedback){
9912 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9919 this.fireEvent('invalid', this, msg);
9922 SafariOnKeyDown : function(event)
9924 // this is a workaround for a password hang bug on chrome/ webkit.
9925 if (this.inputEl().dom.type != 'password') {
9929 var isSelectAll = false;
9931 if(this.inputEl().dom.selectionEnd > 0){
9932 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9934 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9935 event.preventDefault();
9940 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9942 event.preventDefault();
9943 // this is very hacky as keydown always get's upper case.
9945 var cc = String.fromCharCode(event.getCharCode());
9946 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9950 adjustWidth : function(tag, w){
9951 tag = tag.toLowerCase();
9952 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9953 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9957 if(tag == 'textarea'){
9960 }else if(Roo.isOpera){
9964 if(tag == 'textarea'){
9972 setFieldLabel : function(v)
9978 if(this.indicatorEl()){
9979 var ar = this.el.select('label > span',true);
9981 if (ar.elements.length) {
9982 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9983 this.fieldLabel = v;
9987 var br = this.el.select('label',true);
9989 if(br.elements.length) {
9990 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9991 this.fieldLabel = v;
9995 Roo.log('Cannot Found any of label > span || label in input');
9999 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10000 this.fieldLabel = v;
10015 * @class Roo.bootstrap.TextArea
10016 * @extends Roo.bootstrap.Input
10017 * Bootstrap TextArea class
10018 * @cfg {Number} cols Specifies the visible width of a text area
10019 * @cfg {Number} rows Specifies the visible number of lines in a text area
10020 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10021 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10022 * @cfg {string} html text
10025 * Create a new TextArea
10026 * @param {Object} config The config object
10029 Roo.bootstrap.TextArea = function(config){
10030 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10034 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10044 getAutoCreate : function(){
10046 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10052 if(this.inputType != 'hidden'){
10053 cfg.cls = 'form-group' //input-group
10061 value : this.value || '',
10062 html: this.html || '',
10063 cls : 'form-control',
10064 placeholder : this.placeholder || ''
10068 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10069 input.maxLength = this.maxLength;
10073 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10077 input.cols = this.cols;
10080 if (this.readOnly) {
10081 input.readonly = true;
10085 input.name = this.name;
10089 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10093 ['xs','sm','md','lg'].map(function(size){
10094 if (settings[size]) {
10095 cfg.cls += ' col-' + size + '-' + settings[size];
10099 var inputblock = input;
10101 if(this.hasFeedback && !this.allowBlank){
10105 cls: 'glyphicon form-control-feedback'
10109 cls : 'has-feedback',
10118 if (this.before || this.after) {
10121 cls : 'input-group',
10125 inputblock.cn.push({
10127 cls : 'input-group-addon',
10132 inputblock.cn.push(input);
10134 if(this.hasFeedback && !this.allowBlank){
10135 inputblock.cls += ' has-feedback';
10136 inputblock.cn.push(feedback);
10140 inputblock.cn.push({
10142 cls : 'input-group-addon',
10149 if (align ==='left' && this.fieldLabel.length) {
10154 cls : 'control-label',
10155 html : this.fieldLabel
10166 if(this.labelWidth > 12){
10167 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10170 if(this.labelWidth < 13 && this.labelmd == 0){
10171 this.labelmd = this.labelWidth;
10174 if(this.labellg > 0){
10175 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10176 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10179 if(this.labelmd > 0){
10180 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10181 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10184 if(this.labelsm > 0){
10185 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10186 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10189 if(this.labelxs > 0){
10190 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10191 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10194 } else if ( this.fieldLabel.length) {
10199 //cls : 'input-group-addon',
10200 html : this.fieldLabel
10218 if (this.disabled) {
10219 input.disabled=true;
10226 * return the real textarea element.
10228 inputEl: function ()
10230 return this.el.select('textarea.form-control',true).first();
10234 * Clear any invalid styles/messages for this field
10236 clearInvalid : function()
10239 if(!this.el || this.preventMark){ // not rendered
10243 var label = this.el.select('label', true).first();
10244 var icon = this.el.select('i.fa-star', true).first();
10249 this.el.removeClass( this.validClass);
10250 this.inputEl().removeClass('is-invalid');
10252 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10254 var feedback = this.el.select('.form-control-feedback', true).first();
10257 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10262 this.fireEvent('valid', this);
10266 * Mark this field as valid
10268 markValid : function()
10270 if(!this.el || this.preventMark){ // not rendered
10274 this.el.removeClass([this.invalidClass, this.validClass]);
10275 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10277 var feedback = this.el.select('.form-control-feedback', true).first();
10280 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10283 if(this.disabled || this.allowBlank){
10287 var label = this.el.select('label', true).first();
10288 var icon = this.el.select('i.fa-star', true).first();
10293 if (Roo.bootstrap.version == 3) {
10294 this.el.addClass(this.validClass);
10296 this.inputEl().addClass('is-valid');
10300 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10302 var feedback = this.el.select('.form-control-feedback', true).first();
10305 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10306 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10311 this.fireEvent('valid', this);
10315 * Mark this field as invalid
10316 * @param {String} msg The validation message
10318 markInvalid : function(msg)
10320 if(!this.el || this.preventMark){ // not rendered
10324 this.el.removeClass([this.invalidClass, this.validClass]);
10325 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10327 var feedback = this.el.select('.form-control-feedback', true).first();
10330 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10333 if(this.disabled || this.allowBlank){
10337 var label = this.el.select('label', true).first();
10338 var icon = this.el.select('i.fa-star', true).first();
10340 if(!this.getValue().length && label && !icon){
10341 this.el.createChild({
10343 cls : 'text-danger fa fa-lg fa-star',
10344 tooltip : 'This field is required',
10345 style : 'margin-right:5px;'
10349 if (Roo.bootstrap.version == 3) {
10350 this.el.addClass(this.invalidClass);
10352 this.inputEl().addClass('is-invalid');
10355 // fixme ... this may be depricated need to test..
10356 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10358 var feedback = this.el.select('.form-control-feedback', true).first();
10361 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10363 if(this.getValue().length || this.forceFeedback){
10364 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10371 this.fireEvent('invalid', this, msg);
10379 * trigger field - base class for combo..
10384 * @class Roo.bootstrap.TriggerField
10385 * @extends Roo.bootstrap.Input
10386 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10387 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10388 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10389 * for which you can provide a custom implementation. For example:
10391 var trigger = new Roo.bootstrap.TriggerField();
10392 trigger.onTriggerClick = myTriggerFn;
10393 trigger.applyTo('my-field');
10396 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10397 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10398 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10399 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10400 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10403 * Create a new TriggerField.
10404 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10405 * to the base TextField)
10407 Roo.bootstrap.TriggerField = function(config){
10408 this.mimicing = false;
10409 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10412 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10414 * @cfg {String} triggerClass A CSS class to apply to the trigger
10417 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10422 * @cfg {Boolean} removable (true|false) special filter default false
10426 /** @cfg {Boolean} grow @hide */
10427 /** @cfg {Number} growMin @hide */
10428 /** @cfg {Number} growMax @hide */
10434 autoSize: Roo.emptyFn,
10438 deferHeight : true,
10441 actionMode : 'wrap',
10446 getAutoCreate : function(){
10448 var align = this.labelAlign || this.parentLabelAlign();
10453 cls: 'form-group' //input-group
10460 type : this.inputType,
10461 cls : 'form-control',
10462 autocomplete: 'new-password',
10463 placeholder : this.placeholder || ''
10467 input.name = this.name;
10470 input.cls += ' input-' + this.size;
10473 if (this.disabled) {
10474 input.disabled=true;
10477 var inputblock = input;
10479 if(this.hasFeedback && !this.allowBlank){
10483 cls: 'glyphicon form-control-feedback'
10486 if(this.removable && !this.editable && !this.tickable){
10488 cls : 'has-feedback',
10494 cls : 'roo-combo-removable-btn close'
10501 cls : 'has-feedback',
10510 if(this.removable && !this.editable && !this.tickable){
10512 cls : 'roo-removable',
10518 cls : 'roo-combo-removable-btn close'
10525 if (this.before || this.after) {
10528 cls : 'input-group',
10532 inputblock.cn.push({
10534 cls : 'input-group-addon input-group-prepend input-group-text',
10539 inputblock.cn.push(input);
10541 if(this.hasFeedback && !this.allowBlank){
10542 inputblock.cls += ' has-feedback';
10543 inputblock.cn.push(feedback);
10547 inputblock.cn.push({
10549 cls : 'input-group-addon input-group-append input-group-text',
10558 var ibwrap = inputblock;
10563 cls: 'roo-select2-choices',
10567 cls: 'roo-select2-search-field',
10579 cls: 'roo-select2-container input-group',
10584 cls: 'form-hidden-field'
10590 if(!this.multiple && this.showToggleBtn){
10596 if (this.caret != false) {
10599 cls: 'fa fa-' + this.caret
10606 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10611 cls: 'combobox-clear',
10625 combobox.cls += ' roo-select2-container-multi';
10629 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10630 tooltip : 'This field is required'
10632 if (Roo.bootstrap.version == 4) {
10635 style : 'display:none'
10640 if (align ==='left' && this.fieldLabel.length) {
10642 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10649 cls : 'control-label',
10650 html : this.fieldLabel
10662 var labelCfg = cfg.cn[1];
10663 var contentCfg = cfg.cn[2];
10665 if(this.indicatorpos == 'right'){
10670 cls : 'control-label',
10674 html : this.fieldLabel
10688 labelCfg = cfg.cn[0];
10689 contentCfg = cfg.cn[1];
10692 if(this.labelWidth > 12){
10693 labelCfg.style = "width: " + this.labelWidth + 'px';
10696 if(this.labelWidth < 13 && this.labelmd == 0){
10697 this.labelmd = this.labelWidth;
10700 if(this.labellg > 0){
10701 labelCfg.cls += ' col-lg-' + this.labellg;
10702 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10705 if(this.labelmd > 0){
10706 labelCfg.cls += ' col-md-' + this.labelmd;
10707 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10710 if(this.labelsm > 0){
10711 labelCfg.cls += ' col-sm-' + this.labelsm;
10712 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10715 if(this.labelxs > 0){
10716 labelCfg.cls += ' col-xs-' + this.labelxs;
10717 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10720 } else if ( this.fieldLabel.length) {
10721 // Roo.log(" label");
10726 //cls : 'input-group-addon',
10727 html : this.fieldLabel
10735 if(this.indicatorpos == 'right'){
10743 html : this.fieldLabel
10757 // Roo.log(" no label && no align");
10764 ['xs','sm','md','lg'].map(function(size){
10765 if (settings[size]) {
10766 cfg.cls += ' col-' + size + '-' + settings[size];
10777 onResize : function(w, h){
10778 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10779 // if(typeof w == 'number'){
10780 // var x = w - this.trigger.getWidth();
10781 // this.inputEl().setWidth(this.adjustWidth('input', x));
10782 // this.trigger.setStyle('left', x+'px');
10787 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10790 getResizeEl : function(){
10791 return this.inputEl();
10795 getPositionEl : function(){
10796 return this.inputEl();
10800 alignErrorIcon : function(){
10801 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10805 initEvents : function(){
10809 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10810 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10811 if(!this.multiple && this.showToggleBtn){
10812 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10813 if(this.hideTrigger){
10814 this.trigger.setDisplayed(false);
10816 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10820 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10823 if(this.removable && !this.editable && !this.tickable){
10824 var close = this.closeTriggerEl();
10827 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10828 close.on('click', this.removeBtnClick, this, close);
10832 //this.trigger.addClassOnOver('x-form-trigger-over');
10833 //this.trigger.addClassOnClick('x-form-trigger-click');
10836 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10840 closeTriggerEl : function()
10842 var close = this.el.select('.roo-combo-removable-btn', true).first();
10843 return close ? close : false;
10846 removeBtnClick : function(e, h, el)
10848 e.preventDefault();
10850 if(this.fireEvent("remove", this) !== false){
10852 this.fireEvent("afterremove", this)
10856 createList : function()
10858 this.list = Roo.get(document.body).createChild({
10859 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10860 cls: 'typeahead typeahead-long dropdown-menu',
10861 style: 'display:none'
10864 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10869 initTrigger : function(){
10874 onDestroy : function(){
10876 this.trigger.removeAllListeners();
10877 // this.trigger.remove();
10880 // this.wrap.remove();
10882 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10886 onFocus : function(){
10887 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10889 if(!this.mimicing){
10890 this.wrap.addClass('x-trigger-wrap-focus');
10891 this.mimicing = true;
10892 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10893 if(this.monitorTab){
10894 this.el.on("keydown", this.checkTab, this);
10901 checkTab : function(e){
10902 if(e.getKey() == e.TAB){
10903 this.triggerBlur();
10908 onBlur : function(){
10913 mimicBlur : function(e, t){
10915 if(!this.wrap.contains(t) && this.validateBlur()){
10916 this.triggerBlur();
10922 triggerBlur : function(){
10923 this.mimicing = false;
10924 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10925 if(this.monitorTab){
10926 this.el.un("keydown", this.checkTab, this);
10928 //this.wrap.removeClass('x-trigger-wrap-focus');
10929 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10933 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10934 validateBlur : function(e, t){
10939 onDisable : function(){
10940 this.inputEl().dom.disabled = true;
10941 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10943 // this.wrap.addClass('x-item-disabled');
10948 onEnable : function(){
10949 this.inputEl().dom.disabled = false;
10950 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10952 // this.el.removeClass('x-item-disabled');
10957 onShow : function(){
10958 var ae = this.getActionEl();
10961 ae.dom.style.display = '';
10962 ae.dom.style.visibility = 'visible';
10968 onHide : function(){
10969 var ae = this.getActionEl();
10970 ae.dom.style.display = 'none';
10974 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10975 * by an implementing function.
10977 * @param {EventObject} e
10979 onTriggerClick : Roo.emptyFn
10983 * Ext JS Library 1.1.1
10984 * Copyright(c) 2006-2007, Ext JS, LLC.
10986 * Originally Released Under LGPL - original licence link has changed is not relivant.
10989 * <script type="text/javascript">
10994 * @class Roo.data.SortTypes
10996 * Defines the default sorting (casting?) comparison functions used when sorting data.
10998 Roo.data.SortTypes = {
11000 * Default sort that does nothing
11001 * @param {Mixed} s The value being converted
11002 * @return {Mixed} The comparison value
11004 none : function(s){
11009 * The regular expression used to strip tags
11013 stripTagsRE : /<\/?[^>]+>/gi,
11016 * Strips all HTML tags to sort on text only
11017 * @param {Mixed} s The value being converted
11018 * @return {String} The comparison value
11020 asText : function(s){
11021 return String(s).replace(this.stripTagsRE, "");
11025 * Strips all HTML tags to sort on text only - Case insensitive
11026 * @param {Mixed} s The value being converted
11027 * @return {String} The comparison value
11029 asUCText : function(s){
11030 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11034 * Case insensitive string
11035 * @param {Mixed} s The value being converted
11036 * @return {String} The comparison value
11038 asUCString : function(s) {
11039 return String(s).toUpperCase();
11044 * @param {Mixed} s The value being converted
11045 * @return {Number} The comparison value
11047 asDate : function(s) {
11051 if(s instanceof Date){
11052 return s.getTime();
11054 return Date.parse(String(s));
11059 * @param {Mixed} s The value being converted
11060 * @return {Float} The comparison value
11062 asFloat : function(s) {
11063 var val = parseFloat(String(s).replace(/,/g, ""));
11072 * @param {Mixed} s The value being converted
11073 * @return {Number} The comparison value
11075 asInt : function(s) {
11076 var val = parseInt(String(s).replace(/,/g, ""));
11084 * Ext JS Library 1.1.1
11085 * Copyright(c) 2006-2007, Ext JS, LLC.
11087 * Originally Released Under LGPL - original licence link has changed is not relivant.
11090 * <script type="text/javascript">
11094 * @class Roo.data.Record
11095 * Instances of this class encapsulate both record <em>definition</em> information, and record
11096 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11097 * to access Records cached in an {@link Roo.data.Store} object.<br>
11099 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11100 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11103 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11105 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11106 * {@link #create}. The parameters are the same.
11107 * @param {Array} data An associative Array of data values keyed by the field name.
11108 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11109 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11110 * not specified an integer id is generated.
11112 Roo.data.Record = function(data, id){
11113 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11118 * Generate a constructor for a specific record layout.
11119 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11120 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11121 * Each field definition object may contain the following properties: <ul>
11122 * <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,
11123 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11124 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11125 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11126 * is being used, then this is a string containing the javascript expression to reference the data relative to
11127 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11128 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11129 * this may be omitted.</p></li>
11130 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11131 * <ul><li>auto (Default, implies no conversion)</li>
11136 * <li>date</li></ul></p></li>
11137 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11138 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11139 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11140 * by the Reader into an object that will be stored in the Record. It is passed the
11141 * following parameters:<ul>
11142 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11144 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11146 * <br>usage:<br><pre><code>
11147 var TopicRecord = Roo.data.Record.create(
11148 {name: 'title', mapping: 'topic_title'},
11149 {name: 'author', mapping: 'username'},
11150 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11151 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11152 {name: 'lastPoster', mapping: 'user2'},
11153 {name: 'excerpt', mapping: 'post_text'}
11156 var myNewRecord = new TopicRecord({
11157 title: 'Do my job please',
11160 lastPost: new Date(),
11161 lastPoster: 'Animal',
11162 excerpt: 'No way dude!'
11164 myStore.add(myNewRecord);
11169 Roo.data.Record.create = function(o){
11170 var f = function(){
11171 f.superclass.constructor.apply(this, arguments);
11173 Roo.extend(f, Roo.data.Record);
11174 var p = f.prototype;
11175 p.fields = new Roo.util.MixedCollection(false, function(field){
11178 for(var i = 0, len = o.length; i < len; i++){
11179 p.fields.add(new Roo.data.Field(o[i]));
11181 f.getField = function(name){
11182 return p.fields.get(name);
11187 Roo.data.Record.AUTO_ID = 1000;
11188 Roo.data.Record.EDIT = 'edit';
11189 Roo.data.Record.REJECT = 'reject';
11190 Roo.data.Record.COMMIT = 'commit';
11192 Roo.data.Record.prototype = {
11194 * Readonly flag - true if this record has been modified.
11203 join : function(store){
11204 this.store = store;
11208 * Set the named field to the specified value.
11209 * @param {String} name The name of the field to set.
11210 * @param {Object} value The value to set the field to.
11212 set : function(name, value){
11213 if(this.data[name] == value){
11217 if(!this.modified){
11218 this.modified = {};
11220 if(typeof this.modified[name] == 'undefined'){
11221 this.modified[name] = this.data[name];
11223 this.data[name] = value;
11224 if(!this.editing && this.store){
11225 this.store.afterEdit(this);
11230 * Get the value of the named field.
11231 * @param {String} name The name of the field to get the value of.
11232 * @return {Object} The value of the field.
11234 get : function(name){
11235 return this.data[name];
11239 beginEdit : function(){
11240 this.editing = true;
11241 this.modified = {};
11245 cancelEdit : function(){
11246 this.editing = false;
11247 delete this.modified;
11251 endEdit : function(){
11252 this.editing = false;
11253 if(this.dirty && this.store){
11254 this.store.afterEdit(this);
11259 * Usually called by the {@link Roo.data.Store} which owns the Record.
11260 * Rejects all changes made to the Record since either creation, or the last commit operation.
11261 * Modified fields are reverted to their original values.
11263 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11264 * of reject operations.
11266 reject : function(){
11267 var m = this.modified;
11269 if(typeof m[n] != "function"){
11270 this.data[n] = m[n];
11273 this.dirty = false;
11274 delete this.modified;
11275 this.editing = false;
11277 this.store.afterReject(this);
11282 * Usually called by the {@link Roo.data.Store} which owns the Record.
11283 * Commits all changes made to the Record since either creation, or the last commit operation.
11285 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11286 * of commit operations.
11288 commit : function(){
11289 this.dirty = false;
11290 delete this.modified;
11291 this.editing = false;
11293 this.store.afterCommit(this);
11298 hasError : function(){
11299 return this.error != null;
11303 clearError : function(){
11308 * Creates a copy of this record.
11309 * @param {String} id (optional) A new record id if you don't want to use this record's id
11312 copy : function(newId) {
11313 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11317 * Ext JS Library 1.1.1
11318 * Copyright(c) 2006-2007, Ext JS, LLC.
11320 * Originally Released Under LGPL - original licence link has changed is not relivant.
11323 * <script type="text/javascript">
11329 * @class Roo.data.Store
11330 * @extends Roo.util.Observable
11331 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11332 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11334 * 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
11335 * has no knowledge of the format of the data returned by the Proxy.<br>
11337 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11338 * instances from the data object. These records are cached and made available through accessor functions.
11340 * Creates a new Store.
11341 * @param {Object} config A config object containing the objects needed for the Store to access data,
11342 * and read the data into Records.
11344 Roo.data.Store = function(config){
11345 this.data = new Roo.util.MixedCollection(false);
11346 this.data.getKey = function(o){
11349 this.baseParams = {};
11351 this.paramNames = {
11356 "multisort" : "_multisort"
11359 if(config && config.data){
11360 this.inlineData = config.data;
11361 delete config.data;
11364 Roo.apply(this, config);
11366 if(this.reader){ // reader passed
11367 this.reader = Roo.factory(this.reader, Roo.data);
11368 this.reader.xmodule = this.xmodule || false;
11369 if(!this.recordType){
11370 this.recordType = this.reader.recordType;
11372 if(this.reader.onMetaChange){
11373 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11377 if(this.recordType){
11378 this.fields = this.recordType.prototype.fields;
11380 this.modified = [];
11384 * @event datachanged
11385 * Fires when the data cache has changed, and a widget which is using this Store
11386 * as a Record cache should refresh its view.
11387 * @param {Store} this
11389 datachanged : true,
11391 * @event metachange
11392 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11393 * @param {Store} this
11394 * @param {Object} meta The JSON metadata
11399 * Fires when Records have been added to the Store
11400 * @param {Store} this
11401 * @param {Roo.data.Record[]} records The array of Records added
11402 * @param {Number} index The index at which the record(s) were added
11407 * Fires when a Record has been removed from the Store
11408 * @param {Store} this
11409 * @param {Roo.data.Record} record The Record that was removed
11410 * @param {Number} index The index at which the record was removed
11415 * Fires when a Record has been updated
11416 * @param {Store} this
11417 * @param {Roo.data.Record} record The Record that was updated
11418 * @param {String} operation The update operation being performed. Value may be one of:
11420 Roo.data.Record.EDIT
11421 Roo.data.Record.REJECT
11422 Roo.data.Record.COMMIT
11428 * Fires when the data cache has been cleared.
11429 * @param {Store} this
11433 * @event beforeload
11434 * Fires before a request is made for a new data object. If the beforeload handler returns false
11435 * the load action will be canceled.
11436 * @param {Store} this
11437 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11441 * @event beforeloadadd
11442 * Fires after a new set of Records has been loaded.
11443 * @param {Store} this
11444 * @param {Roo.data.Record[]} records The Records that were loaded
11445 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11447 beforeloadadd : true,
11450 * Fires after a new set of Records has been loaded, before they are added to the store.
11451 * @param {Store} this
11452 * @param {Roo.data.Record[]} records The Records that were loaded
11453 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11454 * @params {Object} return from reader
11458 * @event loadexception
11459 * Fires if an exception occurs in the Proxy during loading.
11460 * Called with the signature of the Proxy's "loadexception" event.
11461 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11464 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11465 * @param {Object} load options
11466 * @param {Object} jsonData from your request (normally this contains the Exception)
11468 loadexception : true
11472 this.proxy = Roo.factory(this.proxy, Roo.data);
11473 this.proxy.xmodule = this.xmodule || false;
11474 this.relayEvents(this.proxy, ["loadexception"]);
11476 this.sortToggle = {};
11477 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11479 Roo.data.Store.superclass.constructor.call(this);
11481 if(this.inlineData){
11482 this.loadData(this.inlineData);
11483 delete this.inlineData;
11487 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11489 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11490 * without a remote query - used by combo/forms at present.
11494 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11497 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11500 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11501 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11504 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11505 * on any HTTP request
11508 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11511 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11515 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11516 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11518 remoteSort : false,
11521 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11522 * loaded or when a record is removed. (defaults to false).
11524 pruneModifiedRecords : false,
11527 lastOptions : null,
11530 * Add Records to the Store and fires the add event.
11531 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11533 add : function(records){
11534 records = [].concat(records);
11535 for(var i = 0, len = records.length; i < len; i++){
11536 records[i].join(this);
11538 var index = this.data.length;
11539 this.data.addAll(records);
11540 this.fireEvent("add", this, records, index);
11544 * Remove a Record from the Store and fires the remove event.
11545 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11547 remove : function(record){
11548 var index = this.data.indexOf(record);
11549 this.data.removeAt(index);
11551 if(this.pruneModifiedRecords){
11552 this.modified.remove(record);
11554 this.fireEvent("remove", this, record, index);
11558 * Remove all Records from the Store and fires the clear event.
11560 removeAll : function(){
11562 if(this.pruneModifiedRecords){
11563 this.modified = [];
11565 this.fireEvent("clear", this);
11569 * Inserts Records to the Store at the given index and fires the add event.
11570 * @param {Number} index The start index at which to insert the passed Records.
11571 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11573 insert : function(index, records){
11574 records = [].concat(records);
11575 for(var i = 0, len = records.length; i < len; i++){
11576 this.data.insert(index, records[i]);
11577 records[i].join(this);
11579 this.fireEvent("add", this, records, index);
11583 * Get the index within the cache of the passed Record.
11584 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11585 * @return {Number} The index of the passed Record. Returns -1 if not found.
11587 indexOf : function(record){
11588 return this.data.indexOf(record);
11592 * Get the index within the cache of the Record with the passed id.
11593 * @param {String} id The id of the Record to find.
11594 * @return {Number} The index of the Record. Returns -1 if not found.
11596 indexOfId : function(id){
11597 return this.data.indexOfKey(id);
11601 * Get the Record with the specified id.
11602 * @param {String} id The id of the Record to find.
11603 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11605 getById : function(id){
11606 return this.data.key(id);
11610 * Get the Record at the specified index.
11611 * @param {Number} index The index of the Record to find.
11612 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11614 getAt : function(index){
11615 return this.data.itemAt(index);
11619 * Returns a range of Records between specified indices.
11620 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11621 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11622 * @return {Roo.data.Record[]} An array of Records
11624 getRange : function(start, end){
11625 return this.data.getRange(start, end);
11629 storeOptions : function(o){
11630 o = Roo.apply({}, o);
11633 this.lastOptions = o;
11637 * Loads the Record cache from the configured Proxy using the configured Reader.
11639 * If using remote paging, then the first load call must specify the <em>start</em>
11640 * and <em>limit</em> properties in the options.params property to establish the initial
11641 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11643 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11644 * and this call will return before the new data has been loaded. Perform any post-processing
11645 * in a callback function, or in a "load" event handler.</strong>
11647 * @param {Object} options An object containing properties which control loading options:<ul>
11648 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11649 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11650 * passed the following arguments:<ul>
11651 * <li>r : Roo.data.Record[]</li>
11652 * <li>options: Options object from the load call</li>
11653 * <li>success: Boolean success indicator</li></ul></li>
11654 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11655 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11658 load : function(options){
11659 options = options || {};
11660 if(this.fireEvent("beforeload", this, options) !== false){
11661 this.storeOptions(options);
11662 var p = Roo.apply(options.params || {}, this.baseParams);
11663 // if meta was not loaded from remote source.. try requesting it.
11664 if (!this.reader.metaFromRemote) {
11665 p._requestMeta = 1;
11667 if(this.sortInfo && this.remoteSort){
11668 var pn = this.paramNames;
11669 p[pn["sort"]] = this.sortInfo.field;
11670 p[pn["dir"]] = this.sortInfo.direction;
11672 if (this.multiSort) {
11673 var pn = this.paramNames;
11674 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11677 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11682 * Reloads the Record cache from the configured Proxy using the configured Reader and
11683 * the options from the last load operation performed.
11684 * @param {Object} options (optional) An object containing properties which may override the options
11685 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11686 * the most recently used options are reused).
11688 reload : function(options){
11689 this.load(Roo.applyIf(options||{}, this.lastOptions));
11693 // Called as a callback by the Reader during a load operation.
11694 loadRecords : function(o, options, success){
11695 if(!o || success === false){
11696 if(success !== false){
11697 this.fireEvent("load", this, [], options, o);
11699 if(options.callback){
11700 options.callback.call(options.scope || this, [], options, false);
11704 // if data returned failure - throw an exception.
11705 if (o.success === false) {
11706 // show a message if no listener is registered.
11707 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11708 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11710 // loadmask wil be hooked into this..
11711 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11714 var r = o.records, t = o.totalRecords || r.length;
11716 this.fireEvent("beforeloadadd", this, r, options, o);
11718 if(!options || options.add !== true){
11719 if(this.pruneModifiedRecords){
11720 this.modified = [];
11722 for(var i = 0, len = r.length; i < len; i++){
11726 this.data = this.snapshot;
11727 delete this.snapshot;
11730 this.data.addAll(r);
11731 this.totalLength = t;
11733 this.fireEvent("datachanged", this);
11735 this.totalLength = Math.max(t, this.data.length+r.length);
11739 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11741 var e = new Roo.data.Record({});
11743 e.set(this.parent.displayField, this.parent.emptyTitle);
11744 e.set(this.parent.valueField, '');
11749 this.fireEvent("load", this, r, options, o);
11750 if(options.callback){
11751 options.callback.call(options.scope || this, r, options, true);
11757 * Loads data from a passed data block. A Reader which understands the format of the data
11758 * must have been configured in the constructor.
11759 * @param {Object} data The data block from which to read the Records. The format of the data expected
11760 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11761 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11763 loadData : function(o, append){
11764 var r = this.reader.readRecords(o);
11765 this.loadRecords(r, {add: append}, true);
11769 * Gets the number of cached records.
11771 * <em>If using paging, this may not be the total size of the dataset. If the data object
11772 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11773 * the data set size</em>
11775 getCount : function(){
11776 return this.data.length || 0;
11780 * Gets the total number of records in the dataset as returned by the server.
11782 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11783 * the dataset size</em>
11785 getTotalCount : function(){
11786 return this.totalLength || 0;
11790 * Returns the sort state of the Store as an object with two properties:
11792 field {String} The name of the field by which the Records are sorted
11793 direction {String} The sort order, "ASC" or "DESC"
11796 getSortState : function(){
11797 return this.sortInfo;
11801 applySort : function(){
11802 if(this.sortInfo && !this.remoteSort){
11803 var s = this.sortInfo, f = s.field;
11804 var st = this.fields.get(f).sortType;
11805 var fn = function(r1, r2){
11806 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11807 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11809 this.data.sort(s.direction, fn);
11810 if(this.snapshot && this.snapshot != this.data){
11811 this.snapshot.sort(s.direction, fn);
11817 * Sets the default sort column and order to be used by the next load operation.
11818 * @param {String} fieldName The name of the field to sort by.
11819 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11821 setDefaultSort : function(field, dir){
11822 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11826 * Sort the Records.
11827 * If remote sorting is used, the sort is performed on the server, and the cache is
11828 * reloaded. If local sorting is used, the cache is sorted internally.
11829 * @param {String} fieldName The name of the field to sort by.
11830 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11832 sort : function(fieldName, dir){
11833 var f = this.fields.get(fieldName);
11835 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11837 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11838 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11843 this.sortToggle[f.name] = dir;
11844 this.sortInfo = {field: f.name, direction: dir};
11845 if(!this.remoteSort){
11847 this.fireEvent("datachanged", this);
11849 this.load(this.lastOptions);
11854 * Calls the specified function for each of the Records in the cache.
11855 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11856 * Returning <em>false</em> aborts and exits the iteration.
11857 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11859 each : function(fn, scope){
11860 this.data.each(fn, scope);
11864 * Gets all records modified since the last commit. Modified records are persisted across load operations
11865 * (e.g., during paging).
11866 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11868 getModifiedRecords : function(){
11869 return this.modified;
11873 createFilterFn : function(property, value, anyMatch){
11874 if(!value.exec){ // not a regex
11875 value = String(value);
11876 if(value.length == 0){
11879 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11881 return function(r){
11882 return value.test(r.data[property]);
11887 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11888 * @param {String} property A field on your records
11889 * @param {Number} start The record index to start at (defaults to 0)
11890 * @param {Number} end The last record index to include (defaults to length - 1)
11891 * @return {Number} The sum
11893 sum : function(property, start, end){
11894 var rs = this.data.items, v = 0;
11895 start = start || 0;
11896 end = (end || end === 0) ? end : rs.length-1;
11898 for(var i = start; i <= end; i++){
11899 v += (rs[i].data[property] || 0);
11905 * Filter the records by a specified property.
11906 * @param {String} field A field on your records
11907 * @param {String/RegExp} value Either a string that the field
11908 * should start with or a RegExp to test against the field
11909 * @param {Boolean} anyMatch True to match any part not just the beginning
11911 filter : function(property, value, anyMatch){
11912 var fn = this.createFilterFn(property, value, anyMatch);
11913 return fn ? this.filterBy(fn) : this.clearFilter();
11917 * Filter by a function. The specified function will be called with each
11918 * record in this data source. If the function returns true the record is included,
11919 * otherwise it is filtered.
11920 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11921 * @param {Object} scope (optional) The scope of the function (defaults to this)
11923 filterBy : function(fn, scope){
11924 this.snapshot = this.snapshot || this.data;
11925 this.data = this.queryBy(fn, scope||this);
11926 this.fireEvent("datachanged", this);
11930 * Query the records by a specified property.
11931 * @param {String} field A field on your records
11932 * @param {String/RegExp} value Either a string that the field
11933 * should start with or a RegExp to test against the field
11934 * @param {Boolean} anyMatch True to match any part not just the beginning
11935 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11937 query : function(property, value, anyMatch){
11938 var fn = this.createFilterFn(property, value, anyMatch);
11939 return fn ? this.queryBy(fn) : this.data.clone();
11943 * Query by a function. The specified function will be called with each
11944 * record in this data source. If the function returns true the record is included
11946 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11947 * @param {Object} scope (optional) The scope of the function (defaults to this)
11948 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11950 queryBy : function(fn, scope){
11951 var data = this.snapshot || this.data;
11952 return data.filterBy(fn, scope||this);
11956 * Collects unique values for a particular dataIndex from this store.
11957 * @param {String} dataIndex The property to collect
11958 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11959 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11960 * @return {Array} An array of the unique values
11962 collect : function(dataIndex, allowNull, bypassFilter){
11963 var d = (bypassFilter === true && this.snapshot) ?
11964 this.snapshot.items : this.data.items;
11965 var v, sv, r = [], l = {};
11966 for(var i = 0, len = d.length; i < len; i++){
11967 v = d[i].data[dataIndex];
11969 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11978 * Revert to a view of the Record cache with no filtering applied.
11979 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11981 clearFilter : function(suppressEvent){
11982 if(this.snapshot && this.snapshot != this.data){
11983 this.data = this.snapshot;
11984 delete this.snapshot;
11985 if(suppressEvent !== true){
11986 this.fireEvent("datachanged", this);
11992 afterEdit : function(record){
11993 if(this.modified.indexOf(record) == -1){
11994 this.modified.push(record);
11996 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12000 afterReject : function(record){
12001 this.modified.remove(record);
12002 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12006 afterCommit : function(record){
12007 this.modified.remove(record);
12008 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12012 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12013 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12015 commitChanges : function(){
12016 var m = this.modified.slice(0);
12017 this.modified = [];
12018 for(var i = 0, len = m.length; i < len; i++){
12024 * Cancel outstanding changes on all changed records.
12026 rejectChanges : function(){
12027 var m = this.modified.slice(0);
12028 this.modified = [];
12029 for(var i = 0, len = m.length; i < len; i++){
12034 onMetaChange : function(meta, rtype, o){
12035 this.recordType = rtype;
12036 this.fields = rtype.prototype.fields;
12037 delete this.snapshot;
12038 this.sortInfo = meta.sortInfo || this.sortInfo;
12039 this.modified = [];
12040 this.fireEvent('metachange', this, this.reader.meta);
12043 moveIndex : function(data, type)
12045 var index = this.indexOf(data);
12047 var newIndex = index + type;
12051 this.insert(newIndex, data);
12056 * Ext JS Library 1.1.1
12057 * Copyright(c) 2006-2007, Ext JS, LLC.
12059 * Originally Released Under LGPL - original licence link has changed is not relivant.
12062 * <script type="text/javascript">
12066 * @class Roo.data.SimpleStore
12067 * @extends Roo.data.Store
12068 * Small helper class to make creating Stores from Array data easier.
12069 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12070 * @cfg {Array} fields An array of field definition objects, or field name strings.
12071 * @cfg {Array} data The multi-dimensional array of data
12073 * @param {Object} config
12075 Roo.data.SimpleStore = function(config){
12076 Roo.data.SimpleStore.superclass.constructor.call(this, {
12078 reader: new Roo.data.ArrayReader({
12081 Roo.data.Record.create(config.fields)
12083 proxy : new Roo.data.MemoryProxy(config.data)
12087 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12089 * Ext JS Library 1.1.1
12090 * Copyright(c) 2006-2007, Ext JS, LLC.
12092 * Originally Released Under LGPL - original licence link has changed is not relivant.
12095 * <script type="text/javascript">
12100 * @extends Roo.data.Store
12101 * @class Roo.data.JsonStore
12102 * Small helper class to make creating Stores for JSON data easier. <br/>
12104 var store = new Roo.data.JsonStore({
12105 url: 'get-images.php',
12107 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12110 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12111 * JsonReader and HttpProxy (unless inline data is provided).</b>
12112 * @cfg {Array} fields An array of field definition objects, or field name strings.
12114 * @param {Object} config
12116 Roo.data.JsonStore = function(c){
12117 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12118 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12119 reader: new Roo.data.JsonReader(c, c.fields)
12122 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12124 * Ext JS Library 1.1.1
12125 * Copyright(c) 2006-2007, Ext JS, LLC.
12127 * Originally Released Under LGPL - original licence link has changed is not relivant.
12130 * <script type="text/javascript">
12134 Roo.data.Field = function(config){
12135 if(typeof config == "string"){
12136 config = {name: config};
12138 Roo.apply(this, config);
12141 this.type = "auto";
12144 var st = Roo.data.SortTypes;
12145 // named sortTypes are supported, here we look them up
12146 if(typeof this.sortType == "string"){
12147 this.sortType = st[this.sortType];
12150 // set default sortType for strings and dates
12151 if(!this.sortType){
12154 this.sortType = st.asUCString;
12157 this.sortType = st.asDate;
12160 this.sortType = st.none;
12165 var stripRe = /[\$,%]/g;
12167 // prebuilt conversion function for this field, instead of
12168 // switching every time we're reading a value
12170 var cv, dateFormat = this.dateFormat;
12175 cv = function(v){ return v; };
12178 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12182 return v !== undefined && v !== null && v !== '' ?
12183 parseInt(String(v).replace(stripRe, ""), 10) : '';
12188 return v !== undefined && v !== null && v !== '' ?
12189 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12194 cv = function(v){ return v === true || v === "true" || v == 1; };
12201 if(v instanceof Date){
12205 if(dateFormat == "timestamp"){
12206 return new Date(v*1000);
12208 return Date.parseDate(v, dateFormat);
12210 var parsed = Date.parse(v);
12211 return parsed ? new Date(parsed) : null;
12220 Roo.data.Field.prototype = {
12228 * Ext JS Library 1.1.1
12229 * Copyright(c) 2006-2007, Ext JS, LLC.
12231 * Originally Released Under LGPL - original licence link has changed is not relivant.
12234 * <script type="text/javascript">
12237 // Base class for reading structured data from a data source. This class is intended to be
12238 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12241 * @class Roo.data.DataReader
12242 * Base class for reading structured data from a data source. This class is intended to be
12243 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12246 Roo.data.DataReader = function(meta, recordType){
12250 this.recordType = recordType instanceof Array ?
12251 Roo.data.Record.create(recordType) : recordType;
12254 Roo.data.DataReader.prototype = {
12256 * Create an empty record
12257 * @param {Object} data (optional) - overlay some values
12258 * @return {Roo.data.Record} record created.
12260 newRow : function(d) {
12262 this.recordType.prototype.fields.each(function(c) {
12264 case 'int' : da[c.name] = 0; break;
12265 case 'date' : da[c.name] = new Date(); break;
12266 case 'float' : da[c.name] = 0.0; break;
12267 case 'boolean' : da[c.name] = false; break;
12268 default : da[c.name] = ""; break;
12272 return new this.recordType(Roo.apply(da, d));
12277 * Ext JS Library 1.1.1
12278 * Copyright(c) 2006-2007, Ext JS, LLC.
12280 * Originally Released Under LGPL - original licence link has changed is not relivant.
12283 * <script type="text/javascript">
12287 * @class Roo.data.DataProxy
12288 * @extends Roo.data.Observable
12289 * This class is an abstract base class for implementations which provide retrieval of
12290 * unformatted data objects.<br>
12292 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12293 * (of the appropriate type which knows how to parse the data object) to provide a block of
12294 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12296 * Custom implementations must implement the load method as described in
12297 * {@link Roo.data.HttpProxy#load}.
12299 Roo.data.DataProxy = function(){
12302 * @event beforeload
12303 * Fires before a network request is made to retrieve a data object.
12304 * @param {Object} This DataProxy object.
12305 * @param {Object} params The params parameter to the load function.
12310 * Fires before the load method's callback is called.
12311 * @param {Object} This DataProxy object.
12312 * @param {Object} o The data object.
12313 * @param {Object} arg The callback argument object passed to the load function.
12317 * @event loadexception
12318 * Fires if an Exception occurs during data retrieval.
12319 * @param {Object} This DataProxy object.
12320 * @param {Object} o The data object.
12321 * @param {Object} arg The callback argument object passed to the load function.
12322 * @param {Object} e The Exception.
12324 loadexception : true
12326 Roo.data.DataProxy.superclass.constructor.call(this);
12329 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12332 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12336 * Ext JS Library 1.1.1
12337 * Copyright(c) 2006-2007, Ext JS, LLC.
12339 * Originally Released Under LGPL - original licence link has changed is not relivant.
12342 * <script type="text/javascript">
12345 * @class Roo.data.MemoryProxy
12346 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12347 * to the Reader when its load method is called.
12349 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12351 Roo.data.MemoryProxy = function(data){
12355 Roo.data.MemoryProxy.superclass.constructor.call(this);
12359 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12362 * Load data from the requested source (in this case an in-memory
12363 * data object passed to the constructor), read the data object into
12364 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12365 * process that block using the passed callback.
12366 * @param {Object} params This parameter is not used by the MemoryProxy class.
12367 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12368 * object into a block of Roo.data.Records.
12369 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12370 * The function must be passed <ul>
12371 * <li>The Record block object</li>
12372 * <li>The "arg" argument from the load function</li>
12373 * <li>A boolean success indicator</li>
12375 * @param {Object} scope The scope in which to call the callback
12376 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12378 load : function(params, reader, callback, scope, arg){
12379 params = params || {};
12382 result = reader.readRecords(params.data || this.data);
12384 this.fireEvent("loadexception", this, arg, null, e);
12385 callback.call(scope, null, arg, false);
12388 callback.call(scope, result, arg, true);
12392 update : function(params, records){
12397 * Ext JS Library 1.1.1
12398 * Copyright(c) 2006-2007, Ext JS, LLC.
12400 * Originally Released Under LGPL - original licence link has changed is not relivant.
12403 * <script type="text/javascript">
12406 * @class Roo.data.HttpProxy
12407 * @extends Roo.data.DataProxy
12408 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12409 * configured to reference a certain URL.<br><br>
12411 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12412 * from which the running page was served.<br><br>
12414 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12416 * Be aware that to enable the browser to parse an XML document, the server must set
12417 * the Content-Type header in the HTTP response to "text/xml".
12419 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12420 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12421 * will be used to make the request.
12423 Roo.data.HttpProxy = function(conn){
12424 Roo.data.HttpProxy.superclass.constructor.call(this);
12425 // is conn a conn config or a real conn?
12427 this.useAjax = !conn || !conn.events;
12431 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12432 // thse are take from connection...
12435 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12438 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12439 * extra parameters to each request made by this object. (defaults to undefined)
12442 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12443 * to each request made by this object. (defaults to undefined)
12446 * @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)
12449 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12452 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12458 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12462 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12463 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12464 * a finer-grained basis than the DataProxy events.
12466 getConnection : function(){
12467 return this.useAjax ? Roo.Ajax : this.conn;
12471 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12472 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12473 * process that block using the passed callback.
12474 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12475 * for the request to the remote server.
12476 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12477 * object into a block of Roo.data.Records.
12478 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12479 * The function must be passed <ul>
12480 * <li>The Record block object</li>
12481 * <li>The "arg" argument from the load function</li>
12482 * <li>A boolean success indicator</li>
12484 * @param {Object} scope The scope in which to call the callback
12485 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12487 load : function(params, reader, callback, scope, arg){
12488 if(this.fireEvent("beforeload", this, params) !== false){
12490 params : params || {},
12492 callback : callback,
12497 callback : this.loadResponse,
12501 Roo.applyIf(o, this.conn);
12502 if(this.activeRequest){
12503 Roo.Ajax.abort(this.activeRequest);
12505 this.activeRequest = Roo.Ajax.request(o);
12507 this.conn.request(o);
12510 callback.call(scope||this, null, arg, false);
12515 loadResponse : function(o, success, response){
12516 delete this.activeRequest;
12518 this.fireEvent("loadexception", this, o, response);
12519 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12524 result = o.reader.read(response);
12526 this.fireEvent("loadexception", this, o, response, e);
12527 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12531 this.fireEvent("load", this, o, o.request.arg);
12532 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12536 update : function(dataSet){
12541 updateResponse : function(dataSet){
12546 * Ext JS Library 1.1.1
12547 * Copyright(c) 2006-2007, Ext JS, LLC.
12549 * Originally Released Under LGPL - original licence link has changed is not relivant.
12552 * <script type="text/javascript">
12556 * @class Roo.data.ScriptTagProxy
12557 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12558 * other than the originating domain of the running page.<br><br>
12560 * <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
12561 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12563 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12564 * source code that is used as the source inside a <script> tag.<br><br>
12566 * In order for the browser to process the returned data, the server must wrap the data object
12567 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12568 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12569 * depending on whether the callback name was passed:
12572 boolean scriptTag = false;
12573 String cb = request.getParameter("callback");
12576 response.setContentType("text/javascript");
12578 response.setContentType("application/x-json");
12580 Writer out = response.getWriter();
12582 out.write(cb + "(");
12584 out.print(dataBlock.toJsonString());
12591 * @param {Object} config A configuration object.
12593 Roo.data.ScriptTagProxy = function(config){
12594 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12595 Roo.apply(this, config);
12596 this.head = document.getElementsByTagName("head")[0];
12599 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12601 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12603 * @cfg {String} url The URL from which to request the data object.
12606 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12610 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12611 * the server the name of the callback function set up by the load call to process the returned data object.
12612 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12613 * javascript output which calls this named function passing the data object as its only parameter.
12615 callbackParam : "callback",
12617 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12618 * name to the request.
12623 * Load data from the configured URL, read the data object into
12624 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12625 * process that block using the passed callback.
12626 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12627 * for the request to the remote server.
12628 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12629 * object into a block of Roo.data.Records.
12630 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12631 * The function must be passed <ul>
12632 * <li>The Record block object</li>
12633 * <li>The "arg" argument from the load function</li>
12634 * <li>A boolean success indicator</li>
12636 * @param {Object} scope The scope in which to call the callback
12637 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12639 load : function(params, reader, callback, scope, arg){
12640 if(this.fireEvent("beforeload", this, params) !== false){
12642 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12644 var url = this.url;
12645 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12647 url += "&_dc=" + (new Date().getTime());
12649 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12652 cb : "stcCallback"+transId,
12653 scriptId : "stcScript"+transId,
12657 callback : callback,
12663 window[trans.cb] = function(o){
12664 conn.handleResponse(o, trans);
12667 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12669 if(this.autoAbort !== false){
12673 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12675 var script = document.createElement("script");
12676 script.setAttribute("src", url);
12677 script.setAttribute("type", "text/javascript");
12678 script.setAttribute("id", trans.scriptId);
12679 this.head.appendChild(script);
12681 this.trans = trans;
12683 callback.call(scope||this, null, arg, false);
12688 isLoading : function(){
12689 return this.trans ? true : false;
12693 * Abort the current server request.
12695 abort : function(){
12696 if(this.isLoading()){
12697 this.destroyTrans(this.trans);
12702 destroyTrans : function(trans, isLoaded){
12703 this.head.removeChild(document.getElementById(trans.scriptId));
12704 clearTimeout(trans.timeoutId);
12706 window[trans.cb] = undefined;
12708 delete window[trans.cb];
12711 // if hasn't been loaded, wait for load to remove it to prevent script error
12712 window[trans.cb] = function(){
12713 window[trans.cb] = undefined;
12715 delete window[trans.cb];
12722 handleResponse : function(o, trans){
12723 this.trans = false;
12724 this.destroyTrans(trans, true);
12727 result = trans.reader.readRecords(o);
12729 this.fireEvent("loadexception", this, o, trans.arg, e);
12730 trans.callback.call(trans.scope||window, null, trans.arg, false);
12733 this.fireEvent("load", this, o, trans.arg);
12734 trans.callback.call(trans.scope||window, result, trans.arg, true);
12738 handleFailure : function(trans){
12739 this.trans = false;
12740 this.destroyTrans(trans, false);
12741 this.fireEvent("loadexception", this, null, trans.arg);
12742 trans.callback.call(trans.scope||window, null, trans.arg, false);
12746 * Ext JS Library 1.1.1
12747 * Copyright(c) 2006-2007, Ext JS, LLC.
12749 * Originally Released Under LGPL - original licence link has changed is not relivant.
12752 * <script type="text/javascript">
12756 * @class Roo.data.JsonReader
12757 * @extends Roo.data.DataReader
12758 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12759 * based on mappings in a provided Roo.data.Record constructor.
12761 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12762 * in the reply previously.
12767 var RecordDef = Roo.data.Record.create([
12768 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12769 {name: 'occupation'} // This field will use "occupation" as the mapping.
12771 var myReader = new Roo.data.JsonReader({
12772 totalProperty: "results", // The property which contains the total dataset size (optional)
12773 root: "rows", // The property which contains an Array of row objects
12774 id: "id" // The property within each row object that provides an ID for the record (optional)
12778 * This would consume a JSON file like this:
12780 { 'results': 2, 'rows': [
12781 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12782 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12785 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12786 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12787 * paged from the remote server.
12788 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12789 * @cfg {String} root name of the property which contains the Array of row objects.
12790 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12791 * @cfg {Array} fields Array of field definition objects
12793 * Create a new JsonReader
12794 * @param {Object} meta Metadata configuration options
12795 * @param {Object} recordType Either an Array of field definition objects,
12796 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12798 Roo.data.JsonReader = function(meta, recordType){
12801 // set some defaults:
12802 Roo.applyIf(meta, {
12803 totalProperty: 'total',
12804 successProperty : 'success',
12809 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12811 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12814 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12815 * Used by Store query builder to append _requestMeta to params.
12818 metaFromRemote : false,
12820 * This method is only used by a DataProxy which has retrieved data from a remote server.
12821 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12822 * @return {Object} data A data block which is used by an Roo.data.Store object as
12823 * a cache of Roo.data.Records.
12825 read : function(response){
12826 var json = response.responseText;
12828 var o = /* eval:var:o */ eval("("+json+")");
12830 throw {message: "JsonReader.read: Json object not found"};
12836 this.metaFromRemote = true;
12837 this.meta = o.metaData;
12838 this.recordType = Roo.data.Record.create(o.metaData.fields);
12839 this.onMetaChange(this.meta, this.recordType, o);
12841 return this.readRecords(o);
12844 // private function a store will implement
12845 onMetaChange : function(meta, recordType, o){
12852 simpleAccess: function(obj, subsc) {
12859 getJsonAccessor: function(){
12861 return function(expr) {
12863 return(re.test(expr))
12864 ? new Function("obj", "return obj." + expr)
12869 return Roo.emptyFn;
12874 * Create a data block containing Roo.data.Records from an XML document.
12875 * @param {Object} o An object which contains an Array of row objects in the property specified
12876 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12877 * which contains the total size of the dataset.
12878 * @return {Object} data A data block which is used by an Roo.data.Store object as
12879 * a cache of Roo.data.Records.
12881 readRecords : function(o){
12883 * After any data loads, the raw JSON data is available for further custom processing.
12887 var s = this.meta, Record = this.recordType,
12888 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12890 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12892 if(s.totalProperty) {
12893 this.getTotal = this.getJsonAccessor(s.totalProperty);
12895 if(s.successProperty) {
12896 this.getSuccess = this.getJsonAccessor(s.successProperty);
12898 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12900 var g = this.getJsonAccessor(s.id);
12901 this.getId = function(rec) {
12903 return (r === undefined || r === "") ? null : r;
12906 this.getId = function(){return null;};
12909 for(var jj = 0; jj < fl; jj++){
12911 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12912 this.ef[jj] = this.getJsonAccessor(map);
12916 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12917 if(s.totalProperty){
12918 var vt = parseInt(this.getTotal(o), 10);
12923 if(s.successProperty){
12924 var vs = this.getSuccess(o);
12925 if(vs === false || vs === 'false'){
12930 for(var i = 0; i < c; i++){
12933 var id = this.getId(n);
12934 for(var j = 0; j < fl; j++){
12936 var v = this.ef[j](n);
12938 Roo.log('missing convert for ' + f.name);
12942 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12944 var record = new Record(values, id);
12946 records[i] = record;
12952 totalRecords : totalRecords
12957 * Ext JS Library 1.1.1
12958 * Copyright(c) 2006-2007, Ext JS, LLC.
12960 * Originally Released Under LGPL - original licence link has changed is not relivant.
12963 * <script type="text/javascript">
12967 * @class Roo.data.ArrayReader
12968 * @extends Roo.data.DataReader
12969 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12970 * Each element of that Array represents a row of data fields. The
12971 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12972 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12976 var RecordDef = Roo.data.Record.create([
12977 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12978 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12980 var myReader = new Roo.data.ArrayReader({
12981 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12985 * This would consume an Array like this:
12987 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12989 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12991 * Create a new JsonReader
12992 * @param {Object} meta Metadata configuration options.
12993 * @param {Object} recordType Either an Array of field definition objects
12994 * as specified to {@link Roo.data.Record#create},
12995 * or an {@link Roo.data.Record} object
12996 * created using {@link Roo.data.Record#create}.
12998 Roo.data.ArrayReader = function(meta, recordType){
12999 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
13002 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13004 * Create a data block containing Roo.data.Records from an XML document.
13005 * @param {Object} o An Array of row objects which represents the dataset.
13006 * @return {Object} data A data block which is used by an Roo.data.Store object as
13007 * a cache of Roo.data.Records.
13009 readRecords : function(o){
13010 var sid = this.meta ? this.meta.id : null;
13011 var recordType = this.recordType, fields = recordType.prototype.fields;
13014 for(var i = 0; i < root.length; i++){
13017 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13018 for(var j = 0, jlen = fields.length; j < jlen; j++){
13019 var f = fields.items[j];
13020 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13021 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13023 values[f.name] = v;
13025 var record = new recordType(values, id);
13027 records[records.length] = record;
13031 totalRecords : records.length
13040 * @class Roo.bootstrap.ComboBox
13041 * @extends Roo.bootstrap.TriggerField
13042 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13043 * @cfg {Boolean} append (true|false) default false
13044 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13045 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13046 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13047 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13048 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13049 * @cfg {Boolean} animate default true
13050 * @cfg {Boolean} emptyResultText only for touch device
13051 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13052 * @cfg {String} emptyTitle default ''
13054 * Create a new ComboBox.
13055 * @param {Object} config Configuration options
13057 Roo.bootstrap.ComboBox = function(config){
13058 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13062 * Fires when the dropdown list is expanded
13063 * @param {Roo.bootstrap.ComboBox} combo This combo box
13068 * Fires when the dropdown list is collapsed
13069 * @param {Roo.bootstrap.ComboBox} combo This combo box
13073 * @event beforeselect
13074 * Fires before a list item is selected. Return false to cancel the selection.
13075 * @param {Roo.bootstrap.ComboBox} combo This combo box
13076 * @param {Roo.data.Record} record The data record returned from the underlying store
13077 * @param {Number} index The index of the selected item in the dropdown list
13079 'beforeselect' : true,
13082 * Fires when a list item is selected
13083 * @param {Roo.bootstrap.ComboBox} combo This combo box
13084 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13085 * @param {Number} index The index of the selected item in the dropdown list
13089 * @event beforequery
13090 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13091 * The event object passed has these properties:
13092 * @param {Roo.bootstrap.ComboBox} combo This combo box
13093 * @param {String} query The query
13094 * @param {Boolean} forceAll true to force "all" query
13095 * @param {Boolean} cancel true to cancel the query
13096 * @param {Object} e The query event object
13098 'beforequery': true,
13101 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13102 * @param {Roo.bootstrap.ComboBox} combo This combo box
13107 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13108 * @param {Roo.bootstrap.ComboBox} combo This combo box
13109 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13114 * Fires when the remove value from the combobox array
13115 * @param {Roo.bootstrap.ComboBox} combo This combo box
13119 * @event afterremove
13120 * Fires when the remove value from the combobox array
13121 * @param {Roo.bootstrap.ComboBox} combo This combo box
13123 'afterremove' : true,
13125 * @event specialfilter
13126 * Fires when specialfilter
13127 * @param {Roo.bootstrap.ComboBox} combo This combo box
13129 'specialfilter' : true,
13132 * Fires when tick the element
13133 * @param {Roo.bootstrap.ComboBox} combo This combo box
13137 * @event touchviewdisplay
13138 * Fires when touch view require special display (default is using displayField)
13139 * @param {Roo.bootstrap.ComboBox} combo This combo box
13140 * @param {Object} cfg set html .
13142 'touchviewdisplay' : true
13147 this.tickItems = [];
13149 this.selectedIndex = -1;
13150 if(this.mode == 'local'){
13151 if(config.queryDelay === undefined){
13152 this.queryDelay = 10;
13154 if(config.minChars === undefined){
13160 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13163 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13164 * rendering into an Roo.Editor, defaults to false)
13167 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13168 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13171 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13174 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13175 * the dropdown list (defaults to undefined, with no header element)
13179 * @cfg {String/Roo.Template} tpl The template to use to render the output
13183 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13185 listWidth: undefined,
13187 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13188 * mode = 'remote' or 'text' if mode = 'local')
13190 displayField: undefined,
13193 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13194 * mode = 'remote' or 'value' if mode = 'local').
13195 * Note: use of a valueField requires the user make a selection
13196 * in order for a value to be mapped.
13198 valueField: undefined,
13200 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13205 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13206 * field's data value (defaults to the underlying DOM element's name)
13208 hiddenName: undefined,
13210 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13214 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13216 selectedClass: 'active',
13219 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13223 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13224 * anchor positions (defaults to 'tl-bl')
13226 listAlign: 'tl-bl?',
13228 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13232 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13233 * query specified by the allQuery config option (defaults to 'query')
13235 triggerAction: 'query',
13237 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13238 * (defaults to 4, does not apply if editable = false)
13242 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13243 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13247 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13248 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13252 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13253 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13257 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13258 * when editable = true (defaults to false)
13260 selectOnFocus:false,
13262 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13264 queryParam: 'query',
13266 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13267 * when mode = 'remote' (defaults to 'Loading...')
13269 loadingText: 'Loading...',
13271 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13275 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13279 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13280 * traditional select (defaults to true)
13284 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13288 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13292 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13293 * listWidth has a higher value)
13297 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13298 * allow the user to set arbitrary text into the field (defaults to false)
13300 forceSelection:false,
13302 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13303 * if typeAhead = true (defaults to 250)
13305 typeAheadDelay : 250,
13307 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13308 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13310 valueNotFoundText : undefined,
13312 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13314 blockFocus : false,
13317 * @cfg {Boolean} disableClear Disable showing of clear button.
13319 disableClear : false,
13321 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13323 alwaysQuery : false,
13326 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13331 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13333 invalidClass : "has-warning",
13336 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13338 validClass : "has-success",
13341 * @cfg {Boolean} specialFilter (true|false) special filter default false
13343 specialFilter : false,
13346 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13348 mobileTouchView : true,
13351 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13353 useNativeIOS : false,
13356 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13358 mobile_restrict_height : false,
13360 ios_options : false,
13372 btnPosition : 'right',
13373 triggerList : true,
13374 showToggleBtn : true,
13376 emptyResultText: 'Empty',
13377 triggerText : 'Select',
13380 // element that contains real text value.. (when hidden is used..)
13382 getAutoCreate : function()
13387 * Render classic select for iso
13390 if(Roo.isIOS && this.useNativeIOS){
13391 cfg = this.getAutoCreateNativeIOS();
13399 if(Roo.isTouch && this.mobileTouchView){
13400 cfg = this.getAutoCreateTouchView();
13407 if(!this.tickable){
13408 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13413 * ComboBox with tickable selections
13416 var align = this.labelAlign || this.parentLabelAlign();
13419 cls : 'form-group roo-combobox-tickable' //input-group
13422 var btn_text_select = '';
13423 var btn_text_done = '';
13424 var btn_text_cancel = '';
13426 if (this.btn_text_show) {
13427 btn_text_select = 'Select';
13428 btn_text_done = 'Done';
13429 btn_text_cancel = 'Cancel';
13434 cls : 'tickable-buttons',
13439 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13440 //html : this.triggerText
13441 html: btn_text_select
13447 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13449 html: btn_text_done
13455 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13457 html: btn_text_cancel
13463 buttons.cn.unshift({
13465 cls: 'roo-select2-search-field-input'
13471 Roo.each(buttons.cn, function(c){
13473 c.cls += ' btn-' + _this.size;
13476 if (_this.disabled) {
13483 style : 'display: contents',
13488 cls: 'form-hidden-field'
13492 cls: 'roo-select2-choices',
13496 cls: 'roo-select2-search-field',
13507 cls: 'roo-select2-container input-group roo-select2-container-multi',
13513 // cls: 'typeahead typeahead-long dropdown-menu',
13514 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13519 if(this.hasFeedback && !this.allowBlank){
13523 cls: 'glyphicon form-control-feedback'
13526 combobox.cn.push(feedback);
13531 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13532 tooltip : 'This field is required'
13534 if (Roo.bootstrap.version == 4) {
13537 style : 'display:none'
13540 if (align ==='left' && this.fieldLabel.length) {
13542 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13549 cls : 'control-label col-form-label',
13550 html : this.fieldLabel
13562 var labelCfg = cfg.cn[1];
13563 var contentCfg = cfg.cn[2];
13566 if(this.indicatorpos == 'right'){
13572 cls : 'control-label col-form-label',
13576 html : this.fieldLabel
13592 labelCfg = cfg.cn[0];
13593 contentCfg = cfg.cn[1];
13597 if(this.labelWidth > 12){
13598 labelCfg.style = "width: " + this.labelWidth + 'px';
13601 if(this.labelWidth < 13 && this.labelmd == 0){
13602 this.labelmd = this.labelWidth;
13605 if(this.labellg > 0){
13606 labelCfg.cls += ' col-lg-' + this.labellg;
13607 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13610 if(this.labelmd > 0){
13611 labelCfg.cls += ' col-md-' + this.labelmd;
13612 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13615 if(this.labelsm > 0){
13616 labelCfg.cls += ' col-sm-' + this.labelsm;
13617 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13620 if(this.labelxs > 0){
13621 labelCfg.cls += ' col-xs-' + this.labelxs;
13622 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13626 } else if ( this.fieldLabel.length) {
13627 // Roo.log(" label");
13632 //cls : 'input-group-addon',
13633 html : this.fieldLabel
13638 if(this.indicatorpos == 'right'){
13642 //cls : 'input-group-addon',
13643 html : this.fieldLabel
13653 // Roo.log(" no label && no align");
13660 ['xs','sm','md','lg'].map(function(size){
13661 if (settings[size]) {
13662 cfg.cls += ' col-' + size + '-' + settings[size];
13670 _initEventsCalled : false,
13673 initEvents: function()
13675 if (this._initEventsCalled) { // as we call render... prevent looping...
13678 this._initEventsCalled = true;
13681 throw "can not find store for combo";
13684 this.indicator = this.indicatorEl();
13686 this.store = Roo.factory(this.store, Roo.data);
13687 this.store.parent = this;
13689 // if we are building from html. then this element is so complex, that we can not really
13690 // use the rendered HTML.
13691 // so we have to trash and replace the previous code.
13692 if (Roo.XComponent.build_from_html) {
13693 // remove this element....
13694 var e = this.el.dom, k=0;
13695 while (e ) { e = e.previousSibling; ++k;}
13700 this.rendered = false;
13702 this.render(this.parent().getChildContainer(true), k);
13705 if(Roo.isIOS && this.useNativeIOS){
13706 this.initIOSView();
13714 if(Roo.isTouch && this.mobileTouchView){
13715 this.initTouchView();
13720 this.initTickableEvents();
13724 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13726 if(this.hiddenName){
13728 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13730 this.hiddenField.dom.value =
13731 this.hiddenValue !== undefined ? this.hiddenValue :
13732 this.value !== undefined ? this.value : '';
13734 // prevent input submission
13735 this.el.dom.removeAttribute('name');
13736 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13741 // this.el.dom.setAttribute('autocomplete', 'off');
13744 var cls = 'x-combo-list';
13746 //this.list = new Roo.Layer({
13747 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13753 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13754 _this.list.setWidth(lw);
13757 this.list.on('mouseover', this.onViewOver, this);
13758 this.list.on('mousemove', this.onViewMove, this);
13759 this.list.on('scroll', this.onViewScroll, this);
13762 this.list.swallowEvent('mousewheel');
13763 this.assetHeight = 0;
13766 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13767 this.assetHeight += this.header.getHeight();
13770 this.innerList = this.list.createChild({cls:cls+'-inner'});
13771 this.innerList.on('mouseover', this.onViewOver, this);
13772 this.innerList.on('mousemove', this.onViewMove, this);
13773 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13775 if(this.allowBlank && !this.pageSize && !this.disableClear){
13776 this.footer = this.list.createChild({cls:cls+'-ft'});
13777 this.pageTb = new Roo.Toolbar(this.footer);
13781 this.footer = this.list.createChild({cls:cls+'-ft'});
13782 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13783 {pageSize: this.pageSize});
13787 if (this.pageTb && this.allowBlank && !this.disableClear) {
13789 this.pageTb.add(new Roo.Toolbar.Fill(), {
13790 cls: 'x-btn-icon x-btn-clear',
13792 handler: function()
13795 _this.clearValue();
13796 _this.onSelect(false, -1);
13801 this.assetHeight += this.footer.getHeight();
13806 this.tpl = Roo.bootstrap.version == 4 ?
13807 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13808 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13811 this.view = new Roo.View(this.list, this.tpl, {
13812 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13814 //this.view.wrapEl.setDisplayed(false);
13815 this.view.on('click', this.onViewClick, this);
13818 this.store.on('beforeload', this.onBeforeLoad, this);
13819 this.store.on('load', this.onLoad, this);
13820 this.store.on('loadexception', this.onLoadException, this);
13822 if(this.resizable){
13823 this.resizer = new Roo.Resizable(this.list, {
13824 pinned:true, handles:'se'
13826 this.resizer.on('resize', function(r, w, h){
13827 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13828 this.listWidth = w;
13829 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13830 this.restrictHeight();
13832 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13835 if(!this.editable){
13836 this.editable = true;
13837 this.setEditable(false);
13842 if (typeof(this.events.add.listeners) != 'undefined') {
13844 this.addicon = this.wrap.createChild(
13845 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13847 this.addicon.on('click', function(e) {
13848 this.fireEvent('add', this);
13851 if (typeof(this.events.edit.listeners) != 'undefined') {
13853 this.editicon = this.wrap.createChild(
13854 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13855 if (this.addicon) {
13856 this.editicon.setStyle('margin-left', '40px');
13858 this.editicon.on('click', function(e) {
13860 // we fire even if inothing is selected..
13861 this.fireEvent('edit', this, this.lastData );
13867 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13868 "up" : function(e){
13869 this.inKeyMode = true;
13873 "down" : function(e){
13874 if(!this.isExpanded()){
13875 this.onTriggerClick();
13877 this.inKeyMode = true;
13882 "enter" : function(e){
13883 // this.onViewClick();
13887 if(this.fireEvent("specialkey", this, e)){
13888 this.onViewClick(false);
13894 "esc" : function(e){
13898 "tab" : function(e){
13901 if(this.fireEvent("specialkey", this, e)){
13902 this.onViewClick(false);
13910 doRelay : function(foo, bar, hname){
13911 if(hname == 'down' || this.scope.isExpanded()){
13912 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13921 this.queryDelay = Math.max(this.queryDelay || 10,
13922 this.mode == 'local' ? 10 : 250);
13925 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13927 if(this.typeAhead){
13928 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13930 if(this.editable !== false){
13931 this.inputEl().on("keyup", this.onKeyUp, this);
13933 if(this.forceSelection){
13934 this.inputEl().on('blur', this.doForce, this);
13938 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13939 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13943 initTickableEvents: function()
13947 if(this.hiddenName){
13949 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13951 this.hiddenField.dom.value =
13952 this.hiddenValue !== undefined ? this.hiddenValue :
13953 this.value !== undefined ? this.value : '';
13955 // prevent input submission
13956 this.el.dom.removeAttribute('name');
13957 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13962 // this.list = this.el.select('ul.dropdown-menu',true).first();
13964 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13965 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13966 if(this.triggerList){
13967 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13970 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13971 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13973 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13974 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13976 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13977 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13979 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13980 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13981 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13984 this.cancelBtn.hide();
13989 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13990 _this.list.setWidth(lw);
13993 this.list.on('mouseover', this.onViewOver, this);
13994 this.list.on('mousemove', this.onViewMove, this);
13996 this.list.on('scroll', this.onViewScroll, this);
13999 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14000 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14003 this.view = new Roo.View(this.list, this.tpl, {
14008 selectedClass: this.selectedClass
14011 //this.view.wrapEl.setDisplayed(false);
14012 this.view.on('click', this.onViewClick, this);
14016 this.store.on('beforeload', this.onBeforeLoad, this);
14017 this.store.on('load', this.onLoad, this);
14018 this.store.on('loadexception', this.onLoadException, this);
14021 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14022 "up" : function(e){
14023 this.inKeyMode = true;
14027 "down" : function(e){
14028 this.inKeyMode = true;
14032 "enter" : function(e){
14033 if(this.fireEvent("specialkey", this, e)){
14034 this.onViewClick(false);
14040 "esc" : function(e){
14041 this.onTickableFooterButtonClick(e, false, false);
14044 "tab" : function(e){
14045 this.fireEvent("specialkey", this, e);
14047 this.onTickableFooterButtonClick(e, false, false);
14054 doRelay : function(e, fn, key){
14055 if(this.scope.isExpanded()){
14056 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14065 this.queryDelay = Math.max(this.queryDelay || 10,
14066 this.mode == 'local' ? 10 : 250);
14069 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14071 if(this.typeAhead){
14072 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14075 if(this.editable !== false){
14076 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14079 this.indicator = this.indicatorEl();
14081 if(this.indicator){
14082 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14083 this.indicator.hide();
14088 onDestroy : function(){
14090 this.view.setStore(null);
14091 this.view.el.removeAllListeners();
14092 this.view.el.remove();
14093 this.view.purgeListeners();
14096 this.list.dom.innerHTML = '';
14100 this.store.un('beforeload', this.onBeforeLoad, this);
14101 this.store.un('load', this.onLoad, this);
14102 this.store.un('loadexception', this.onLoadException, this);
14104 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14108 fireKey : function(e){
14109 if(e.isNavKeyPress() && !this.list.isVisible()){
14110 this.fireEvent("specialkey", this, e);
14115 onResize: function(w, h){
14116 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14118 // if(typeof w != 'number'){
14119 // // we do not handle it!?!?
14122 // var tw = this.trigger.getWidth();
14123 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14124 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14126 // this.inputEl().setWidth( this.adjustWidth('input', x));
14128 // //this.trigger.setStyle('left', x+'px');
14130 // if(this.list && this.listWidth === undefined){
14131 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14132 // this.list.setWidth(lw);
14133 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14141 * Allow or prevent the user from directly editing the field text. If false is passed,
14142 * the user will only be able to select from the items defined in the dropdown list. This method
14143 * is the runtime equivalent of setting the 'editable' config option at config time.
14144 * @param {Boolean} value True to allow the user to directly edit the field text
14146 setEditable : function(value){
14147 if(value == this.editable){
14150 this.editable = value;
14152 this.inputEl().dom.setAttribute('readOnly', true);
14153 this.inputEl().on('mousedown', this.onTriggerClick, this);
14154 this.inputEl().addClass('x-combo-noedit');
14156 this.inputEl().dom.setAttribute('readOnly', false);
14157 this.inputEl().un('mousedown', this.onTriggerClick, this);
14158 this.inputEl().removeClass('x-combo-noedit');
14164 onBeforeLoad : function(combo,opts){
14165 if(!this.hasFocus){
14169 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14171 this.restrictHeight();
14172 this.selectedIndex = -1;
14176 onLoad : function(){
14178 this.hasQuery = false;
14180 if(!this.hasFocus){
14184 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14185 this.loading.hide();
14188 if(this.store.getCount() > 0){
14191 this.restrictHeight();
14192 if(this.lastQuery == this.allQuery){
14193 if(this.editable && !this.tickable){
14194 this.inputEl().dom.select();
14198 !this.selectByValue(this.value, true) &&
14201 !this.store.lastOptions ||
14202 typeof(this.store.lastOptions.add) == 'undefined' ||
14203 this.store.lastOptions.add != true
14206 this.select(0, true);
14209 if(this.autoFocus){
14212 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14213 this.taTask.delay(this.typeAheadDelay);
14217 this.onEmptyResults();
14223 onLoadException : function()
14225 this.hasQuery = false;
14227 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14228 this.loading.hide();
14231 if(this.tickable && this.editable){
14236 // only causes errors at present
14237 //Roo.log(this.store.reader.jsonData);
14238 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14240 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14246 onTypeAhead : function(){
14247 if(this.store.getCount() > 0){
14248 var r = this.store.getAt(0);
14249 var newValue = r.data[this.displayField];
14250 var len = newValue.length;
14251 var selStart = this.getRawValue().length;
14253 if(selStart != len){
14254 this.setRawValue(newValue);
14255 this.selectText(selStart, newValue.length);
14261 onSelect : function(record, index){
14263 if(this.fireEvent('beforeselect', this, record, index) !== false){
14265 this.setFromData(index > -1 ? record.data : false);
14268 this.fireEvent('select', this, record, index);
14273 * Returns the currently selected field value or empty string if no value is set.
14274 * @return {String} value The selected value
14276 getValue : function()
14278 if(Roo.isIOS && this.useNativeIOS){
14279 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14283 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14286 if(this.valueField){
14287 return typeof this.value != 'undefined' ? this.value : '';
14289 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14293 getRawValue : function()
14295 if(Roo.isIOS && this.useNativeIOS){
14296 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14299 var v = this.inputEl().getValue();
14305 * Clears any text/value currently set in the field
14307 clearValue : function(){
14309 if(this.hiddenField){
14310 this.hiddenField.dom.value = '';
14313 this.setRawValue('');
14314 this.lastSelectionText = '';
14315 this.lastData = false;
14317 var close = this.closeTriggerEl();
14328 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14329 * will be displayed in the field. If the value does not match the data value of an existing item,
14330 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14331 * Otherwise the field will be blank (although the value will still be set).
14332 * @param {String} value The value to match
14334 setValue : function(v)
14336 if(Roo.isIOS && this.useNativeIOS){
14337 this.setIOSValue(v);
14347 if(this.valueField){
14348 var r = this.findRecord(this.valueField, v);
14350 text = r.data[this.displayField];
14351 }else if(this.valueNotFoundText !== undefined){
14352 text = this.valueNotFoundText;
14355 this.lastSelectionText = text;
14356 if(this.hiddenField){
14357 this.hiddenField.dom.value = v;
14359 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14362 var close = this.closeTriggerEl();
14365 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14371 * @property {Object} the last set data for the element
14376 * Sets the value of the field based on a object which is related to the record format for the store.
14377 * @param {Object} value the value to set as. or false on reset?
14379 setFromData : function(o){
14386 var dv = ''; // display value
14387 var vv = ''; // value value..
14389 if (this.displayField) {
14390 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14392 // this is an error condition!!!
14393 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14396 if(this.valueField){
14397 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14400 var close = this.closeTriggerEl();
14403 if(dv.length || vv * 1 > 0){
14405 this.blockFocus=true;
14411 if(this.hiddenField){
14412 this.hiddenField.dom.value = vv;
14414 this.lastSelectionText = dv;
14415 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14419 // no hidden field.. - we store the value in 'value', but still display
14420 // display field!!!!
14421 this.lastSelectionText = dv;
14422 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14429 reset : function(){
14430 // overridden so that last data is reset..
14437 this.setValue(this.originalValue);
14438 //this.clearInvalid();
14439 this.lastData = false;
14441 this.view.clearSelections();
14447 findRecord : function(prop, value){
14449 if(this.store.getCount() > 0){
14450 this.store.each(function(r){
14451 if(r.data[prop] == value){
14461 getName: function()
14463 // returns hidden if it's set..
14464 if (!this.rendered) {return ''};
14465 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14469 onViewMove : function(e, t){
14470 this.inKeyMode = false;
14474 onViewOver : function(e, t){
14475 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14478 var item = this.view.findItemFromChild(t);
14481 var index = this.view.indexOf(item);
14482 this.select(index, false);
14487 onViewClick : function(view, doFocus, el, e)
14489 var index = this.view.getSelectedIndexes()[0];
14491 var r = this.store.getAt(index);
14495 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14502 Roo.each(this.tickItems, function(v,k){
14504 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14506 _this.tickItems.splice(k, 1);
14508 if(typeof(e) == 'undefined' && view == false){
14509 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14521 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14522 this.tickItems.push(r.data);
14525 if(typeof(e) == 'undefined' && view == false){
14526 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14533 this.onSelect(r, index);
14535 if(doFocus !== false && !this.blockFocus){
14536 this.inputEl().focus();
14541 restrictHeight : function(){
14542 //this.innerList.dom.style.height = '';
14543 //var inner = this.innerList.dom;
14544 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14545 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14546 //this.list.beginUpdate();
14547 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14548 this.list.alignTo(this.inputEl(), this.listAlign);
14549 this.list.alignTo(this.inputEl(), this.listAlign);
14550 //this.list.endUpdate();
14554 onEmptyResults : function(){
14556 if(this.tickable && this.editable){
14557 this.hasFocus = false;
14558 this.restrictHeight();
14566 * Returns true if the dropdown list is expanded, else false.
14568 isExpanded : function(){
14569 return this.list.isVisible();
14573 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14574 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14575 * @param {String} value The data value of the item to select
14576 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14577 * selected item if it is not currently in view (defaults to true)
14578 * @return {Boolean} True if the value matched an item in the list, else false
14580 selectByValue : function(v, scrollIntoView){
14581 if(v !== undefined && v !== null){
14582 var r = this.findRecord(this.valueField || this.displayField, v);
14584 this.select(this.store.indexOf(r), scrollIntoView);
14592 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14593 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14594 * @param {Number} index The zero-based index of the list item to select
14595 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14596 * selected item if it is not currently in view (defaults to true)
14598 select : function(index, scrollIntoView){
14599 this.selectedIndex = index;
14600 this.view.select(index);
14601 if(scrollIntoView !== false){
14602 var el = this.view.getNode(index);
14604 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14607 this.list.scrollChildIntoView(el, false);
14613 selectNext : function(){
14614 var ct = this.store.getCount();
14616 if(this.selectedIndex == -1){
14618 }else if(this.selectedIndex < ct-1){
14619 this.select(this.selectedIndex+1);
14625 selectPrev : function(){
14626 var ct = this.store.getCount();
14628 if(this.selectedIndex == -1){
14630 }else if(this.selectedIndex != 0){
14631 this.select(this.selectedIndex-1);
14637 onKeyUp : function(e){
14638 if(this.editable !== false && !e.isSpecialKey()){
14639 this.lastKey = e.getKey();
14640 this.dqTask.delay(this.queryDelay);
14645 validateBlur : function(){
14646 return !this.list || !this.list.isVisible();
14650 initQuery : function(){
14652 var v = this.getRawValue();
14654 if(this.tickable && this.editable){
14655 v = this.tickableInputEl().getValue();
14662 doForce : function(){
14663 if(this.inputEl().dom.value.length > 0){
14664 this.inputEl().dom.value =
14665 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14671 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14672 * query allowing the query action to be canceled if needed.
14673 * @param {String} query The SQL query to execute
14674 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14675 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14676 * saved in the current store (defaults to false)
14678 doQuery : function(q, forceAll){
14680 if(q === undefined || q === null){
14685 forceAll: forceAll,
14689 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14694 forceAll = qe.forceAll;
14695 if(forceAll === true || (q.length >= this.minChars)){
14697 this.hasQuery = true;
14699 if(this.lastQuery != q || this.alwaysQuery){
14700 this.lastQuery = q;
14701 if(this.mode == 'local'){
14702 this.selectedIndex = -1;
14704 this.store.clearFilter();
14707 if(this.specialFilter){
14708 this.fireEvent('specialfilter', this);
14713 this.store.filter(this.displayField, q);
14716 this.store.fireEvent("datachanged", this.store);
14723 this.store.baseParams[this.queryParam] = q;
14725 var options = {params : this.getParams(q)};
14728 options.add = true;
14729 options.params.start = this.page * this.pageSize;
14732 this.store.load(options);
14735 * this code will make the page width larger, at the beginning, the list not align correctly,
14736 * we should expand the list on onLoad
14737 * so command out it
14742 this.selectedIndex = -1;
14747 this.loadNext = false;
14751 getParams : function(q){
14753 //p[this.queryParam] = q;
14757 p.limit = this.pageSize;
14763 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14765 collapse : function(){
14766 if(!this.isExpanded()){
14772 this.hasFocus = false;
14776 this.cancelBtn.hide();
14777 this.trigger.show();
14780 this.tickableInputEl().dom.value = '';
14781 this.tickableInputEl().blur();
14786 Roo.get(document).un('mousedown', this.collapseIf, this);
14787 Roo.get(document).un('mousewheel', this.collapseIf, this);
14788 if (!this.editable) {
14789 Roo.get(document).un('keydown', this.listKeyPress, this);
14791 this.fireEvent('collapse', this);
14797 collapseIf : function(e){
14798 var in_combo = e.within(this.el);
14799 var in_list = e.within(this.list);
14800 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14802 if (in_combo || in_list || is_list) {
14803 //e.stopPropagation();
14808 this.onTickableFooterButtonClick(e, false, false);
14816 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14818 expand : function(){
14820 if(this.isExpanded() || !this.hasFocus){
14824 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14825 this.list.setWidth(lw);
14831 this.restrictHeight();
14835 this.tickItems = Roo.apply([], this.item);
14838 this.cancelBtn.show();
14839 this.trigger.hide();
14842 this.tickableInputEl().focus();
14847 Roo.get(document).on('mousedown', this.collapseIf, this);
14848 Roo.get(document).on('mousewheel', this.collapseIf, this);
14849 if (!this.editable) {
14850 Roo.get(document).on('keydown', this.listKeyPress, this);
14853 this.fireEvent('expand', this);
14857 // Implements the default empty TriggerField.onTriggerClick function
14858 onTriggerClick : function(e)
14860 Roo.log('trigger click');
14862 if(this.disabled || !this.triggerList){
14867 this.loadNext = false;
14869 if(this.isExpanded()){
14871 if (!this.blockFocus) {
14872 this.inputEl().focus();
14876 this.hasFocus = true;
14877 if(this.triggerAction == 'all') {
14878 this.doQuery(this.allQuery, true);
14880 this.doQuery(this.getRawValue());
14882 if (!this.blockFocus) {
14883 this.inputEl().focus();
14888 onTickableTriggerClick : function(e)
14895 this.loadNext = false;
14896 this.hasFocus = true;
14898 if(this.triggerAction == 'all') {
14899 this.doQuery(this.allQuery, true);
14901 this.doQuery(this.getRawValue());
14905 onSearchFieldClick : function(e)
14907 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14908 this.onTickableFooterButtonClick(e, false, false);
14912 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14917 this.loadNext = false;
14918 this.hasFocus = true;
14920 if(this.triggerAction == 'all') {
14921 this.doQuery(this.allQuery, true);
14923 this.doQuery(this.getRawValue());
14927 listKeyPress : function(e)
14929 //Roo.log('listkeypress');
14930 // scroll to first matching element based on key pres..
14931 if (e.isSpecialKey()) {
14934 var k = String.fromCharCode(e.getKey()).toUpperCase();
14937 var csel = this.view.getSelectedNodes();
14938 var cselitem = false;
14940 var ix = this.view.indexOf(csel[0]);
14941 cselitem = this.store.getAt(ix);
14942 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14948 this.store.each(function(v) {
14950 // start at existing selection.
14951 if (cselitem.id == v.id) {
14957 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14958 match = this.store.indexOf(v);
14964 if (match === false) {
14965 return true; // no more action?
14968 this.view.select(match);
14969 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14970 sn.scrollIntoView(sn.dom.parentNode, false);
14973 onViewScroll : function(e, t){
14975 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){
14979 this.hasQuery = true;
14981 this.loading = this.list.select('.loading', true).first();
14983 if(this.loading === null){
14984 this.list.createChild({
14986 cls: 'loading roo-select2-more-results roo-select2-active',
14987 html: 'Loading more results...'
14990 this.loading = this.list.select('.loading', true).first();
14992 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14994 this.loading.hide();
14997 this.loading.show();
15002 this.loadNext = true;
15004 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15009 addItem : function(o)
15011 var dv = ''; // display value
15013 if (this.displayField) {
15014 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15016 // this is an error condition!!!
15017 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15024 var choice = this.choices.createChild({
15026 cls: 'roo-select2-search-choice',
15035 cls: 'roo-select2-search-choice-close fa fa-times',
15040 }, this.searchField);
15042 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15044 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15052 this.inputEl().dom.value = '';
15057 onRemoveItem : function(e, _self, o)
15059 e.preventDefault();
15061 this.lastItem = Roo.apply([], this.item);
15063 var index = this.item.indexOf(o.data) * 1;
15066 Roo.log('not this item?!');
15070 this.item.splice(index, 1);
15075 this.fireEvent('remove', this, e);
15081 syncValue : function()
15083 if(!this.item.length){
15090 Roo.each(this.item, function(i){
15091 if(_this.valueField){
15092 value.push(i[_this.valueField]);
15099 this.value = value.join(',');
15101 if(this.hiddenField){
15102 this.hiddenField.dom.value = this.value;
15105 this.store.fireEvent("datachanged", this.store);
15110 clearItem : function()
15112 if(!this.multiple){
15118 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15126 if(this.tickable && !Roo.isTouch){
15127 this.view.refresh();
15131 inputEl: function ()
15133 if(Roo.isIOS && this.useNativeIOS){
15134 return this.el.select('select.roo-ios-select', true).first();
15137 if(Roo.isTouch && this.mobileTouchView){
15138 return this.el.select('input.form-control',true).first();
15142 return this.searchField;
15145 return this.el.select('input.form-control',true).first();
15148 onTickableFooterButtonClick : function(e, btn, el)
15150 e.preventDefault();
15152 this.lastItem = Roo.apply([], this.item);
15154 if(btn && btn.name == 'cancel'){
15155 this.tickItems = Roo.apply([], this.item);
15164 Roo.each(this.tickItems, function(o){
15172 validate : function()
15174 if(this.getVisibilityEl().hasClass('hidden')){
15178 var v = this.getRawValue();
15181 v = this.getValue();
15184 if(this.disabled || this.allowBlank || v.length){
15189 this.markInvalid();
15193 tickableInputEl : function()
15195 if(!this.tickable || !this.editable){
15196 return this.inputEl();
15199 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15203 getAutoCreateTouchView : function()
15208 cls: 'form-group' //input-group
15214 type : this.inputType,
15215 cls : 'form-control x-combo-noedit',
15216 autocomplete: 'new-password',
15217 placeholder : this.placeholder || '',
15222 input.name = this.name;
15226 input.cls += ' input-' + this.size;
15229 if (this.disabled) {
15230 input.disabled = true;
15241 inputblock.cls += ' input-group';
15243 inputblock.cn.unshift({
15245 cls : 'input-group-addon input-group-prepend input-group-text',
15250 if(this.removable && !this.multiple){
15251 inputblock.cls += ' roo-removable';
15253 inputblock.cn.push({
15256 cls : 'roo-combo-removable-btn close'
15260 if(this.hasFeedback && !this.allowBlank){
15262 inputblock.cls += ' has-feedback';
15264 inputblock.cn.push({
15266 cls: 'glyphicon form-control-feedback'
15273 inputblock.cls += (this.before) ? '' : ' input-group';
15275 inputblock.cn.push({
15277 cls : 'input-group-addon input-group-append input-group-text',
15283 var ibwrap = inputblock;
15288 cls: 'roo-select2-choices',
15292 cls: 'roo-select2-search-field',
15305 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15310 cls: 'form-hidden-field'
15316 if(!this.multiple && this.showToggleBtn){
15323 if (this.caret != false) {
15326 cls: 'fa fa-' + this.caret
15333 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15338 cls: 'combobox-clear',
15352 combobox.cls += ' roo-select2-container-multi';
15355 var align = this.labelAlign || this.parentLabelAlign();
15357 if (align ==='left' && this.fieldLabel.length) {
15362 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15363 tooltip : 'This field is required'
15367 cls : 'control-label col-form-label',
15368 html : this.fieldLabel
15379 var labelCfg = cfg.cn[1];
15380 var contentCfg = cfg.cn[2];
15383 if(this.indicatorpos == 'right'){
15388 cls : 'control-label col-form-label',
15392 html : this.fieldLabel
15396 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15397 tooltip : 'This field is required'
15410 labelCfg = cfg.cn[0];
15411 contentCfg = cfg.cn[1];
15416 if(this.labelWidth > 12){
15417 labelCfg.style = "width: " + this.labelWidth + 'px';
15420 if(this.labelWidth < 13 && this.labelmd == 0){
15421 this.labelmd = this.labelWidth;
15424 if(this.labellg > 0){
15425 labelCfg.cls += ' col-lg-' + this.labellg;
15426 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15429 if(this.labelmd > 0){
15430 labelCfg.cls += ' col-md-' + this.labelmd;
15431 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15434 if(this.labelsm > 0){
15435 labelCfg.cls += ' col-sm-' + this.labelsm;
15436 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15439 if(this.labelxs > 0){
15440 labelCfg.cls += ' col-xs-' + this.labelxs;
15441 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15445 } else if ( this.fieldLabel.length) {
15449 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15450 tooltip : 'This field is required'
15454 cls : 'control-label',
15455 html : this.fieldLabel
15466 if(this.indicatorpos == 'right'){
15470 cls : 'control-label',
15471 html : this.fieldLabel,
15475 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15476 tooltip : 'This field is required'
15493 var settings = this;
15495 ['xs','sm','md','lg'].map(function(size){
15496 if (settings[size]) {
15497 cfg.cls += ' col-' + size + '-' + settings[size];
15504 initTouchView : function()
15506 this.renderTouchView();
15508 this.touchViewEl.on('scroll', function(){
15509 this.el.dom.scrollTop = 0;
15512 this.originalValue = this.getValue();
15514 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15516 this.inputEl().on("click", this.showTouchView, this);
15517 if (this.triggerEl) {
15518 this.triggerEl.on("click", this.showTouchView, this);
15522 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15523 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15525 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15527 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15528 this.store.on('load', this.onTouchViewLoad, this);
15529 this.store.on('loadexception', this.onTouchViewLoadException, this);
15531 if(this.hiddenName){
15533 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15535 this.hiddenField.dom.value =
15536 this.hiddenValue !== undefined ? this.hiddenValue :
15537 this.value !== undefined ? this.value : '';
15539 this.el.dom.removeAttribute('name');
15540 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15544 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15545 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15548 if(this.removable && !this.multiple){
15549 var close = this.closeTriggerEl();
15551 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15552 close.on('click', this.removeBtnClick, this, close);
15556 * fix the bug in Safari iOS8
15558 this.inputEl().on("focus", function(e){
15559 document.activeElement.blur();
15562 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15569 renderTouchView : function()
15571 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15572 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15574 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15575 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15577 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15578 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15579 this.touchViewBodyEl.setStyle('overflow', 'auto');
15581 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15582 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15584 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15585 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15589 showTouchView : function()
15595 this.touchViewHeaderEl.hide();
15597 if(this.modalTitle.length){
15598 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15599 this.touchViewHeaderEl.show();
15602 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15603 this.touchViewEl.show();
15605 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15607 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15608 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15610 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15612 if(this.modalTitle.length){
15613 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15616 this.touchViewBodyEl.setHeight(bodyHeight);
15620 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15622 this.touchViewEl.addClass('in');
15625 if(this._touchViewMask){
15626 Roo.get(document.body).addClass("x-body-masked");
15627 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15628 this._touchViewMask.setStyle('z-index', 10000);
15629 this._touchViewMask.addClass('show');
15632 this.doTouchViewQuery();
15636 hideTouchView : function()
15638 this.touchViewEl.removeClass('in');
15642 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15644 this.touchViewEl.setStyle('display', 'none');
15647 if(this._touchViewMask){
15648 this._touchViewMask.removeClass('show');
15649 Roo.get(document.body).removeClass("x-body-masked");
15653 setTouchViewValue : function()
15660 Roo.each(this.tickItems, function(o){
15665 this.hideTouchView();
15668 doTouchViewQuery : function()
15677 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15681 if(!this.alwaysQuery || this.mode == 'local'){
15682 this.onTouchViewLoad();
15689 onTouchViewBeforeLoad : function(combo,opts)
15695 onTouchViewLoad : function()
15697 if(this.store.getCount() < 1){
15698 this.onTouchViewEmptyResults();
15702 this.clearTouchView();
15704 var rawValue = this.getRawValue();
15706 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15708 this.tickItems = [];
15710 this.store.data.each(function(d, rowIndex){
15711 var row = this.touchViewListGroup.createChild(template);
15713 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15714 row.addClass(d.data.cls);
15717 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15720 html : d.data[this.displayField]
15723 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15724 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15727 row.removeClass('selected');
15728 if(!this.multiple && this.valueField &&
15729 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15732 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15733 row.addClass('selected');
15736 if(this.multiple && this.valueField &&
15737 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15741 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15742 this.tickItems.push(d.data);
15745 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15749 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15751 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15753 if(this.modalTitle.length){
15754 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15757 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15759 if(this.mobile_restrict_height && listHeight < bodyHeight){
15760 this.touchViewBodyEl.setHeight(listHeight);
15765 if(firstChecked && listHeight > bodyHeight){
15766 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15771 onTouchViewLoadException : function()
15773 this.hideTouchView();
15776 onTouchViewEmptyResults : function()
15778 this.clearTouchView();
15780 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15782 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15786 clearTouchView : function()
15788 this.touchViewListGroup.dom.innerHTML = '';
15791 onTouchViewClick : function(e, el, o)
15793 e.preventDefault();
15796 var rowIndex = o.rowIndex;
15798 var r = this.store.getAt(rowIndex);
15800 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15802 if(!this.multiple){
15803 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15804 c.dom.removeAttribute('checked');
15807 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15809 this.setFromData(r.data);
15811 var close = this.closeTriggerEl();
15817 this.hideTouchView();
15819 this.fireEvent('select', this, r, rowIndex);
15824 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15825 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15826 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15830 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15831 this.addItem(r.data);
15832 this.tickItems.push(r.data);
15836 getAutoCreateNativeIOS : function()
15839 cls: 'form-group' //input-group,
15844 cls : 'roo-ios-select'
15848 combobox.name = this.name;
15851 if (this.disabled) {
15852 combobox.disabled = true;
15855 var settings = this;
15857 ['xs','sm','md','lg'].map(function(size){
15858 if (settings[size]) {
15859 cfg.cls += ' col-' + size + '-' + settings[size];
15869 initIOSView : function()
15871 this.store.on('load', this.onIOSViewLoad, this);
15876 onIOSViewLoad : function()
15878 if(this.store.getCount() < 1){
15882 this.clearIOSView();
15884 if(this.allowBlank) {
15886 var default_text = '-- SELECT --';
15888 if(this.placeholder.length){
15889 default_text = this.placeholder;
15892 if(this.emptyTitle.length){
15893 default_text += ' - ' + this.emptyTitle + ' -';
15896 var opt = this.inputEl().createChild({
15899 html : default_text
15903 o[this.valueField] = 0;
15904 o[this.displayField] = default_text;
15906 this.ios_options.push({
15913 this.store.data.each(function(d, rowIndex){
15917 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15918 html = d.data[this.displayField];
15923 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15924 value = d.data[this.valueField];
15933 if(this.value == d.data[this.valueField]){
15934 option['selected'] = true;
15937 var opt = this.inputEl().createChild(option);
15939 this.ios_options.push({
15946 this.inputEl().on('change', function(){
15947 this.fireEvent('select', this);
15952 clearIOSView: function()
15954 this.inputEl().dom.innerHTML = '';
15956 this.ios_options = [];
15959 setIOSValue: function(v)
15963 if(!this.ios_options){
15967 Roo.each(this.ios_options, function(opts){
15969 opts.el.dom.removeAttribute('selected');
15971 if(opts.data[this.valueField] != v){
15975 opts.el.dom.setAttribute('selected', true);
15981 * @cfg {Boolean} grow
15985 * @cfg {Number} growMin
15989 * @cfg {Number} growMax
15998 Roo.apply(Roo.bootstrap.ComboBox, {
16002 cls: 'modal-header',
16024 cls: 'list-group-item',
16028 cls: 'roo-combobox-list-group-item-value'
16032 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16046 listItemCheckbox : {
16048 cls: 'list-group-item',
16052 cls: 'roo-combobox-list-group-item-value'
16056 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16072 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16077 cls: 'modal-footer',
16085 cls: 'col-xs-6 text-left',
16088 cls: 'btn btn-danger roo-touch-view-cancel',
16094 cls: 'col-xs-6 text-right',
16097 cls: 'btn btn-success roo-touch-view-ok',
16108 Roo.apply(Roo.bootstrap.ComboBox, {
16110 touchViewTemplate : {
16112 cls: 'modal fade roo-combobox-touch-view',
16116 cls: 'modal-dialog',
16117 style : 'position:fixed', // we have to fix position....
16121 cls: 'modal-content',
16123 Roo.bootstrap.ComboBox.header,
16124 Roo.bootstrap.ComboBox.body,
16125 Roo.bootstrap.ComboBox.footer
16134 * Ext JS Library 1.1.1
16135 * Copyright(c) 2006-2007, Ext JS, LLC.
16137 * Originally Released Under LGPL - original licence link has changed is not relivant.
16140 * <script type="text/javascript">
16145 * @extends Roo.util.Observable
16146 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16147 * This class also supports single and multi selection modes. <br>
16148 * Create a data model bound view:
16150 var store = new Roo.data.Store(...);
16152 var view = new Roo.View({
16154 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16156 singleSelect: true,
16157 selectedClass: "ydataview-selected",
16161 // listen for node click?
16162 view.on("click", function(vw, index, node, e){
16163 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16167 dataModel.load("foobar.xml");
16169 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16171 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16172 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16174 * Note: old style constructor is still suported (container, template, config)
16177 * Create a new View
16178 * @param {Object} config The config object
16181 Roo.View = function(config, depreciated_tpl, depreciated_config){
16183 this.parent = false;
16185 if (typeof(depreciated_tpl) == 'undefined') {
16186 // new way.. - universal constructor.
16187 Roo.apply(this, config);
16188 this.el = Roo.get(this.el);
16191 this.el = Roo.get(config);
16192 this.tpl = depreciated_tpl;
16193 Roo.apply(this, depreciated_config);
16195 this.wrapEl = this.el.wrap().wrap();
16196 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16199 if(typeof(this.tpl) == "string"){
16200 this.tpl = new Roo.Template(this.tpl);
16202 // support xtype ctors..
16203 this.tpl = new Roo.factory(this.tpl, Roo);
16207 this.tpl.compile();
16212 * @event beforeclick
16213 * Fires before a click is processed. Returns false to cancel the default action.
16214 * @param {Roo.View} this
16215 * @param {Number} index The index of the target node
16216 * @param {HTMLElement} node The target node
16217 * @param {Roo.EventObject} e The raw event object
16219 "beforeclick" : true,
16222 * Fires when a template node is clicked.
16223 * @param {Roo.View} this
16224 * @param {Number} index The index of the target node
16225 * @param {HTMLElement} node The target node
16226 * @param {Roo.EventObject} e The raw event object
16231 * Fires when a template node is double clicked.
16232 * @param {Roo.View} this
16233 * @param {Number} index The index of the target node
16234 * @param {HTMLElement} node The target node
16235 * @param {Roo.EventObject} e The raw event object
16239 * @event contextmenu
16240 * Fires when a template node is right clicked.
16241 * @param {Roo.View} this
16242 * @param {Number} index The index of the target node
16243 * @param {HTMLElement} node The target node
16244 * @param {Roo.EventObject} e The raw event object
16246 "contextmenu" : true,
16248 * @event selectionchange
16249 * Fires when the selected nodes change.
16250 * @param {Roo.View} this
16251 * @param {Array} selections Array of the selected nodes
16253 "selectionchange" : true,
16256 * @event beforeselect
16257 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16258 * @param {Roo.View} this
16259 * @param {HTMLElement} node The node to be selected
16260 * @param {Array} selections Array of currently selected nodes
16262 "beforeselect" : true,
16264 * @event preparedata
16265 * Fires on every row to render, to allow you to change the data.
16266 * @param {Roo.View} this
16267 * @param {Object} data to be rendered (change this)
16269 "preparedata" : true
16277 "click": this.onClick,
16278 "dblclick": this.onDblClick,
16279 "contextmenu": this.onContextMenu,
16283 this.selections = [];
16285 this.cmp = new Roo.CompositeElementLite([]);
16287 this.store = Roo.factory(this.store, Roo.data);
16288 this.setStore(this.store, true);
16291 if ( this.footer && this.footer.xtype) {
16293 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16295 this.footer.dataSource = this.store;
16296 this.footer.container = fctr;
16297 this.footer = Roo.factory(this.footer, Roo);
16298 fctr.insertFirst(this.el);
16300 // this is a bit insane - as the paging toolbar seems to detach the el..
16301 // dom.parentNode.parentNode.parentNode
16302 // they get detached?
16306 Roo.View.superclass.constructor.call(this);
16311 Roo.extend(Roo.View, Roo.util.Observable, {
16314 * @cfg {Roo.data.Store} store Data store to load data from.
16319 * @cfg {String|Roo.Element} el The container element.
16324 * @cfg {String|Roo.Template} tpl The template used by this View
16328 * @cfg {String} dataName the named area of the template to use as the data area
16329 * Works with domtemplates roo-name="name"
16333 * @cfg {String} selectedClass The css class to add to selected nodes
16335 selectedClass : "x-view-selected",
16337 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16342 * @cfg {String} text to display on mask (default Loading)
16346 * @cfg {Boolean} multiSelect Allow multiple selection
16348 multiSelect : false,
16350 * @cfg {Boolean} singleSelect Allow single selection
16352 singleSelect: false,
16355 * @cfg {Boolean} toggleSelect - selecting
16357 toggleSelect : false,
16360 * @cfg {Boolean} tickable - selecting
16365 * Returns the element this view is bound to.
16366 * @return {Roo.Element}
16368 getEl : function(){
16369 return this.wrapEl;
16375 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16377 refresh : function(){
16378 //Roo.log('refresh');
16381 // if we are using something like 'domtemplate', then
16382 // the what gets used is:
16383 // t.applySubtemplate(NAME, data, wrapping data..)
16384 // the outer template then get' applied with
16385 // the store 'extra data'
16386 // and the body get's added to the
16387 // roo-name="data" node?
16388 // <span class='roo-tpl-{name}'></span> ?????
16392 this.clearSelections();
16393 this.el.update("");
16395 var records = this.store.getRange();
16396 if(records.length < 1) {
16398 // is this valid?? = should it render a template??
16400 this.el.update(this.emptyText);
16404 if (this.dataName) {
16405 this.el.update(t.apply(this.store.meta)); //????
16406 el = this.el.child('.roo-tpl-' + this.dataName);
16409 for(var i = 0, len = records.length; i < len; i++){
16410 var data = this.prepareData(records[i].data, i, records[i]);
16411 this.fireEvent("preparedata", this, data, i, records[i]);
16413 var d = Roo.apply({}, data);
16416 Roo.apply(d, {'roo-id' : Roo.id()});
16420 Roo.each(this.parent.item, function(item){
16421 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16424 Roo.apply(d, {'roo-data-checked' : 'checked'});
16428 html[html.length] = Roo.util.Format.trim(
16430 t.applySubtemplate(this.dataName, d, this.store.meta) :
16437 el.update(html.join(""));
16438 this.nodes = el.dom.childNodes;
16439 this.updateIndexes(0);
16444 * Function to override to reformat the data that is sent to
16445 * the template for each node.
16446 * DEPRICATED - use the preparedata event handler.
16447 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16448 * a JSON object for an UpdateManager bound view).
16450 prepareData : function(data, index, record)
16452 this.fireEvent("preparedata", this, data, index, record);
16456 onUpdate : function(ds, record){
16457 // Roo.log('on update');
16458 this.clearSelections();
16459 var index = this.store.indexOf(record);
16460 var n = this.nodes[index];
16461 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16462 n.parentNode.removeChild(n);
16463 this.updateIndexes(index, index);
16469 onAdd : function(ds, records, index)
16471 //Roo.log(['on Add', ds, records, index] );
16472 this.clearSelections();
16473 if(this.nodes.length == 0){
16477 var n = this.nodes[index];
16478 for(var i = 0, len = records.length; i < len; i++){
16479 var d = this.prepareData(records[i].data, i, records[i]);
16481 this.tpl.insertBefore(n, d);
16484 this.tpl.append(this.el, d);
16487 this.updateIndexes(index);
16490 onRemove : function(ds, record, index){
16491 // Roo.log('onRemove');
16492 this.clearSelections();
16493 var el = this.dataName ?
16494 this.el.child('.roo-tpl-' + this.dataName) :
16497 el.dom.removeChild(this.nodes[index]);
16498 this.updateIndexes(index);
16502 * Refresh an individual node.
16503 * @param {Number} index
16505 refreshNode : function(index){
16506 this.onUpdate(this.store, this.store.getAt(index));
16509 updateIndexes : function(startIndex, endIndex){
16510 var ns = this.nodes;
16511 startIndex = startIndex || 0;
16512 endIndex = endIndex || ns.length - 1;
16513 for(var i = startIndex; i <= endIndex; i++){
16514 ns[i].nodeIndex = i;
16519 * Changes the data store this view uses and refresh the view.
16520 * @param {Store} store
16522 setStore : function(store, initial){
16523 if(!initial && this.store){
16524 this.store.un("datachanged", this.refresh);
16525 this.store.un("add", this.onAdd);
16526 this.store.un("remove", this.onRemove);
16527 this.store.un("update", this.onUpdate);
16528 this.store.un("clear", this.refresh);
16529 this.store.un("beforeload", this.onBeforeLoad);
16530 this.store.un("load", this.onLoad);
16531 this.store.un("loadexception", this.onLoad);
16535 store.on("datachanged", this.refresh, this);
16536 store.on("add", this.onAdd, this);
16537 store.on("remove", this.onRemove, this);
16538 store.on("update", this.onUpdate, this);
16539 store.on("clear", this.refresh, this);
16540 store.on("beforeload", this.onBeforeLoad, this);
16541 store.on("load", this.onLoad, this);
16542 store.on("loadexception", this.onLoad, this);
16550 * onbeforeLoad - masks the loading area.
16553 onBeforeLoad : function(store,opts)
16555 //Roo.log('onBeforeLoad');
16557 this.el.update("");
16559 this.el.mask(this.mask ? this.mask : "Loading" );
16561 onLoad : function ()
16568 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16569 * @param {HTMLElement} node
16570 * @return {HTMLElement} The template node
16572 findItemFromChild : function(node){
16573 var el = this.dataName ?
16574 this.el.child('.roo-tpl-' + this.dataName,true) :
16577 if(!node || node.parentNode == el){
16580 var p = node.parentNode;
16581 while(p && p != el){
16582 if(p.parentNode == el){
16591 onClick : function(e){
16592 var item = this.findItemFromChild(e.getTarget());
16594 var index = this.indexOf(item);
16595 if(this.onItemClick(item, index, e) !== false){
16596 this.fireEvent("click", this, index, item, e);
16599 this.clearSelections();
16604 onContextMenu : function(e){
16605 var item = this.findItemFromChild(e.getTarget());
16607 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16612 onDblClick : function(e){
16613 var item = this.findItemFromChild(e.getTarget());
16615 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16619 onItemClick : function(item, index, e)
16621 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16624 if (this.toggleSelect) {
16625 var m = this.isSelected(item) ? 'unselect' : 'select';
16628 _t[m](item, true, false);
16631 if(this.multiSelect || this.singleSelect){
16632 if(this.multiSelect && e.shiftKey && this.lastSelection){
16633 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16635 this.select(item, this.multiSelect && e.ctrlKey);
16636 this.lastSelection = item;
16639 if(!this.tickable){
16640 e.preventDefault();
16648 * Get the number of selected nodes.
16651 getSelectionCount : function(){
16652 return this.selections.length;
16656 * Get the currently selected nodes.
16657 * @return {Array} An array of HTMLElements
16659 getSelectedNodes : function(){
16660 return this.selections;
16664 * Get the indexes of the selected nodes.
16667 getSelectedIndexes : function(){
16668 var indexes = [], s = this.selections;
16669 for(var i = 0, len = s.length; i < len; i++){
16670 indexes.push(s[i].nodeIndex);
16676 * Clear all selections
16677 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16679 clearSelections : function(suppressEvent){
16680 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16681 this.cmp.elements = this.selections;
16682 this.cmp.removeClass(this.selectedClass);
16683 this.selections = [];
16684 if(!suppressEvent){
16685 this.fireEvent("selectionchange", this, this.selections);
16691 * Returns true if the passed node is selected
16692 * @param {HTMLElement/Number} node The node or node index
16693 * @return {Boolean}
16695 isSelected : function(node){
16696 var s = this.selections;
16700 node = this.getNode(node);
16701 return s.indexOf(node) !== -1;
16706 * @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
16707 * @param {Boolean} keepExisting (optional) true to keep existing selections
16708 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16710 select : function(nodeInfo, keepExisting, suppressEvent){
16711 if(nodeInfo instanceof Array){
16713 this.clearSelections(true);
16715 for(var i = 0, len = nodeInfo.length; i < len; i++){
16716 this.select(nodeInfo[i], true, true);
16720 var node = this.getNode(nodeInfo);
16721 if(!node || this.isSelected(node)){
16722 return; // already selected.
16725 this.clearSelections(true);
16728 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16729 Roo.fly(node).addClass(this.selectedClass);
16730 this.selections.push(node);
16731 if(!suppressEvent){
16732 this.fireEvent("selectionchange", this, this.selections);
16740 * @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
16741 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16742 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16744 unselect : function(nodeInfo, keepExisting, suppressEvent)
16746 if(nodeInfo instanceof Array){
16747 Roo.each(this.selections, function(s) {
16748 this.unselect(s, nodeInfo);
16752 var node = this.getNode(nodeInfo);
16753 if(!node || !this.isSelected(node)){
16754 //Roo.log("not selected");
16755 return; // not selected.
16759 Roo.each(this.selections, function(s) {
16761 Roo.fly(node).removeClass(this.selectedClass);
16768 this.selections= ns;
16769 this.fireEvent("selectionchange", this, this.selections);
16773 * Gets a template node.
16774 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16775 * @return {HTMLElement} The node or null if it wasn't found
16777 getNode : function(nodeInfo){
16778 if(typeof nodeInfo == "string"){
16779 return document.getElementById(nodeInfo);
16780 }else if(typeof nodeInfo == "number"){
16781 return this.nodes[nodeInfo];
16787 * Gets a range template nodes.
16788 * @param {Number} startIndex
16789 * @param {Number} endIndex
16790 * @return {Array} An array of nodes
16792 getNodes : function(start, end){
16793 var ns = this.nodes;
16794 start = start || 0;
16795 end = typeof end == "undefined" ? ns.length - 1 : end;
16798 for(var i = start; i <= end; i++){
16802 for(var i = start; i >= end; i--){
16810 * Finds the index of the passed node
16811 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16812 * @return {Number} The index of the node or -1
16814 indexOf : function(node){
16815 node = this.getNode(node);
16816 if(typeof node.nodeIndex == "number"){
16817 return node.nodeIndex;
16819 var ns = this.nodes;
16820 for(var i = 0, len = ns.length; i < len; i++){
16831 * based on jquery fullcalendar
16835 Roo.bootstrap = Roo.bootstrap || {};
16837 * @class Roo.bootstrap.Calendar
16838 * @extends Roo.bootstrap.Component
16839 * Bootstrap Calendar class
16840 * @cfg {Boolean} loadMask (true|false) default false
16841 * @cfg {Object} header generate the user specific header of the calendar, default false
16844 * Create a new Container
16845 * @param {Object} config The config object
16850 Roo.bootstrap.Calendar = function(config){
16851 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16855 * Fires when a date is selected
16856 * @param {DatePicker} this
16857 * @param {Date} date The selected date
16861 * @event monthchange
16862 * Fires when the displayed month changes
16863 * @param {DatePicker} this
16864 * @param {Date} date The selected month
16866 'monthchange': true,
16868 * @event evententer
16869 * Fires when mouse over an event
16870 * @param {Calendar} this
16871 * @param {event} Event
16873 'evententer': true,
16875 * @event eventleave
16876 * Fires when the mouse leaves an
16877 * @param {Calendar} this
16880 'eventleave': true,
16882 * @event eventclick
16883 * Fires when the mouse click an
16884 * @param {Calendar} this
16893 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16896 * @cfg {Number} startDay
16897 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16905 getAutoCreate : function(){
16908 var fc_button = function(name, corner, style, content ) {
16909 return Roo.apply({},{
16911 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16913 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16916 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16927 style : 'width:100%',
16934 cls : 'fc-header-left',
16936 fc_button('prev', 'left', 'arrow', '‹' ),
16937 fc_button('next', 'right', 'arrow', '›' ),
16938 { tag: 'span', cls: 'fc-header-space' },
16939 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16947 cls : 'fc-header-center',
16951 cls: 'fc-header-title',
16954 html : 'month / year'
16962 cls : 'fc-header-right',
16964 /* fc_button('month', 'left', '', 'month' ),
16965 fc_button('week', '', '', 'week' ),
16966 fc_button('day', 'right', '', 'day' )
16978 header = this.header;
16981 var cal_heads = function() {
16983 // fixme - handle this.
16985 for (var i =0; i < Date.dayNames.length; i++) {
16986 var d = Date.dayNames[i];
16989 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16990 html : d.substring(0,3)
16994 ret[0].cls += ' fc-first';
16995 ret[6].cls += ' fc-last';
16998 var cal_cell = function(n) {
17001 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17006 cls: 'fc-day-number',
17010 cls: 'fc-day-content',
17014 style: 'position: relative;' // height: 17px;
17026 var cal_rows = function() {
17029 for (var r = 0; r < 6; r++) {
17036 for (var i =0; i < Date.dayNames.length; i++) {
17037 var d = Date.dayNames[i];
17038 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17041 row.cn[0].cls+=' fc-first';
17042 row.cn[0].cn[0].style = 'min-height:90px';
17043 row.cn[6].cls+=' fc-last';
17047 ret[0].cls += ' fc-first';
17048 ret[4].cls += ' fc-prev-last';
17049 ret[5].cls += ' fc-last';
17056 cls: 'fc-border-separate',
17057 style : 'width:100%',
17065 cls : 'fc-first fc-last',
17083 cls : 'fc-content',
17084 style : "position: relative;",
17087 cls : 'fc-view fc-view-month fc-grid',
17088 style : 'position: relative',
17089 unselectable : 'on',
17092 cls : 'fc-event-container',
17093 style : 'position:absolute;z-index:8;top:0;left:0;'
17111 initEvents : function()
17114 throw "can not find store for calendar";
17120 style: "text-align:center",
17124 style: "background-color:white;width:50%;margin:250 auto",
17128 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17139 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17141 var size = this.el.select('.fc-content', true).first().getSize();
17142 this.maskEl.setSize(size.width, size.height);
17143 this.maskEl.enableDisplayMode("block");
17144 if(!this.loadMask){
17145 this.maskEl.hide();
17148 this.store = Roo.factory(this.store, Roo.data);
17149 this.store.on('load', this.onLoad, this);
17150 this.store.on('beforeload', this.onBeforeLoad, this);
17154 this.cells = this.el.select('.fc-day',true);
17155 //Roo.log(this.cells);
17156 this.textNodes = this.el.query('.fc-day-number');
17157 this.cells.addClassOnOver('fc-state-hover');
17159 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17160 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17161 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17162 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17164 this.on('monthchange', this.onMonthChange, this);
17166 this.update(new Date().clearTime());
17169 resize : function() {
17170 var sz = this.el.getSize();
17172 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17173 this.el.select('.fc-day-content div',true).setHeight(34);
17178 showPrevMonth : function(e){
17179 this.update(this.activeDate.add("mo", -1));
17181 showToday : function(e){
17182 this.update(new Date().clearTime());
17185 showNextMonth : function(e){
17186 this.update(this.activeDate.add("mo", 1));
17190 showPrevYear : function(){
17191 this.update(this.activeDate.add("y", -1));
17195 showNextYear : function(){
17196 this.update(this.activeDate.add("y", 1));
17201 update : function(date)
17203 var vd = this.activeDate;
17204 this.activeDate = date;
17205 // if(vd && this.el){
17206 // var t = date.getTime();
17207 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17208 // Roo.log('using add remove');
17210 // this.fireEvent('monthchange', this, date);
17212 // this.cells.removeClass("fc-state-highlight");
17213 // this.cells.each(function(c){
17214 // if(c.dateValue == t){
17215 // c.addClass("fc-state-highlight");
17216 // setTimeout(function(){
17217 // try{c.dom.firstChild.focus();}catch(e){}
17227 var days = date.getDaysInMonth();
17229 var firstOfMonth = date.getFirstDateOfMonth();
17230 var startingPos = firstOfMonth.getDay()-this.startDay;
17232 if(startingPos < this.startDay){
17236 var pm = date.add(Date.MONTH, -1);
17237 var prevStart = pm.getDaysInMonth()-startingPos;
17239 this.cells = this.el.select('.fc-day',true);
17240 this.textNodes = this.el.query('.fc-day-number');
17241 this.cells.addClassOnOver('fc-state-hover');
17243 var cells = this.cells.elements;
17244 var textEls = this.textNodes;
17246 Roo.each(cells, function(cell){
17247 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17250 days += startingPos;
17252 // convert everything to numbers so it's fast
17253 var day = 86400000;
17254 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17257 //Roo.log(prevStart);
17259 var today = new Date().clearTime().getTime();
17260 var sel = date.clearTime().getTime();
17261 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17262 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17263 var ddMatch = this.disabledDatesRE;
17264 var ddText = this.disabledDatesText;
17265 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17266 var ddaysText = this.disabledDaysText;
17267 var format = this.format;
17269 var setCellClass = function(cal, cell){
17273 //Roo.log('set Cell Class');
17275 var t = d.getTime();
17279 cell.dateValue = t;
17281 cell.className += " fc-today";
17282 cell.className += " fc-state-highlight";
17283 cell.title = cal.todayText;
17286 // disable highlight in other month..
17287 //cell.className += " fc-state-highlight";
17292 cell.className = " fc-state-disabled";
17293 cell.title = cal.minText;
17297 cell.className = " fc-state-disabled";
17298 cell.title = cal.maxText;
17302 if(ddays.indexOf(d.getDay()) != -1){
17303 cell.title = ddaysText;
17304 cell.className = " fc-state-disabled";
17307 if(ddMatch && format){
17308 var fvalue = d.dateFormat(format);
17309 if(ddMatch.test(fvalue)){
17310 cell.title = ddText.replace("%0", fvalue);
17311 cell.className = " fc-state-disabled";
17315 if (!cell.initialClassName) {
17316 cell.initialClassName = cell.dom.className;
17319 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17324 for(; i < startingPos; i++) {
17325 textEls[i].innerHTML = (++prevStart);
17326 d.setDate(d.getDate()+1);
17328 cells[i].className = "fc-past fc-other-month";
17329 setCellClass(this, cells[i]);
17334 for(; i < days; i++){
17335 intDay = i - startingPos + 1;
17336 textEls[i].innerHTML = (intDay);
17337 d.setDate(d.getDate()+1);
17339 cells[i].className = ''; // "x-date-active";
17340 setCellClass(this, cells[i]);
17344 for(; i < 42; i++) {
17345 textEls[i].innerHTML = (++extraDays);
17346 d.setDate(d.getDate()+1);
17348 cells[i].className = "fc-future fc-other-month";
17349 setCellClass(this, cells[i]);
17352 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17354 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17356 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17357 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17359 if(totalRows != 6){
17360 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17361 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17364 this.fireEvent('monthchange', this, date);
17368 if(!this.internalRender){
17369 var main = this.el.dom.firstChild;
17370 var w = main.offsetWidth;
17371 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17372 Roo.fly(main).setWidth(w);
17373 this.internalRender = true;
17374 // opera does not respect the auto grow header center column
17375 // then, after it gets a width opera refuses to recalculate
17376 // without a second pass
17377 if(Roo.isOpera && !this.secondPass){
17378 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17379 this.secondPass = true;
17380 this.update.defer(10, this, [date]);
17387 findCell : function(dt) {
17388 dt = dt.clearTime().getTime();
17390 this.cells.each(function(c){
17391 //Roo.log("check " +c.dateValue + '?=' + dt);
17392 if(c.dateValue == dt){
17402 findCells : function(ev) {
17403 var s = ev.start.clone().clearTime().getTime();
17405 var e= ev.end.clone().clearTime().getTime();
17408 this.cells.each(function(c){
17409 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17411 if(c.dateValue > e){
17414 if(c.dateValue < s){
17423 // findBestRow: function(cells)
17427 // for (var i =0 ; i < cells.length;i++) {
17428 // ret = Math.max(cells[i].rows || 0,ret);
17435 addItem : function(ev)
17437 // look for vertical location slot in
17438 var cells = this.findCells(ev);
17440 // ev.row = this.findBestRow(cells);
17442 // work out the location.
17446 for(var i =0; i < cells.length; i++) {
17448 cells[i].row = cells[0].row;
17451 cells[i].row = cells[i].row + 1;
17461 if (crow.start.getY() == cells[i].getY()) {
17463 crow.end = cells[i];
17480 cells[0].events.push(ev);
17482 this.calevents.push(ev);
17485 clearEvents: function() {
17487 if(!this.calevents){
17491 Roo.each(this.cells.elements, function(c){
17497 Roo.each(this.calevents, function(e) {
17498 Roo.each(e.els, function(el) {
17499 el.un('mouseenter' ,this.onEventEnter, this);
17500 el.un('mouseleave' ,this.onEventLeave, this);
17505 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17511 renderEvents: function()
17515 this.cells.each(function(c) {
17524 if(c.row != c.events.length){
17525 r = 4 - (4 - (c.row - c.events.length));
17528 c.events = ev.slice(0, r);
17529 c.more = ev.slice(r);
17531 if(c.more.length && c.more.length == 1){
17532 c.events.push(c.more.pop());
17535 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17539 this.cells.each(function(c) {
17541 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17544 for (var e = 0; e < c.events.length; e++){
17545 var ev = c.events[e];
17546 var rows = ev.rows;
17548 for(var i = 0; i < rows.length; i++) {
17550 // how many rows should it span..
17553 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17554 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17556 unselectable : "on",
17559 cls: 'fc-event-inner',
17563 // cls: 'fc-event-time',
17564 // html : cells.length > 1 ? '' : ev.time
17568 cls: 'fc-event-title',
17569 html : String.format('{0}', ev.title)
17576 cls: 'ui-resizable-handle ui-resizable-e',
17577 html : '  '
17584 cfg.cls += ' fc-event-start';
17586 if ((i+1) == rows.length) {
17587 cfg.cls += ' fc-event-end';
17590 var ctr = _this.el.select('.fc-event-container',true).first();
17591 var cg = ctr.createChild(cfg);
17593 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17594 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17596 var r = (c.more.length) ? 1 : 0;
17597 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17598 cg.setWidth(ebox.right - sbox.x -2);
17600 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17601 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17602 cg.on('click', _this.onEventClick, _this, ev);
17613 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17614 style : 'position: absolute',
17615 unselectable : "on",
17618 cls: 'fc-event-inner',
17622 cls: 'fc-event-title',
17630 cls: 'ui-resizable-handle ui-resizable-e',
17631 html : '  '
17637 var ctr = _this.el.select('.fc-event-container',true).first();
17638 var cg = ctr.createChild(cfg);
17640 var sbox = c.select('.fc-day-content',true).first().getBox();
17641 var ebox = c.select('.fc-day-content',true).first().getBox();
17643 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17644 cg.setWidth(ebox.right - sbox.x -2);
17646 cg.on('click', _this.onMoreEventClick, _this, c.more);
17656 onEventEnter: function (e, el,event,d) {
17657 this.fireEvent('evententer', this, el, event);
17660 onEventLeave: function (e, el,event,d) {
17661 this.fireEvent('eventleave', this, el, event);
17664 onEventClick: function (e, el,event,d) {
17665 this.fireEvent('eventclick', this, el, event);
17668 onMonthChange: function () {
17672 onMoreEventClick: function(e, el, more)
17676 this.calpopover.placement = 'right';
17677 this.calpopover.setTitle('More');
17679 this.calpopover.setContent('');
17681 var ctr = this.calpopover.el.select('.popover-content', true).first();
17683 Roo.each(more, function(m){
17685 cls : 'fc-event-hori fc-event-draggable',
17688 var cg = ctr.createChild(cfg);
17690 cg.on('click', _this.onEventClick, _this, m);
17693 this.calpopover.show(el);
17698 onLoad: function ()
17700 this.calevents = [];
17703 if(this.store.getCount() > 0){
17704 this.store.data.each(function(d){
17707 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17708 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17709 time : d.data.start_time,
17710 title : d.data.title,
17711 description : d.data.description,
17712 venue : d.data.venue
17717 this.renderEvents();
17719 if(this.calevents.length && this.loadMask){
17720 this.maskEl.hide();
17724 onBeforeLoad: function()
17726 this.clearEvents();
17728 this.maskEl.show();
17742 * @class Roo.bootstrap.Popover
17743 * @extends Roo.bootstrap.Component
17744 * Bootstrap Popover class
17745 * @cfg {String} html contents of the popover (or false to use children..)
17746 * @cfg {String} title of popover (or false to hide)
17747 * @cfg {String} placement how it is placed
17748 * @cfg {String} trigger click || hover (or false to trigger manually)
17749 * @cfg {String} over what (parent or false to trigger manually.)
17750 * @cfg {Number} delay - delay before showing
17753 * Create a new Popover
17754 * @param {Object} config The config object
17757 Roo.bootstrap.Popover = function(config){
17758 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17764 * After the popover show
17766 * @param {Roo.bootstrap.Popover} this
17771 * After the popover hide
17773 * @param {Roo.bootstrap.Popover} this
17779 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17781 title: 'Fill in a title',
17784 placement : 'right',
17785 trigger : 'hover', // hover
17791 can_build_overlaid : false,
17793 getChildContainer : function()
17795 return this.el.select('.popover-content',true).first();
17798 getAutoCreate : function(){
17801 cls : 'popover roo-dynamic',
17802 style: 'display:block',
17808 cls : 'popover-inner',
17812 cls: 'popover-title popover-header',
17816 cls : 'popover-content popover-body',
17827 setTitle: function(str)
17830 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17832 setContent: function(str)
17835 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17837 // as it get's added to the bottom of the page.
17838 onRender : function(ct, position)
17840 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17842 var cfg = Roo.apply({}, this.getAutoCreate());
17846 cfg.cls += ' ' + this.cls;
17849 cfg.style = this.style;
17851 //Roo.log("adding to ");
17852 this.el = Roo.get(document.body).createChild(cfg, position);
17853 // Roo.log(this.el);
17858 initEvents : function()
17860 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17861 this.el.enableDisplayMode('block');
17863 if (this.over === false) {
17866 if (this.triggers === false) {
17869 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17870 var triggers = this.trigger ? this.trigger.split(' ') : [];
17871 Roo.each(triggers, function(trigger) {
17873 if (trigger == 'click') {
17874 on_el.on('click', this.toggle, this);
17875 } else if (trigger != 'manual') {
17876 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17877 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17879 on_el.on(eventIn ,this.enter, this);
17880 on_el.on(eventOut, this.leave, this);
17891 toggle : function () {
17892 this.hoverState == 'in' ? this.leave() : this.enter();
17895 enter : function () {
17897 clearTimeout(this.timeout);
17899 this.hoverState = 'in';
17901 if (!this.delay || !this.delay.show) {
17906 this.timeout = setTimeout(function () {
17907 if (_t.hoverState == 'in') {
17910 }, this.delay.show)
17913 leave : function() {
17914 clearTimeout(this.timeout);
17916 this.hoverState = 'out';
17918 if (!this.delay || !this.delay.hide) {
17923 this.timeout = setTimeout(function () {
17924 if (_t.hoverState == 'out') {
17927 }, this.delay.hide)
17930 show : function (on_el)
17933 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17937 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17938 if (this.html !== false) {
17939 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17941 this.el.removeClass([
17942 'fade','top','bottom', 'left', 'right','in',
17943 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17945 if (!this.title.length) {
17946 this.el.select('.popover-title',true).hide();
17949 var placement = typeof this.placement == 'function' ?
17950 this.placement.call(this, this.el, on_el) :
17953 var autoToken = /\s?auto?\s?/i;
17954 var autoPlace = autoToken.test(placement);
17956 placement = placement.replace(autoToken, '') || 'top';
17960 //this.el.setXY([0,0]);
17962 this.el.dom.style.display='block';
17963 this.el.addClass(placement);
17965 //this.el.appendTo(on_el);
17967 var p = this.getPosition();
17968 var box = this.el.getBox();
17973 var align = Roo.bootstrap.Popover.alignment[placement];
17976 this.el.alignTo(on_el, align[0],align[1]);
17977 //var arrow = this.el.select('.arrow',true).first();
17978 //arrow.set(align[2],
17980 this.el.addClass('in');
17983 if (this.el.hasClass('fade')) {
17987 this.hoverState = 'in';
17989 this.fireEvent('show', this);
17994 this.el.setXY([0,0]);
17995 this.el.removeClass('in');
17997 this.hoverState = null;
17999 this.fireEvent('hide', this);
18004 Roo.bootstrap.Popover.alignment = {
18005 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18006 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18007 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18008 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18019 * @class Roo.bootstrap.Progress
18020 * @extends Roo.bootstrap.Component
18021 * Bootstrap Progress class
18022 * @cfg {Boolean} striped striped of the progress bar
18023 * @cfg {Boolean} active animated of the progress bar
18027 * Create a new Progress
18028 * @param {Object} config The config object
18031 Roo.bootstrap.Progress = function(config){
18032 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18035 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18040 getAutoCreate : function(){
18048 cfg.cls += ' progress-striped';
18052 cfg.cls += ' active';
18071 * @class Roo.bootstrap.ProgressBar
18072 * @extends Roo.bootstrap.Component
18073 * Bootstrap ProgressBar class
18074 * @cfg {Number} aria_valuenow aria-value now
18075 * @cfg {Number} aria_valuemin aria-value min
18076 * @cfg {Number} aria_valuemax aria-value max
18077 * @cfg {String} label label for the progress bar
18078 * @cfg {String} panel (success | info | warning | danger )
18079 * @cfg {String} role role of the progress bar
18080 * @cfg {String} sr_only text
18084 * Create a new ProgressBar
18085 * @param {Object} config The config object
18088 Roo.bootstrap.ProgressBar = function(config){
18089 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18092 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18096 aria_valuemax : 100,
18102 getAutoCreate : function()
18107 cls: 'progress-bar',
18108 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18120 cfg.role = this.role;
18123 if(this.aria_valuenow){
18124 cfg['aria-valuenow'] = this.aria_valuenow;
18127 if(this.aria_valuemin){
18128 cfg['aria-valuemin'] = this.aria_valuemin;
18131 if(this.aria_valuemax){
18132 cfg['aria-valuemax'] = this.aria_valuemax;
18135 if(this.label && !this.sr_only){
18136 cfg.html = this.label;
18140 cfg.cls += ' progress-bar-' + this.panel;
18146 update : function(aria_valuenow)
18148 this.aria_valuenow = aria_valuenow;
18150 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18165 * @class Roo.bootstrap.TabGroup
18166 * @extends Roo.bootstrap.Column
18167 * Bootstrap Column class
18168 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18169 * @cfg {Boolean} carousel true to make the group behave like a carousel
18170 * @cfg {Boolean} bullets show bullets for the panels
18171 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18172 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18173 * @cfg {Boolean} showarrow (true|false) show arrow default true
18176 * Create a new TabGroup
18177 * @param {Object} config The config object
18180 Roo.bootstrap.TabGroup = function(config){
18181 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18183 this.navId = Roo.id();
18186 Roo.bootstrap.TabGroup.register(this);
18190 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18193 transition : false,
18198 slideOnTouch : false,
18201 getAutoCreate : function()
18203 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18205 cfg.cls += ' tab-content';
18207 if (this.carousel) {
18208 cfg.cls += ' carousel slide';
18211 cls : 'carousel-inner',
18215 if(this.bullets && !Roo.isTouch){
18218 cls : 'carousel-bullets',
18222 if(this.bullets_cls){
18223 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18230 cfg.cn[0].cn.push(bullets);
18233 if(this.showarrow){
18234 cfg.cn[0].cn.push({
18236 class : 'carousel-arrow',
18240 class : 'carousel-prev',
18244 class : 'fa fa-chevron-left'
18250 class : 'carousel-next',
18254 class : 'fa fa-chevron-right'
18267 initEvents: function()
18269 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18270 // this.el.on("touchstart", this.onTouchStart, this);
18273 if(this.autoslide){
18276 this.slideFn = window.setInterval(function() {
18277 _this.showPanelNext();
18281 if(this.showarrow){
18282 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18283 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18289 // onTouchStart : function(e, el, o)
18291 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18295 // this.showPanelNext();
18299 getChildContainer : function()
18301 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18305 * register a Navigation item
18306 * @param {Roo.bootstrap.NavItem} the navitem to add
18308 register : function(item)
18310 this.tabs.push( item);
18311 item.navId = this.navId; // not really needed..
18316 getActivePanel : function()
18319 Roo.each(this.tabs, function(t) {
18329 getPanelByName : function(n)
18332 Roo.each(this.tabs, function(t) {
18333 if (t.tabId == n) {
18341 indexOfPanel : function(p)
18344 Roo.each(this.tabs, function(t,i) {
18345 if (t.tabId == p.tabId) {
18354 * show a specific panel
18355 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18356 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18358 showPanel : function (pan)
18360 if(this.transition || typeof(pan) == 'undefined'){
18361 Roo.log("waiting for the transitionend");
18365 if (typeof(pan) == 'number') {
18366 pan = this.tabs[pan];
18369 if (typeof(pan) == 'string') {
18370 pan = this.getPanelByName(pan);
18373 var cur = this.getActivePanel();
18376 Roo.log('pan or acitve pan is undefined');
18380 if (pan.tabId == this.getActivePanel().tabId) {
18384 if (false === cur.fireEvent('beforedeactivate')) {
18388 if(this.bullets > 0 && !Roo.isTouch){
18389 this.setActiveBullet(this.indexOfPanel(pan));
18392 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18394 //class="carousel-item carousel-item-next carousel-item-left"
18396 this.transition = true;
18397 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18398 var lr = dir == 'next' ? 'left' : 'right';
18399 pan.el.addClass(dir); // or prev
18400 pan.el.addClass('carousel-item-' + dir); // or prev
18401 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18402 cur.el.addClass(lr); // or right
18403 pan.el.addClass(lr);
18404 cur.el.addClass('carousel-item-' +lr); // or right
18405 pan.el.addClass('carousel-item-' +lr);
18409 cur.el.on('transitionend', function() {
18410 Roo.log("trans end?");
18412 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18413 pan.setActive(true);
18415 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18416 cur.setActive(false);
18418 _this.transition = false;
18420 }, this, { single: true } );
18425 cur.setActive(false);
18426 pan.setActive(true);
18431 showPanelNext : function()
18433 var i = this.indexOfPanel(this.getActivePanel());
18435 if (i >= this.tabs.length - 1 && !this.autoslide) {
18439 if (i >= this.tabs.length - 1 && this.autoslide) {
18443 this.showPanel(this.tabs[i+1]);
18446 showPanelPrev : function()
18448 var i = this.indexOfPanel(this.getActivePanel());
18450 if (i < 1 && !this.autoslide) {
18454 if (i < 1 && this.autoslide) {
18455 i = this.tabs.length;
18458 this.showPanel(this.tabs[i-1]);
18462 addBullet: function()
18464 if(!this.bullets || Roo.isTouch){
18467 var ctr = this.el.select('.carousel-bullets',true).first();
18468 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18469 var bullet = ctr.createChild({
18470 cls : 'bullet bullet-' + i
18471 },ctr.dom.lastChild);
18476 bullet.on('click', (function(e, el, o, ii, t){
18478 e.preventDefault();
18480 this.showPanel(ii);
18482 if(this.autoslide && this.slideFn){
18483 clearInterval(this.slideFn);
18484 this.slideFn = window.setInterval(function() {
18485 _this.showPanelNext();
18489 }).createDelegate(this, [i, bullet], true));
18494 setActiveBullet : function(i)
18500 Roo.each(this.el.select('.bullet', true).elements, function(el){
18501 el.removeClass('selected');
18504 var bullet = this.el.select('.bullet-' + i, true).first();
18510 bullet.addClass('selected');
18521 Roo.apply(Roo.bootstrap.TabGroup, {
18525 * register a Navigation Group
18526 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18528 register : function(navgrp)
18530 this.groups[navgrp.navId] = navgrp;
18534 * fetch a Navigation Group based on the navigation ID
18535 * if one does not exist , it will get created.
18536 * @param {string} the navgroup to add
18537 * @returns {Roo.bootstrap.NavGroup} the navgroup
18539 get: function(navId) {
18540 if (typeof(this.groups[navId]) == 'undefined') {
18541 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18543 return this.groups[navId] ;
18558 * @class Roo.bootstrap.TabPanel
18559 * @extends Roo.bootstrap.Component
18560 * Bootstrap TabPanel class
18561 * @cfg {Boolean} active panel active
18562 * @cfg {String} html panel content
18563 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18564 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18565 * @cfg {String} href click to link..
18569 * Create a new TabPanel
18570 * @param {Object} config The config object
18573 Roo.bootstrap.TabPanel = function(config){
18574 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18578 * Fires when the active status changes
18579 * @param {Roo.bootstrap.TabPanel} this
18580 * @param {Boolean} state the new state
18585 * @event beforedeactivate
18586 * Fires before a tab is de-activated - can be used to do validation on a form.
18587 * @param {Roo.bootstrap.TabPanel} this
18588 * @return {Boolean} false if there is an error
18591 'beforedeactivate': true
18594 this.tabId = this.tabId || Roo.id();
18598 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18606 getAutoCreate : function(){
18611 // item is needed for carousel - not sure if it has any effect otherwise
18612 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18613 html: this.html || ''
18617 cfg.cls += ' active';
18621 cfg.tabId = this.tabId;
18629 initEvents: function()
18631 var p = this.parent();
18633 this.navId = this.navId || p.navId;
18635 if (typeof(this.navId) != 'undefined') {
18636 // not really needed.. but just in case.. parent should be a NavGroup.
18637 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18641 var i = tg.tabs.length - 1;
18643 if(this.active && tg.bullets > 0 && i < tg.bullets){
18644 tg.setActiveBullet(i);
18648 this.el.on('click', this.onClick, this);
18651 this.el.on("touchstart", this.onTouchStart, this);
18652 this.el.on("touchmove", this.onTouchMove, this);
18653 this.el.on("touchend", this.onTouchEnd, this);
18658 onRender : function(ct, position)
18660 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18663 setActive : function(state)
18665 Roo.log("panel - set active " + this.tabId + "=" + state);
18667 this.active = state;
18669 this.el.removeClass('active');
18671 } else if (!this.el.hasClass('active')) {
18672 this.el.addClass('active');
18675 this.fireEvent('changed', this, state);
18678 onClick : function(e)
18680 e.preventDefault();
18682 if(!this.href.length){
18686 window.location.href = this.href;
18695 onTouchStart : function(e)
18697 this.swiping = false;
18699 this.startX = e.browserEvent.touches[0].clientX;
18700 this.startY = e.browserEvent.touches[0].clientY;
18703 onTouchMove : function(e)
18705 this.swiping = true;
18707 this.endX = e.browserEvent.touches[0].clientX;
18708 this.endY = e.browserEvent.touches[0].clientY;
18711 onTouchEnd : function(e)
18718 var tabGroup = this.parent();
18720 if(this.endX > this.startX){ // swiping right
18721 tabGroup.showPanelPrev();
18725 if(this.startX > this.endX){ // swiping left
18726 tabGroup.showPanelNext();
18745 * @class Roo.bootstrap.DateField
18746 * @extends Roo.bootstrap.Input
18747 * Bootstrap DateField class
18748 * @cfg {Number} weekStart default 0
18749 * @cfg {String} viewMode default empty, (months|years)
18750 * @cfg {String} minViewMode default empty, (months|years)
18751 * @cfg {Number} startDate default -Infinity
18752 * @cfg {Number} endDate default Infinity
18753 * @cfg {Boolean} todayHighlight default false
18754 * @cfg {Boolean} todayBtn default false
18755 * @cfg {Boolean} calendarWeeks default false
18756 * @cfg {Object} daysOfWeekDisabled default empty
18757 * @cfg {Boolean} singleMode default false (true | false)
18759 * @cfg {Boolean} keyboardNavigation default true
18760 * @cfg {String} language default en
18763 * Create a new DateField
18764 * @param {Object} config The config object
18767 Roo.bootstrap.DateField = function(config){
18768 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18772 * Fires when this field show.
18773 * @param {Roo.bootstrap.DateField} this
18774 * @param {Mixed} date The date value
18779 * Fires when this field hide.
18780 * @param {Roo.bootstrap.DateField} this
18781 * @param {Mixed} date The date value
18786 * Fires when select a date.
18787 * @param {Roo.bootstrap.DateField} this
18788 * @param {Mixed} date The date value
18792 * @event beforeselect
18793 * Fires when before select a date.
18794 * @param {Roo.bootstrap.DateField} this
18795 * @param {Mixed} date The date value
18797 beforeselect : true
18801 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18804 * @cfg {String} format
18805 * The default date format string which can be overriden for localization support. The format must be
18806 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18810 * @cfg {String} altFormats
18811 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18812 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18814 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18822 todayHighlight : false,
18828 keyboardNavigation: true,
18830 calendarWeeks: false,
18832 startDate: -Infinity,
18836 daysOfWeekDisabled: [],
18840 singleMode : false,
18842 UTCDate: function()
18844 return new Date(Date.UTC.apply(Date, arguments));
18847 UTCToday: function()
18849 var today = new Date();
18850 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18853 getDate: function() {
18854 var d = this.getUTCDate();
18855 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18858 getUTCDate: function() {
18862 setDate: function(d) {
18863 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18866 setUTCDate: function(d) {
18868 this.setValue(this.formatDate(this.date));
18871 onRender: function(ct, position)
18874 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18876 this.language = this.language || 'en';
18877 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18878 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18880 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18881 this.format = this.format || 'm/d/y';
18882 this.isInline = false;
18883 this.isInput = true;
18884 this.component = this.el.select('.add-on', true).first() || false;
18885 this.component = (this.component && this.component.length === 0) ? false : this.component;
18886 this.hasInput = this.component && this.inputEl().length;
18888 if (typeof(this.minViewMode === 'string')) {
18889 switch (this.minViewMode) {
18891 this.minViewMode = 1;
18894 this.minViewMode = 2;
18897 this.minViewMode = 0;
18902 if (typeof(this.viewMode === 'string')) {
18903 switch (this.viewMode) {
18916 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18918 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18920 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18922 this.picker().on('mousedown', this.onMousedown, this);
18923 this.picker().on('click', this.onClick, this);
18925 this.picker().addClass('datepicker-dropdown');
18927 this.startViewMode = this.viewMode;
18929 if(this.singleMode){
18930 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18931 v.setVisibilityMode(Roo.Element.DISPLAY);
18935 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18936 v.setStyle('width', '189px');
18940 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18941 if(!this.calendarWeeks){
18946 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18947 v.attr('colspan', function(i, val){
18948 return parseInt(val) + 1;
18953 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18955 this.setStartDate(this.startDate);
18956 this.setEndDate(this.endDate);
18958 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18965 if(this.isInline) {
18970 picker : function()
18972 return this.pickerEl;
18973 // return this.el.select('.datepicker', true).first();
18976 fillDow: function()
18978 var dowCnt = this.weekStart;
18987 if(this.calendarWeeks){
18995 while (dowCnt < this.weekStart + 7) {
18999 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19003 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19006 fillMonths: function()
19009 var months = this.picker().select('>.datepicker-months td', true).first();
19011 months.dom.innerHTML = '';
19017 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19020 months.createChild(month);
19027 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;
19029 if (this.date < this.startDate) {
19030 this.viewDate = new Date(this.startDate);
19031 } else if (this.date > this.endDate) {
19032 this.viewDate = new Date(this.endDate);
19034 this.viewDate = new Date(this.date);
19042 var d = new Date(this.viewDate),
19043 year = d.getUTCFullYear(),
19044 month = d.getUTCMonth(),
19045 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19046 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19047 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19048 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19049 currentDate = this.date && this.date.valueOf(),
19050 today = this.UTCToday();
19052 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19054 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19056 // this.picker.select('>tfoot th.today').
19057 // .text(dates[this.language].today)
19058 // .toggle(this.todayBtn !== false);
19060 this.updateNavArrows();
19063 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19065 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19067 prevMonth.setUTCDate(day);
19069 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19071 var nextMonth = new Date(prevMonth);
19073 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19075 nextMonth = nextMonth.valueOf();
19077 var fillMonths = false;
19079 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19081 while(prevMonth.valueOf() <= nextMonth) {
19084 if (prevMonth.getUTCDay() === this.weekStart) {
19086 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19094 if(this.calendarWeeks){
19095 // ISO 8601: First week contains first thursday.
19096 // ISO also states week starts on Monday, but we can be more abstract here.
19098 // Start of current week: based on weekstart/current date
19099 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19100 // Thursday of this week
19101 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19102 // First Thursday of year, year from thursday
19103 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19104 // Calendar week: ms between thursdays, div ms per day, div 7 days
19105 calWeek = (th - yth) / 864e5 / 7 + 1;
19107 fillMonths.cn.push({
19115 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19117 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19120 if (this.todayHighlight &&
19121 prevMonth.getUTCFullYear() == today.getFullYear() &&
19122 prevMonth.getUTCMonth() == today.getMonth() &&
19123 prevMonth.getUTCDate() == today.getDate()) {
19124 clsName += ' today';
19127 if (currentDate && prevMonth.valueOf() === currentDate) {
19128 clsName += ' active';
19131 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19132 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19133 clsName += ' disabled';
19136 fillMonths.cn.push({
19138 cls: 'day ' + clsName,
19139 html: prevMonth.getDate()
19142 prevMonth.setDate(prevMonth.getDate()+1);
19145 var currentYear = this.date && this.date.getUTCFullYear();
19146 var currentMonth = this.date && this.date.getUTCMonth();
19148 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19150 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19151 v.removeClass('active');
19153 if(currentYear === year && k === currentMonth){
19154 v.addClass('active');
19157 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19158 v.addClass('disabled');
19164 year = parseInt(year/10, 10) * 10;
19166 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19168 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19171 for (var i = -1; i < 11; i++) {
19172 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19174 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19182 showMode: function(dir)
19185 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19188 Roo.each(this.picker().select('>div',true).elements, function(v){
19189 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19192 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19197 if(this.isInline) {
19201 this.picker().removeClass(['bottom', 'top']);
19203 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19205 * place to the top of element!
19209 this.picker().addClass('top');
19210 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19215 this.picker().addClass('bottom');
19217 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19220 parseDate : function(value)
19222 if(!value || value instanceof Date){
19225 var v = Date.parseDate(value, this.format);
19226 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19227 v = Date.parseDate(value, 'Y-m-d');
19229 if(!v && this.altFormats){
19230 if(!this.altFormatsArray){
19231 this.altFormatsArray = this.altFormats.split("|");
19233 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19234 v = Date.parseDate(value, this.altFormatsArray[i]);
19240 formatDate : function(date, fmt)
19242 return (!date || !(date instanceof Date)) ?
19243 date : date.dateFormat(fmt || this.format);
19246 onFocus : function()
19248 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19252 onBlur : function()
19254 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19256 var d = this.inputEl().getValue();
19263 showPopup : function()
19265 this.picker().show();
19269 this.fireEvent('showpopup', this, this.date);
19272 hidePopup : function()
19274 if(this.isInline) {
19277 this.picker().hide();
19278 this.viewMode = this.startViewMode;
19281 this.fireEvent('hidepopup', this, this.date);
19285 onMousedown: function(e)
19287 e.stopPropagation();
19288 e.preventDefault();
19293 Roo.bootstrap.DateField.superclass.keyup.call(this);
19297 setValue: function(v)
19299 if(this.fireEvent('beforeselect', this, v) !== false){
19300 var d = new Date(this.parseDate(v) ).clearTime();
19302 if(isNaN(d.getTime())){
19303 this.date = this.viewDate = '';
19304 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19308 v = this.formatDate(d);
19310 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19312 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19316 this.fireEvent('select', this, this.date);
19320 getValue: function()
19322 return this.formatDate(this.date);
19325 fireKey: function(e)
19327 if (!this.picker().isVisible()){
19328 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19334 var dateChanged = false,
19336 newDate, newViewDate;
19341 e.preventDefault();
19345 if (!this.keyboardNavigation) {
19348 dir = e.keyCode == 37 ? -1 : 1;
19351 newDate = this.moveYear(this.date, dir);
19352 newViewDate = this.moveYear(this.viewDate, dir);
19353 } else if (e.shiftKey){
19354 newDate = this.moveMonth(this.date, dir);
19355 newViewDate = this.moveMonth(this.viewDate, dir);
19357 newDate = new Date(this.date);
19358 newDate.setUTCDate(this.date.getUTCDate() + dir);
19359 newViewDate = new Date(this.viewDate);
19360 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19362 if (this.dateWithinRange(newDate)){
19363 this.date = newDate;
19364 this.viewDate = newViewDate;
19365 this.setValue(this.formatDate(this.date));
19367 e.preventDefault();
19368 dateChanged = true;
19373 if (!this.keyboardNavigation) {
19376 dir = e.keyCode == 38 ? -1 : 1;
19378 newDate = this.moveYear(this.date, dir);
19379 newViewDate = this.moveYear(this.viewDate, dir);
19380 } else if (e.shiftKey){
19381 newDate = this.moveMonth(this.date, dir);
19382 newViewDate = this.moveMonth(this.viewDate, dir);
19384 newDate = new Date(this.date);
19385 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19386 newViewDate = new Date(this.viewDate);
19387 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19389 if (this.dateWithinRange(newDate)){
19390 this.date = newDate;
19391 this.viewDate = newViewDate;
19392 this.setValue(this.formatDate(this.date));
19394 e.preventDefault();
19395 dateChanged = true;
19399 this.setValue(this.formatDate(this.date));
19401 e.preventDefault();
19404 this.setValue(this.formatDate(this.date));
19418 onClick: function(e)
19420 e.stopPropagation();
19421 e.preventDefault();
19423 var target = e.getTarget();
19425 if(target.nodeName.toLowerCase() === 'i'){
19426 target = Roo.get(target).dom.parentNode;
19429 var nodeName = target.nodeName;
19430 var className = target.className;
19431 var html = target.innerHTML;
19432 //Roo.log(nodeName);
19434 switch(nodeName.toLowerCase()) {
19436 switch(className) {
19442 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19443 switch(this.viewMode){
19445 this.viewDate = this.moveMonth(this.viewDate, dir);
19449 this.viewDate = this.moveYear(this.viewDate, dir);
19455 var date = new Date();
19456 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19458 this.setValue(this.formatDate(this.date));
19465 if (className.indexOf('disabled') < 0) {
19466 this.viewDate.setUTCDate(1);
19467 if (className.indexOf('month') > -1) {
19468 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19470 var year = parseInt(html, 10) || 0;
19471 this.viewDate.setUTCFullYear(year);
19475 if(this.singleMode){
19476 this.setValue(this.formatDate(this.viewDate));
19487 //Roo.log(className);
19488 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19489 var day = parseInt(html, 10) || 1;
19490 var year = this.viewDate.getUTCFullYear(),
19491 month = this.viewDate.getUTCMonth();
19493 if (className.indexOf('old') > -1) {
19500 } else if (className.indexOf('new') > -1) {
19508 //Roo.log([year,month,day]);
19509 this.date = this.UTCDate(year, month, day,0,0,0,0);
19510 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19512 //Roo.log(this.formatDate(this.date));
19513 this.setValue(this.formatDate(this.date));
19520 setStartDate: function(startDate)
19522 this.startDate = startDate || -Infinity;
19523 if (this.startDate !== -Infinity) {
19524 this.startDate = this.parseDate(this.startDate);
19527 this.updateNavArrows();
19530 setEndDate: function(endDate)
19532 this.endDate = endDate || Infinity;
19533 if (this.endDate !== Infinity) {
19534 this.endDate = this.parseDate(this.endDate);
19537 this.updateNavArrows();
19540 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19542 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19543 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19544 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19546 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19547 return parseInt(d, 10);
19550 this.updateNavArrows();
19553 updateNavArrows: function()
19555 if(this.singleMode){
19559 var d = new Date(this.viewDate),
19560 year = d.getUTCFullYear(),
19561 month = d.getUTCMonth();
19563 Roo.each(this.picker().select('.prev', true).elements, function(v){
19565 switch (this.viewMode) {
19568 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19574 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19581 Roo.each(this.picker().select('.next', true).elements, function(v){
19583 switch (this.viewMode) {
19586 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19592 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19600 moveMonth: function(date, dir)
19605 var new_date = new Date(date.valueOf()),
19606 day = new_date.getUTCDate(),
19607 month = new_date.getUTCMonth(),
19608 mag = Math.abs(dir),
19610 dir = dir > 0 ? 1 : -1;
19613 // If going back one month, make sure month is not current month
19614 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19616 return new_date.getUTCMonth() == month;
19618 // If going forward one month, make sure month is as expected
19619 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19621 return new_date.getUTCMonth() != new_month;
19623 new_month = month + dir;
19624 new_date.setUTCMonth(new_month);
19625 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19626 if (new_month < 0 || new_month > 11) {
19627 new_month = (new_month + 12) % 12;
19630 // For magnitudes >1, move one month at a time...
19631 for (var i=0; i<mag; i++) {
19632 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19633 new_date = this.moveMonth(new_date, dir);
19635 // ...then reset the day, keeping it in the new month
19636 new_month = new_date.getUTCMonth();
19637 new_date.setUTCDate(day);
19639 return new_month != new_date.getUTCMonth();
19642 // Common date-resetting loop -- if date is beyond end of month, make it
19645 new_date.setUTCDate(--day);
19646 new_date.setUTCMonth(new_month);
19651 moveYear: function(date, dir)
19653 return this.moveMonth(date, dir*12);
19656 dateWithinRange: function(date)
19658 return date >= this.startDate && date <= this.endDate;
19664 this.picker().remove();
19667 validateValue : function(value)
19669 if(this.getVisibilityEl().hasClass('hidden')){
19673 if(value.length < 1) {
19674 if(this.allowBlank){
19680 if(value.length < this.minLength){
19683 if(value.length > this.maxLength){
19687 var vt = Roo.form.VTypes;
19688 if(!vt[this.vtype](value, this)){
19692 if(typeof this.validator == "function"){
19693 var msg = this.validator(value);
19699 if(this.regex && !this.regex.test(value)){
19703 if(typeof(this.parseDate(value)) == 'undefined'){
19707 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19711 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19721 this.date = this.viewDate = '';
19723 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19728 Roo.apply(Roo.bootstrap.DateField, {
19739 html: '<i class="fa fa-arrow-left"/>'
19749 html: '<i class="fa fa-arrow-right"/>'
19791 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19792 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19793 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19794 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19795 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19808 navFnc: 'FullYear',
19813 navFnc: 'FullYear',
19818 Roo.apply(Roo.bootstrap.DateField, {
19822 cls: 'datepicker dropdown-menu roo-dynamic',
19826 cls: 'datepicker-days',
19830 cls: 'table-condensed',
19832 Roo.bootstrap.DateField.head,
19836 Roo.bootstrap.DateField.footer
19843 cls: 'datepicker-months',
19847 cls: 'table-condensed',
19849 Roo.bootstrap.DateField.head,
19850 Roo.bootstrap.DateField.content,
19851 Roo.bootstrap.DateField.footer
19858 cls: 'datepicker-years',
19862 cls: 'table-condensed',
19864 Roo.bootstrap.DateField.head,
19865 Roo.bootstrap.DateField.content,
19866 Roo.bootstrap.DateField.footer
19885 * @class Roo.bootstrap.TimeField
19886 * @extends Roo.bootstrap.Input
19887 * Bootstrap DateField class
19891 * Create a new TimeField
19892 * @param {Object} config The config object
19895 Roo.bootstrap.TimeField = function(config){
19896 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19900 * Fires when this field show.
19901 * @param {Roo.bootstrap.DateField} thisthis
19902 * @param {Mixed} date The date value
19907 * Fires when this field hide.
19908 * @param {Roo.bootstrap.DateField} this
19909 * @param {Mixed} date The date value
19914 * Fires when select a date.
19915 * @param {Roo.bootstrap.DateField} this
19916 * @param {Mixed} date The date value
19922 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19925 * @cfg {String} format
19926 * The default time format string which can be overriden for localization support. The format must be
19927 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19931 onRender: function(ct, position)
19934 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19936 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19938 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19940 this.pop = this.picker().select('>.datepicker-time',true).first();
19941 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19943 this.picker().on('mousedown', this.onMousedown, this);
19944 this.picker().on('click', this.onClick, this);
19946 this.picker().addClass('datepicker-dropdown');
19951 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19952 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19953 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19954 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19955 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19956 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19960 fireKey: function(e){
19961 if (!this.picker().isVisible()){
19962 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19968 e.preventDefault();
19976 this.onTogglePeriod();
19979 this.onIncrementMinutes();
19982 this.onDecrementMinutes();
19991 onClick: function(e) {
19992 e.stopPropagation();
19993 e.preventDefault();
19996 picker : function()
19998 return this.el.select('.datepicker', true).first();
20001 fillTime: function()
20003 var time = this.pop.select('tbody', true).first();
20005 time.dom.innerHTML = '';
20020 cls: 'hours-up glyphicon glyphicon-chevron-up'
20040 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20061 cls: 'timepicker-hour',
20076 cls: 'timepicker-minute',
20091 cls: 'btn btn-primary period',
20113 cls: 'hours-down glyphicon glyphicon-chevron-down'
20133 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20151 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20158 var hours = this.time.getHours();
20159 var minutes = this.time.getMinutes();
20172 hours = hours - 12;
20176 hours = '0' + hours;
20180 minutes = '0' + minutes;
20183 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20184 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20185 this.pop.select('button', true).first().dom.innerHTML = period;
20191 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20193 var cls = ['bottom'];
20195 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20202 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20207 this.picker().addClass(cls.join('-'));
20211 Roo.each(cls, function(c){
20213 _this.picker().setTop(_this.inputEl().getHeight());
20217 _this.picker().setTop(0 - _this.picker().getHeight());
20222 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20226 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20233 onFocus : function()
20235 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20239 onBlur : function()
20241 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20247 this.picker().show();
20252 this.fireEvent('show', this, this.date);
20257 this.picker().hide();
20260 this.fireEvent('hide', this, this.date);
20263 setTime : function()
20266 this.setValue(this.time.format(this.format));
20268 this.fireEvent('select', this, this.date);
20273 onMousedown: function(e){
20274 e.stopPropagation();
20275 e.preventDefault();
20278 onIncrementHours: function()
20280 Roo.log('onIncrementHours');
20281 this.time = this.time.add(Date.HOUR, 1);
20286 onDecrementHours: function()
20288 Roo.log('onDecrementHours');
20289 this.time = this.time.add(Date.HOUR, -1);
20293 onIncrementMinutes: function()
20295 Roo.log('onIncrementMinutes');
20296 this.time = this.time.add(Date.MINUTE, 1);
20300 onDecrementMinutes: function()
20302 Roo.log('onDecrementMinutes');
20303 this.time = this.time.add(Date.MINUTE, -1);
20307 onTogglePeriod: function()
20309 Roo.log('onTogglePeriod');
20310 this.time = this.time.add(Date.HOUR, 12);
20317 Roo.apply(Roo.bootstrap.TimeField, {
20347 cls: 'btn btn-info ok',
20359 Roo.apply(Roo.bootstrap.TimeField, {
20363 cls: 'datepicker dropdown-menu',
20367 cls: 'datepicker-time',
20371 cls: 'table-condensed',
20373 Roo.bootstrap.TimeField.content,
20374 Roo.bootstrap.TimeField.footer
20393 * @class Roo.bootstrap.MonthField
20394 * @extends Roo.bootstrap.Input
20395 * Bootstrap MonthField class
20397 * @cfg {String} language default en
20400 * Create a new MonthField
20401 * @param {Object} config The config object
20404 Roo.bootstrap.MonthField = function(config){
20405 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20410 * Fires when this field show.
20411 * @param {Roo.bootstrap.MonthField} this
20412 * @param {Mixed} date The date value
20417 * Fires when this field hide.
20418 * @param {Roo.bootstrap.MonthField} this
20419 * @param {Mixed} date The date value
20424 * Fires when select a date.
20425 * @param {Roo.bootstrap.MonthField} this
20426 * @param {String} oldvalue The old value
20427 * @param {String} newvalue The new value
20433 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20435 onRender: function(ct, position)
20438 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20440 this.language = this.language || 'en';
20441 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20442 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20444 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20445 this.isInline = false;
20446 this.isInput = true;
20447 this.component = this.el.select('.add-on', true).first() || false;
20448 this.component = (this.component && this.component.length === 0) ? false : this.component;
20449 this.hasInput = this.component && this.inputEL().length;
20451 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20453 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20455 this.picker().on('mousedown', this.onMousedown, this);
20456 this.picker().on('click', this.onClick, this);
20458 this.picker().addClass('datepicker-dropdown');
20460 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20461 v.setStyle('width', '189px');
20468 if(this.isInline) {
20474 setValue: function(v, suppressEvent)
20476 var o = this.getValue();
20478 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20482 if(suppressEvent !== true){
20483 this.fireEvent('select', this, o, v);
20488 getValue: function()
20493 onClick: function(e)
20495 e.stopPropagation();
20496 e.preventDefault();
20498 var target = e.getTarget();
20500 if(target.nodeName.toLowerCase() === 'i'){
20501 target = Roo.get(target).dom.parentNode;
20504 var nodeName = target.nodeName;
20505 var className = target.className;
20506 var html = target.innerHTML;
20508 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20512 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20514 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20520 picker : function()
20522 return this.pickerEl;
20525 fillMonths: function()
20528 var months = this.picker().select('>.datepicker-months td', true).first();
20530 months.dom.innerHTML = '';
20536 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20539 months.createChild(month);
20548 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20549 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20552 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20553 e.removeClass('active');
20555 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20556 e.addClass('active');
20563 if(this.isInline) {
20567 this.picker().removeClass(['bottom', 'top']);
20569 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20571 * place to the top of element!
20575 this.picker().addClass('top');
20576 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20581 this.picker().addClass('bottom');
20583 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20586 onFocus : function()
20588 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20592 onBlur : function()
20594 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20596 var d = this.inputEl().getValue();
20605 this.picker().show();
20606 this.picker().select('>.datepicker-months', true).first().show();
20610 this.fireEvent('show', this, this.date);
20615 if(this.isInline) {
20618 this.picker().hide();
20619 this.fireEvent('hide', this, this.date);
20623 onMousedown: function(e)
20625 e.stopPropagation();
20626 e.preventDefault();
20631 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20635 fireKey: function(e)
20637 if (!this.picker().isVisible()){
20638 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20649 e.preventDefault();
20653 dir = e.keyCode == 37 ? -1 : 1;
20655 this.vIndex = this.vIndex + dir;
20657 if(this.vIndex < 0){
20661 if(this.vIndex > 11){
20665 if(isNaN(this.vIndex)){
20669 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20675 dir = e.keyCode == 38 ? -1 : 1;
20677 this.vIndex = this.vIndex + dir * 4;
20679 if(this.vIndex < 0){
20683 if(this.vIndex > 11){
20687 if(isNaN(this.vIndex)){
20691 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20696 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20697 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20701 e.preventDefault();
20704 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20705 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20721 this.picker().remove();
20726 Roo.apply(Roo.bootstrap.MonthField, {
20745 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20746 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20751 Roo.apply(Roo.bootstrap.MonthField, {
20755 cls: 'datepicker dropdown-menu roo-dynamic',
20759 cls: 'datepicker-months',
20763 cls: 'table-condensed',
20765 Roo.bootstrap.DateField.content
20785 * @class Roo.bootstrap.CheckBox
20786 * @extends Roo.bootstrap.Input
20787 * Bootstrap CheckBox class
20789 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20790 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20791 * @cfg {String} boxLabel The text that appears beside the checkbox
20792 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20793 * @cfg {Boolean} checked initnal the element
20794 * @cfg {Boolean} inline inline the element (default false)
20795 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20796 * @cfg {String} tooltip label tooltip
20799 * Create a new CheckBox
20800 * @param {Object} config The config object
20803 Roo.bootstrap.CheckBox = function(config){
20804 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20809 * Fires when the element is checked or unchecked.
20810 * @param {Roo.bootstrap.CheckBox} this This input
20811 * @param {Boolean} checked The new checked value
20816 * Fires when the element is click.
20817 * @param {Roo.bootstrap.CheckBox} this This input
20824 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20826 inputType: 'checkbox',
20835 getAutoCreate : function()
20837 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20843 cfg.cls = 'form-group ' + this.inputType; //input-group
20846 cfg.cls += ' ' + this.inputType + '-inline';
20852 type : this.inputType,
20853 value : this.inputValue,
20854 cls : 'roo-' + this.inputType, //'form-box',
20855 placeholder : this.placeholder || ''
20859 if(this.inputType != 'radio'){
20863 cls : 'roo-hidden-value',
20864 value : this.checked ? this.inputValue : this.valueOff
20869 if (this.weight) { // Validity check?
20870 cfg.cls += " " + this.inputType + "-" + this.weight;
20873 if (this.disabled) {
20874 input.disabled=true;
20878 input.checked = this.checked;
20883 input.name = this.name;
20885 if(this.inputType != 'radio'){
20886 hidden.name = this.name;
20887 input.name = '_hidden_' + this.name;
20892 input.cls += ' input-' + this.size;
20897 ['xs','sm','md','lg'].map(function(size){
20898 if (settings[size]) {
20899 cfg.cls += ' col-' + size + '-' + settings[size];
20903 var inputblock = input;
20905 if (this.before || this.after) {
20908 cls : 'input-group',
20913 inputblock.cn.push({
20915 cls : 'input-group-addon',
20920 inputblock.cn.push(input);
20922 if(this.inputType != 'radio'){
20923 inputblock.cn.push(hidden);
20927 inputblock.cn.push({
20929 cls : 'input-group-addon',
20936 if (align ==='left' && this.fieldLabel.length) {
20937 // Roo.log("left and has label");
20942 cls : 'control-label',
20943 html : this.fieldLabel
20953 if(this.labelWidth > 12){
20954 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20957 if(this.labelWidth < 13 && this.labelmd == 0){
20958 this.labelmd = this.labelWidth;
20961 if(this.labellg > 0){
20962 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20963 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20966 if(this.labelmd > 0){
20967 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20968 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20971 if(this.labelsm > 0){
20972 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20973 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20976 if(this.labelxs > 0){
20977 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20978 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20981 } else if ( this.fieldLabel.length) {
20982 // Roo.log(" label");
20986 tag: this.boxLabel ? 'span' : 'label',
20988 cls: 'control-label box-input-label',
20989 //cls : 'input-group-addon',
20990 html : this.fieldLabel
20999 // Roo.log(" no label && no align");
21000 cfg.cn = [ inputblock ] ;
21006 var boxLabelCfg = {
21008 //'for': id, // box label is handled by onclick - so no for...
21010 html: this.boxLabel
21014 boxLabelCfg.tooltip = this.tooltip;
21017 cfg.cn.push(boxLabelCfg);
21020 if(this.inputType != 'radio'){
21021 cfg.cn.push(hidden);
21029 * return the real input element.
21031 inputEl: function ()
21033 return this.el.select('input.roo-' + this.inputType,true).first();
21035 hiddenEl: function ()
21037 return this.el.select('input.roo-hidden-value',true).first();
21040 labelEl: function()
21042 return this.el.select('label.control-label',true).first();
21044 /* depricated... */
21048 return this.labelEl();
21051 boxLabelEl: function()
21053 return this.el.select('label.box-label',true).first();
21056 initEvents : function()
21058 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21060 this.inputEl().on('click', this.onClick, this);
21062 if (this.boxLabel) {
21063 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21066 this.startValue = this.getValue();
21069 Roo.bootstrap.CheckBox.register(this);
21073 onClick : function(e)
21075 if(this.fireEvent('click', this, e) !== false){
21076 this.setChecked(!this.checked);
21081 setChecked : function(state,suppressEvent)
21083 this.startValue = this.getValue();
21085 if(this.inputType == 'radio'){
21087 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21088 e.dom.checked = false;
21091 this.inputEl().dom.checked = true;
21093 this.inputEl().dom.value = this.inputValue;
21095 if(suppressEvent !== true){
21096 this.fireEvent('check', this, true);
21104 this.checked = state;
21106 this.inputEl().dom.checked = state;
21109 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21111 if(suppressEvent !== true){
21112 this.fireEvent('check', this, state);
21118 getValue : function()
21120 if(this.inputType == 'radio'){
21121 return this.getGroupValue();
21124 return this.hiddenEl().dom.value;
21128 getGroupValue : function()
21130 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21134 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21137 setValue : function(v,suppressEvent)
21139 if(this.inputType == 'radio'){
21140 this.setGroupValue(v, suppressEvent);
21144 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21149 setGroupValue : function(v, suppressEvent)
21151 this.startValue = this.getValue();
21153 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21154 e.dom.checked = false;
21156 if(e.dom.value == v){
21157 e.dom.checked = true;
21161 if(suppressEvent !== true){
21162 this.fireEvent('check', this, true);
21170 validate : function()
21172 if(this.getVisibilityEl().hasClass('hidden')){
21178 (this.inputType == 'radio' && this.validateRadio()) ||
21179 (this.inputType == 'checkbox' && this.validateCheckbox())
21185 this.markInvalid();
21189 validateRadio : function()
21191 if(this.getVisibilityEl().hasClass('hidden')){
21195 if(this.allowBlank){
21201 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21202 if(!e.dom.checked){
21214 validateCheckbox : function()
21217 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21218 //return (this.getValue() == this.inputValue) ? true : false;
21221 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21229 for(var i in group){
21230 if(group[i].el.isVisible(true)){
21238 for(var i in group){
21243 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21250 * Mark this field as valid
21252 markValid : function()
21256 this.fireEvent('valid', this);
21258 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21261 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21268 if(this.inputType == 'radio'){
21269 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21270 var fg = e.findParent('.form-group', false, true);
21271 if (Roo.bootstrap.version == 3) {
21272 fg.removeClass([_this.invalidClass, _this.validClass]);
21273 fg.addClass(_this.validClass);
21275 fg.removeClass(['is-valid', 'is-invalid']);
21276 fg.addClass('is-valid');
21284 var fg = this.el.findParent('.form-group', false, true);
21285 if (Roo.bootstrap.version == 3) {
21286 fg.removeClass([this.invalidClass, this.validClass]);
21287 fg.addClass(this.validClass);
21289 fg.removeClass(['is-valid', 'is-invalid']);
21290 fg.addClass('is-valid');
21295 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21301 for(var i in group){
21302 var fg = group[i].el.findParent('.form-group', false, true);
21303 if (Roo.bootstrap.version == 3) {
21304 fg.removeClass([this.invalidClass, this.validClass]);
21305 fg.addClass(this.validClass);
21307 fg.removeClass(['is-valid', 'is-invalid']);
21308 fg.addClass('is-valid');
21314 * Mark this field as invalid
21315 * @param {String} msg The validation message
21317 markInvalid : function(msg)
21319 if(this.allowBlank){
21325 this.fireEvent('invalid', this, msg);
21327 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21330 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21334 label.markInvalid();
21337 if(this.inputType == 'radio'){
21339 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21340 var fg = e.findParent('.form-group', false, true);
21341 if (Roo.bootstrap.version == 3) {
21342 fg.removeClass([_this.invalidClass, _this.validClass]);
21343 fg.addClass(_this.invalidClass);
21345 fg.removeClass(['is-invalid', 'is-valid']);
21346 fg.addClass('is-invalid');
21354 var fg = this.el.findParent('.form-group', false, true);
21355 if (Roo.bootstrap.version == 3) {
21356 fg.removeClass([_this.invalidClass, _this.validClass]);
21357 fg.addClass(_this.invalidClass);
21359 fg.removeClass(['is-invalid', 'is-valid']);
21360 fg.addClass('is-invalid');
21365 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21371 for(var i in group){
21372 var fg = group[i].el.findParent('.form-group', false, true);
21373 if (Roo.bootstrap.version == 3) {
21374 fg.removeClass([_this.invalidClass, _this.validClass]);
21375 fg.addClass(_this.invalidClass);
21377 fg.removeClass(['is-invalid', 'is-valid']);
21378 fg.addClass('is-invalid');
21384 clearInvalid : function()
21386 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21388 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21390 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21392 if (label && label.iconEl) {
21393 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21394 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21398 disable : function()
21400 if(this.inputType != 'radio'){
21401 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21408 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21409 _this.getActionEl().addClass(this.disabledClass);
21410 e.dom.disabled = true;
21414 this.disabled = true;
21415 this.fireEvent("disable", this);
21419 enable : function()
21421 if(this.inputType != 'radio'){
21422 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21429 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21430 _this.getActionEl().removeClass(this.disabledClass);
21431 e.dom.disabled = false;
21435 this.disabled = false;
21436 this.fireEvent("enable", this);
21440 setBoxLabel : function(v)
21445 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21451 Roo.apply(Roo.bootstrap.CheckBox, {
21456 * register a CheckBox Group
21457 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21459 register : function(checkbox)
21461 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21462 this.groups[checkbox.groupId] = {};
21465 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21469 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21473 * fetch a CheckBox Group based on the group ID
21474 * @param {string} the group ID
21475 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21477 get: function(groupId) {
21478 if (typeof(this.groups[groupId]) == 'undefined') {
21482 return this.groups[groupId] ;
21495 * @class Roo.bootstrap.Radio
21496 * @extends Roo.bootstrap.Component
21497 * Bootstrap Radio class
21498 * @cfg {String} boxLabel - the label associated
21499 * @cfg {String} value - the value of radio
21502 * Create a new Radio
21503 * @param {Object} config The config object
21505 Roo.bootstrap.Radio = function(config){
21506 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21510 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21516 getAutoCreate : function()
21520 cls : 'form-group radio',
21525 html : this.boxLabel
21533 initEvents : function()
21535 this.parent().register(this);
21537 this.el.on('click', this.onClick, this);
21541 onClick : function(e)
21543 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21544 this.setChecked(true);
21548 setChecked : function(state, suppressEvent)
21550 this.parent().setValue(this.value, suppressEvent);
21554 setBoxLabel : function(v)
21559 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21574 * @class Roo.bootstrap.SecurePass
21575 * @extends Roo.bootstrap.Input
21576 * Bootstrap SecurePass class
21580 * Create a new SecurePass
21581 * @param {Object} config The config object
21584 Roo.bootstrap.SecurePass = function (config) {
21585 // these go here, so the translation tool can replace them..
21587 PwdEmpty: "Please type a password, and then retype it to confirm.",
21588 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21589 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21590 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21591 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21592 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21593 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21594 TooWeak: "Your password is Too Weak."
21596 this.meterLabel = "Password strength:";
21597 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21598 this.meterClass = [
21599 "roo-password-meter-tooweak",
21600 "roo-password-meter-weak",
21601 "roo-password-meter-medium",
21602 "roo-password-meter-strong",
21603 "roo-password-meter-grey"
21608 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21611 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21613 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21615 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21616 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21617 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21618 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21619 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21620 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21621 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21631 * @cfg {String/Object} Label for the strength meter (defaults to
21632 * 'Password strength:')
21637 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21638 * ['Weak', 'Medium', 'Strong'])
21641 pwdStrengths: false,
21654 initEvents: function ()
21656 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21658 if (this.el.is('input[type=password]') && Roo.isSafari) {
21659 this.el.on('keydown', this.SafariOnKeyDown, this);
21662 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21665 onRender: function (ct, position)
21667 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21668 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21669 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21671 this.trigger.createChild({
21676 cls: 'roo-password-meter-grey col-xs-12',
21679 //width: this.meterWidth + 'px'
21683 cls: 'roo-password-meter-text'
21689 if (this.hideTrigger) {
21690 this.trigger.setDisplayed(false);
21692 this.setSize(this.width || '', this.height || '');
21695 onDestroy: function ()
21697 if (this.trigger) {
21698 this.trigger.removeAllListeners();
21699 this.trigger.remove();
21702 this.wrap.remove();
21704 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21707 checkStrength: function ()
21709 var pwd = this.inputEl().getValue();
21710 if (pwd == this._lastPwd) {
21715 if (this.ClientSideStrongPassword(pwd)) {
21717 } else if (this.ClientSideMediumPassword(pwd)) {
21719 } else if (this.ClientSideWeakPassword(pwd)) {
21725 Roo.log('strength1: ' + strength);
21727 //var pm = this.trigger.child('div/div/div').dom;
21728 var pm = this.trigger.child('div/div');
21729 pm.removeClass(this.meterClass);
21730 pm.addClass(this.meterClass[strength]);
21733 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21735 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21737 this._lastPwd = pwd;
21741 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21743 this._lastPwd = '';
21745 var pm = this.trigger.child('div/div');
21746 pm.removeClass(this.meterClass);
21747 pm.addClass('roo-password-meter-grey');
21750 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21753 this.inputEl().dom.type='password';
21756 validateValue: function (value)
21759 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21762 if (value.length == 0) {
21763 if (this.allowBlank) {
21764 this.clearInvalid();
21768 this.markInvalid(this.errors.PwdEmpty);
21769 this.errorMsg = this.errors.PwdEmpty;
21777 if ('[\x21-\x7e]*'.match(value)) {
21778 this.markInvalid(this.errors.PwdBadChar);
21779 this.errorMsg = this.errors.PwdBadChar;
21782 if (value.length < 6) {
21783 this.markInvalid(this.errors.PwdShort);
21784 this.errorMsg = this.errors.PwdShort;
21787 if (value.length > 16) {
21788 this.markInvalid(this.errors.PwdLong);
21789 this.errorMsg = this.errors.PwdLong;
21793 if (this.ClientSideStrongPassword(value)) {
21795 } else if (this.ClientSideMediumPassword(value)) {
21797 } else if (this.ClientSideWeakPassword(value)) {
21804 if (strength < 2) {
21805 //this.markInvalid(this.errors.TooWeak);
21806 this.errorMsg = this.errors.TooWeak;
21811 console.log('strength2: ' + strength);
21813 //var pm = this.trigger.child('div/div/div').dom;
21815 var pm = this.trigger.child('div/div');
21816 pm.removeClass(this.meterClass);
21817 pm.addClass(this.meterClass[strength]);
21819 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21821 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21823 this.errorMsg = '';
21827 CharacterSetChecks: function (type)
21830 this.fResult = false;
21833 isctype: function (character, type)
21836 case this.kCapitalLetter:
21837 if (character >= 'A' && character <= 'Z') {
21842 case this.kSmallLetter:
21843 if (character >= 'a' && character <= 'z') {
21849 if (character >= '0' && character <= '9') {
21854 case this.kPunctuation:
21855 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21866 IsLongEnough: function (pwd, size)
21868 return !(pwd == null || isNaN(size) || pwd.length < size);
21871 SpansEnoughCharacterSets: function (word, nb)
21873 if (!this.IsLongEnough(word, nb))
21878 var characterSetChecks = new Array(
21879 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21880 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21883 for (var index = 0; index < word.length; ++index) {
21884 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21885 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21886 characterSetChecks[nCharSet].fResult = true;
21893 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21894 if (characterSetChecks[nCharSet].fResult) {
21899 if (nCharSets < nb) {
21905 ClientSideStrongPassword: function (pwd)
21907 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21910 ClientSideMediumPassword: function (pwd)
21912 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21915 ClientSideWeakPassword: function (pwd)
21917 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21920 })//<script type="text/javascript">
21923 * Based Ext JS Library 1.1.1
21924 * Copyright(c) 2006-2007, Ext JS, LLC.
21930 * @class Roo.HtmlEditorCore
21931 * @extends Roo.Component
21932 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21934 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21937 Roo.HtmlEditorCore = function(config){
21940 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21945 * @event initialize
21946 * Fires when the editor is fully initialized (including the iframe)
21947 * @param {Roo.HtmlEditorCore} this
21952 * Fires when the editor is first receives the focus. Any insertion must wait
21953 * until after this event.
21954 * @param {Roo.HtmlEditorCore} this
21958 * @event beforesync
21959 * Fires before the textarea is updated with content from the editor iframe. Return false
21960 * to cancel the sync.
21961 * @param {Roo.HtmlEditorCore} this
21962 * @param {String} html
21966 * @event beforepush
21967 * Fires before the iframe editor is updated with content from the textarea. Return false
21968 * to cancel the push.
21969 * @param {Roo.HtmlEditorCore} this
21970 * @param {String} html
21975 * Fires when the textarea is updated with content from the editor iframe.
21976 * @param {Roo.HtmlEditorCore} this
21977 * @param {String} html
21982 * Fires when the iframe editor is updated with content from the textarea.
21983 * @param {Roo.HtmlEditorCore} this
21984 * @param {String} html
21989 * @event editorevent
21990 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21991 * @param {Roo.HtmlEditorCore} this
21997 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21999 // defaults : white / black...
22000 this.applyBlacklists();
22007 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22011 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22017 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22022 * @cfg {Number} height (in pixels)
22026 * @cfg {Number} width (in pixels)
22031 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22034 stylesheets: false,
22039 // private properties
22040 validationEvent : false,
22042 initialized : false,
22044 sourceEditMode : false,
22045 onFocus : Roo.emptyFn,
22047 hideMode:'offsets',
22051 // blacklist + whitelisted elements..
22058 * Protected method that will not generally be called directly. It
22059 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22060 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22062 getDocMarkup : function(){
22066 // inherit styels from page...??
22067 if (this.stylesheets === false) {
22069 Roo.get(document.head).select('style').each(function(node) {
22070 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22073 Roo.get(document.head).select('link').each(function(node) {
22074 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22077 } else if (!this.stylesheets.length) {
22079 st = '<style type="text/css">' +
22080 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22083 st = '<style type="text/css">' +
22088 st += '<style type="text/css">' +
22089 'IMG { cursor: pointer } ' +
22092 var cls = 'roo-htmleditor-body';
22094 if(this.bodyCls.length){
22095 cls += ' ' + this.bodyCls;
22098 return '<html><head>' + st +
22099 //<style type="text/css">' +
22100 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22102 ' </head><body class="' + cls + '"></body></html>';
22106 onRender : function(ct, position)
22109 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22110 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22113 this.el.dom.style.border = '0 none';
22114 this.el.dom.setAttribute('tabIndex', -1);
22115 this.el.addClass('x-hidden hide');
22119 if(Roo.isIE){ // fix IE 1px bogus margin
22120 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22124 this.frameId = Roo.id();
22128 var iframe = this.owner.wrap.createChild({
22130 cls: 'form-control', // bootstrap..
22132 name: this.frameId,
22133 frameBorder : 'no',
22134 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22139 this.iframe = iframe.dom;
22141 this.assignDocWin();
22143 this.doc.designMode = 'on';
22146 this.doc.write(this.getDocMarkup());
22150 var task = { // must defer to wait for browser to be ready
22152 //console.log("run task?" + this.doc.readyState);
22153 this.assignDocWin();
22154 if(this.doc.body || this.doc.readyState == 'complete'){
22156 this.doc.designMode="on";
22160 Roo.TaskMgr.stop(task);
22161 this.initEditor.defer(10, this);
22168 Roo.TaskMgr.start(task);
22173 onResize : function(w, h)
22175 Roo.log('resize: ' +w + ',' + h );
22176 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22180 if(typeof w == 'number'){
22182 this.iframe.style.width = w + 'px';
22184 if(typeof h == 'number'){
22186 this.iframe.style.height = h + 'px';
22188 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22195 * Toggles the editor between standard and source edit mode.
22196 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22198 toggleSourceEdit : function(sourceEditMode){
22200 this.sourceEditMode = sourceEditMode === true;
22202 if(this.sourceEditMode){
22204 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22207 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22208 //this.iframe.className = '';
22211 //this.setSize(this.owner.wrap.getSize());
22212 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22219 * Protected method that will not generally be called directly. If you need/want
22220 * custom HTML cleanup, this is the method you should override.
22221 * @param {String} html The HTML to be cleaned
22222 * return {String} The cleaned HTML
22224 cleanHtml : function(html){
22225 html = String(html);
22226 if(html.length > 5){
22227 if(Roo.isSafari){ // strip safari nonsense
22228 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22231 if(html == ' '){
22238 * HTML Editor -> Textarea
22239 * Protected method that will not generally be called directly. Syncs the contents
22240 * of the editor iframe with the textarea.
22242 syncValue : function(){
22243 if(this.initialized){
22244 var bd = (this.doc.body || this.doc.documentElement);
22245 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22246 var html = bd.innerHTML;
22248 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22249 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22251 html = '<div style="'+m[0]+'">' + html + '</div>';
22254 html = this.cleanHtml(html);
22255 // fix up the special chars.. normaly like back quotes in word...
22256 // however we do not want to do this with chinese..
22257 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22258 var cc = b.charCodeAt();
22260 (cc >= 0x4E00 && cc < 0xA000 ) ||
22261 (cc >= 0x3400 && cc < 0x4E00 ) ||
22262 (cc >= 0xf900 && cc < 0xfb00 )
22268 if(this.owner.fireEvent('beforesync', this, html) !== false){
22269 this.el.dom.value = html;
22270 this.owner.fireEvent('sync', this, html);
22276 * Protected method that will not generally be called directly. Pushes the value of the textarea
22277 * into the iframe editor.
22279 pushValue : function(){
22280 if(this.initialized){
22281 var v = this.el.dom.value.trim();
22283 // if(v.length < 1){
22287 if(this.owner.fireEvent('beforepush', this, v) !== false){
22288 var d = (this.doc.body || this.doc.documentElement);
22290 this.cleanUpPaste();
22291 this.el.dom.value = d.innerHTML;
22292 this.owner.fireEvent('push', this, v);
22298 deferFocus : function(){
22299 this.focus.defer(10, this);
22303 focus : function(){
22304 if(this.win && !this.sourceEditMode){
22311 assignDocWin: function()
22313 var iframe = this.iframe;
22316 this.doc = iframe.contentWindow.document;
22317 this.win = iframe.contentWindow;
22319 // if (!Roo.get(this.frameId)) {
22322 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22323 // this.win = Roo.get(this.frameId).dom.contentWindow;
22325 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22329 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22330 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22335 initEditor : function(){
22336 //console.log("INIT EDITOR");
22337 this.assignDocWin();
22341 this.doc.designMode="on";
22343 this.doc.write(this.getDocMarkup());
22346 var dbody = (this.doc.body || this.doc.documentElement);
22347 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22348 // this copies styles from the containing element into thsi one..
22349 // not sure why we need all of this..
22350 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22352 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22353 //ss['background-attachment'] = 'fixed'; // w3c
22354 dbody.bgProperties = 'fixed'; // ie
22355 //Roo.DomHelper.applyStyles(dbody, ss);
22356 Roo.EventManager.on(this.doc, {
22357 //'mousedown': this.onEditorEvent,
22358 'mouseup': this.onEditorEvent,
22359 'dblclick': this.onEditorEvent,
22360 'click': this.onEditorEvent,
22361 'keyup': this.onEditorEvent,
22366 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22368 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22369 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22371 this.initialized = true;
22373 this.owner.fireEvent('initialize', this);
22378 onDestroy : function(){
22384 //for (var i =0; i < this.toolbars.length;i++) {
22385 // // fixme - ask toolbars for heights?
22386 // this.toolbars[i].onDestroy();
22389 //this.wrap.dom.innerHTML = '';
22390 //this.wrap.remove();
22395 onFirstFocus : function(){
22397 this.assignDocWin();
22400 this.activated = true;
22403 if(Roo.isGecko){ // prevent silly gecko errors
22405 var s = this.win.getSelection();
22406 if(!s.focusNode || s.focusNode.nodeType != 3){
22407 var r = s.getRangeAt(0);
22408 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22413 this.execCmd('useCSS', true);
22414 this.execCmd('styleWithCSS', false);
22417 this.owner.fireEvent('activate', this);
22421 adjustFont: function(btn){
22422 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22423 //if(Roo.isSafari){ // safari
22426 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22427 if(Roo.isSafari){ // safari
22428 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22429 v = (v < 10) ? 10 : v;
22430 v = (v > 48) ? 48 : v;
22431 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22436 v = Math.max(1, v+adjust);
22438 this.execCmd('FontSize', v );
22441 onEditorEvent : function(e)
22443 this.owner.fireEvent('editorevent', this, e);
22444 // this.updateToolbar();
22445 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22448 insertTag : function(tg)
22450 // could be a bit smarter... -> wrap the current selected tRoo..
22451 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22453 range = this.createRange(this.getSelection());
22454 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22455 wrappingNode.appendChild(range.extractContents());
22456 range.insertNode(wrappingNode);
22463 this.execCmd("formatblock", tg);
22467 insertText : function(txt)
22471 var range = this.createRange();
22472 range.deleteContents();
22473 //alert(Sender.getAttribute('label'));
22475 range.insertNode(this.doc.createTextNode(txt));
22481 * Executes a Midas editor command on the editor document and performs necessary focus and
22482 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22483 * @param {String} cmd The Midas command
22484 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22486 relayCmd : function(cmd, value){
22488 this.execCmd(cmd, value);
22489 this.owner.fireEvent('editorevent', this);
22490 //this.updateToolbar();
22491 this.owner.deferFocus();
22495 * Executes a Midas editor command directly on the editor document.
22496 * For visual commands, you should use {@link #relayCmd} instead.
22497 * <b>This should only be called after the editor is initialized.</b>
22498 * @param {String} cmd The Midas command
22499 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22501 execCmd : function(cmd, value){
22502 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22509 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22511 * @param {String} text | dom node..
22513 insertAtCursor : function(text)
22516 if(!this.activated){
22522 var r = this.doc.selection.createRange();
22533 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22537 // from jquery ui (MIT licenced)
22539 var win = this.win;
22541 if (win.getSelection && win.getSelection().getRangeAt) {
22542 range = win.getSelection().getRangeAt(0);
22543 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22544 range.insertNode(node);
22545 } else if (win.document.selection && win.document.selection.createRange) {
22546 // no firefox support
22547 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22548 win.document.selection.createRange().pasteHTML(txt);
22550 // no firefox support
22551 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22552 this.execCmd('InsertHTML', txt);
22561 mozKeyPress : function(e){
22563 var c = e.getCharCode(), cmd;
22566 c = String.fromCharCode(c).toLowerCase();
22580 this.cleanUpPaste.defer(100, this);
22588 e.preventDefault();
22596 fixKeys : function(){ // load time branching for fastest keydown performance
22598 return function(e){
22599 var k = e.getKey(), r;
22602 r = this.doc.selection.createRange();
22605 r.pasteHTML('    ');
22612 r = this.doc.selection.createRange();
22614 var target = r.parentElement();
22615 if(!target || target.tagName.toLowerCase() != 'li'){
22617 r.pasteHTML('<br />');
22623 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22624 this.cleanUpPaste.defer(100, this);
22630 }else if(Roo.isOpera){
22631 return function(e){
22632 var k = e.getKey();
22636 this.execCmd('InsertHTML','    ');
22639 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22640 this.cleanUpPaste.defer(100, this);
22645 }else if(Roo.isSafari){
22646 return function(e){
22647 var k = e.getKey();
22651 this.execCmd('InsertText','\t');
22655 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22656 this.cleanUpPaste.defer(100, this);
22664 getAllAncestors: function()
22666 var p = this.getSelectedNode();
22669 a.push(p); // push blank onto stack..
22670 p = this.getParentElement();
22674 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22678 a.push(this.doc.body);
22682 lastSelNode : false,
22685 getSelection : function()
22687 this.assignDocWin();
22688 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22691 getSelectedNode: function()
22693 // this may only work on Gecko!!!
22695 // should we cache this!!!!
22700 var range = this.createRange(this.getSelection()).cloneRange();
22703 var parent = range.parentElement();
22705 var testRange = range.duplicate();
22706 testRange.moveToElementText(parent);
22707 if (testRange.inRange(range)) {
22710 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22713 parent = parent.parentElement;
22718 // is ancestor a text element.
22719 var ac = range.commonAncestorContainer;
22720 if (ac.nodeType == 3) {
22721 ac = ac.parentNode;
22724 var ar = ac.childNodes;
22727 var other_nodes = [];
22728 var has_other_nodes = false;
22729 for (var i=0;i<ar.length;i++) {
22730 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22733 // fullly contained node.
22735 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22740 // probably selected..
22741 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22742 other_nodes.push(ar[i]);
22746 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22751 has_other_nodes = true;
22753 if (!nodes.length && other_nodes.length) {
22754 nodes= other_nodes;
22756 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22762 createRange: function(sel)
22764 // this has strange effects when using with
22765 // top toolbar - not sure if it's a great idea.
22766 //this.editor.contentWindow.focus();
22767 if (typeof sel != "undefined") {
22769 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22771 return this.doc.createRange();
22774 return this.doc.createRange();
22777 getParentElement: function()
22780 this.assignDocWin();
22781 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22783 var range = this.createRange(sel);
22786 var p = range.commonAncestorContainer;
22787 while (p.nodeType == 3) { // text node
22798 * Range intersection.. the hard stuff...
22802 * [ -- selected range --- ]
22806 * if end is before start or hits it. fail.
22807 * if start is after end or hits it fail.
22809 * if either hits (but other is outside. - then it's not
22815 // @see http://www.thismuchiknow.co.uk/?p=64.
22816 rangeIntersectsNode : function(range, node)
22818 var nodeRange = node.ownerDocument.createRange();
22820 nodeRange.selectNode(node);
22822 nodeRange.selectNodeContents(node);
22825 var rangeStartRange = range.cloneRange();
22826 rangeStartRange.collapse(true);
22828 var rangeEndRange = range.cloneRange();
22829 rangeEndRange.collapse(false);
22831 var nodeStartRange = nodeRange.cloneRange();
22832 nodeStartRange.collapse(true);
22834 var nodeEndRange = nodeRange.cloneRange();
22835 nodeEndRange.collapse(false);
22837 return rangeStartRange.compareBoundaryPoints(
22838 Range.START_TO_START, nodeEndRange) == -1 &&
22839 rangeEndRange.compareBoundaryPoints(
22840 Range.START_TO_START, nodeStartRange) == 1;
22844 rangeCompareNode : function(range, node)
22846 var nodeRange = node.ownerDocument.createRange();
22848 nodeRange.selectNode(node);
22850 nodeRange.selectNodeContents(node);
22854 range.collapse(true);
22856 nodeRange.collapse(true);
22858 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22859 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22861 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22863 var nodeIsBefore = ss == 1;
22864 var nodeIsAfter = ee == -1;
22866 if (nodeIsBefore && nodeIsAfter) {
22869 if (!nodeIsBefore && nodeIsAfter) {
22870 return 1; //right trailed.
22873 if (nodeIsBefore && !nodeIsAfter) {
22874 return 2; // left trailed.
22880 // private? - in a new class?
22881 cleanUpPaste : function()
22883 // cleans up the whole document..
22884 Roo.log('cleanuppaste');
22886 this.cleanUpChildren(this.doc.body);
22887 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22888 if (clean != this.doc.body.innerHTML) {
22889 this.doc.body.innerHTML = clean;
22894 cleanWordChars : function(input) {// change the chars to hex code
22895 var he = Roo.HtmlEditorCore;
22897 var output = input;
22898 Roo.each(he.swapCodes, function(sw) {
22899 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22901 output = output.replace(swapper, sw[1]);
22908 cleanUpChildren : function (n)
22910 if (!n.childNodes.length) {
22913 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22914 this.cleanUpChild(n.childNodes[i]);
22921 cleanUpChild : function (node)
22924 //console.log(node);
22925 if (node.nodeName == "#text") {
22926 // clean up silly Windows -- stuff?
22929 if (node.nodeName == "#comment") {
22930 node.parentNode.removeChild(node);
22931 // clean up silly Windows -- stuff?
22934 var lcname = node.tagName.toLowerCase();
22935 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22936 // whitelist of tags..
22938 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22940 node.parentNode.removeChild(node);
22945 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22947 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22948 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22950 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22951 // remove_keep_children = true;
22954 if (remove_keep_children) {
22955 this.cleanUpChildren(node);
22956 // inserts everything just before this node...
22957 while (node.childNodes.length) {
22958 var cn = node.childNodes[0];
22959 node.removeChild(cn);
22960 node.parentNode.insertBefore(cn, node);
22962 node.parentNode.removeChild(node);
22966 if (!node.attributes || !node.attributes.length) {
22967 this.cleanUpChildren(node);
22971 function cleanAttr(n,v)
22974 if (v.match(/^\./) || v.match(/^\//)) {
22977 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22980 if (v.match(/^#/)) {
22983 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22984 node.removeAttribute(n);
22988 var cwhite = this.cwhite;
22989 var cblack = this.cblack;
22991 function cleanStyle(n,v)
22993 if (v.match(/expression/)) { //XSS?? should we even bother..
22994 node.removeAttribute(n);
22998 var parts = v.split(/;/);
23001 Roo.each(parts, function(p) {
23002 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23006 var l = p.split(':').shift().replace(/\s+/g,'');
23007 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23009 if ( cwhite.length && cblack.indexOf(l) > -1) {
23010 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23011 //node.removeAttribute(n);
23015 // only allow 'c whitelisted system attributes'
23016 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23017 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23018 //node.removeAttribute(n);
23028 if (clean.length) {
23029 node.setAttribute(n, clean.join(';'));
23031 node.removeAttribute(n);
23037 for (var i = node.attributes.length-1; i > -1 ; i--) {
23038 var a = node.attributes[i];
23041 if (a.name.toLowerCase().substr(0,2)=='on') {
23042 node.removeAttribute(a.name);
23045 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23046 node.removeAttribute(a.name);
23049 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23050 cleanAttr(a.name,a.value); // fixme..
23053 if (a.name == 'style') {
23054 cleanStyle(a.name,a.value);
23057 /// clean up MS crap..
23058 // tecnically this should be a list of valid class'es..
23061 if (a.name == 'class') {
23062 if (a.value.match(/^Mso/)) {
23063 node.className = '';
23066 if (a.value.match(/^body$/)) {
23067 node.className = '';
23078 this.cleanUpChildren(node);
23084 * Clean up MS wordisms...
23086 cleanWord : function(node)
23091 this.cleanWord(this.doc.body);
23094 if (node.nodeName == "#text") {
23095 // clean up silly Windows -- stuff?
23098 if (node.nodeName == "#comment") {
23099 node.parentNode.removeChild(node);
23100 // clean up silly Windows -- stuff?
23104 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23105 node.parentNode.removeChild(node);
23109 // remove - but keep children..
23110 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23111 while (node.childNodes.length) {
23112 var cn = node.childNodes[0];
23113 node.removeChild(cn);
23114 node.parentNode.insertBefore(cn, node);
23116 node.parentNode.removeChild(node);
23117 this.iterateChildren(node, this.cleanWord);
23121 if (node.className.length) {
23123 var cn = node.className.split(/\W+/);
23125 Roo.each(cn, function(cls) {
23126 if (cls.match(/Mso[a-zA-Z]+/)) {
23131 node.className = cna.length ? cna.join(' ') : '';
23133 node.removeAttribute("class");
23137 if (node.hasAttribute("lang")) {
23138 node.removeAttribute("lang");
23141 if (node.hasAttribute("style")) {
23143 var styles = node.getAttribute("style").split(";");
23145 Roo.each(styles, function(s) {
23146 if (!s.match(/:/)) {
23149 var kv = s.split(":");
23150 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23153 // what ever is left... we allow.
23156 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23157 if (!nstyle.length) {
23158 node.removeAttribute('style');
23161 this.iterateChildren(node, this.cleanWord);
23167 * iterateChildren of a Node, calling fn each time, using this as the scole..
23168 * @param {DomNode} node node to iterate children of.
23169 * @param {Function} fn method of this class to call on each item.
23171 iterateChildren : function(node, fn)
23173 if (!node.childNodes.length) {
23176 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23177 fn.call(this, node.childNodes[i])
23183 * cleanTableWidths.
23185 * Quite often pasting from word etc.. results in tables with column and widths.
23186 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23189 cleanTableWidths : function(node)
23194 this.cleanTableWidths(this.doc.body);
23199 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23202 Roo.log(node.tagName);
23203 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23204 this.iterateChildren(node, this.cleanTableWidths);
23207 if (node.hasAttribute('width')) {
23208 node.removeAttribute('width');
23212 if (node.hasAttribute("style")) {
23215 var styles = node.getAttribute("style").split(";");
23217 Roo.each(styles, function(s) {
23218 if (!s.match(/:/)) {
23221 var kv = s.split(":");
23222 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23225 // what ever is left... we allow.
23228 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23229 if (!nstyle.length) {
23230 node.removeAttribute('style');
23234 this.iterateChildren(node, this.cleanTableWidths);
23242 domToHTML : function(currentElement, depth, nopadtext) {
23244 depth = depth || 0;
23245 nopadtext = nopadtext || false;
23247 if (!currentElement) {
23248 return this.domToHTML(this.doc.body);
23251 //Roo.log(currentElement);
23253 var allText = false;
23254 var nodeName = currentElement.nodeName;
23255 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23257 if (nodeName == '#text') {
23259 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23264 if (nodeName != 'BODY') {
23267 // Prints the node tagName, such as <A>, <IMG>, etc
23270 for(i = 0; i < currentElement.attributes.length;i++) {
23272 var aname = currentElement.attributes.item(i).name;
23273 if (!currentElement.attributes.item(i).value.length) {
23276 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23279 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23288 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23291 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23296 // Traverse the tree
23298 var currentElementChild = currentElement.childNodes.item(i);
23299 var allText = true;
23300 var innerHTML = '';
23302 while (currentElementChild) {
23303 // Formatting code (indent the tree so it looks nice on the screen)
23304 var nopad = nopadtext;
23305 if (lastnode == 'SPAN') {
23309 if (currentElementChild.nodeName == '#text') {
23310 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23311 toadd = nopadtext ? toadd : toadd.trim();
23312 if (!nopad && toadd.length > 80) {
23313 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23315 innerHTML += toadd;
23318 currentElementChild = currentElement.childNodes.item(i);
23324 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23326 // Recursively traverse the tree structure of the child node
23327 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23328 lastnode = currentElementChild.nodeName;
23330 currentElementChild=currentElement.childNodes.item(i);
23336 // The remaining code is mostly for formatting the tree
23337 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23342 ret+= "</"+tagName+">";
23348 applyBlacklists : function()
23350 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23351 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23355 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23356 if (b.indexOf(tag) > -1) {
23359 this.white.push(tag);
23363 Roo.each(w, function(tag) {
23364 if (b.indexOf(tag) > -1) {
23367 if (this.white.indexOf(tag) > -1) {
23370 this.white.push(tag);
23375 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23376 if (w.indexOf(tag) > -1) {
23379 this.black.push(tag);
23383 Roo.each(b, function(tag) {
23384 if (w.indexOf(tag) > -1) {
23387 if (this.black.indexOf(tag) > -1) {
23390 this.black.push(tag);
23395 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23396 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23400 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23401 if (b.indexOf(tag) > -1) {
23404 this.cwhite.push(tag);
23408 Roo.each(w, function(tag) {
23409 if (b.indexOf(tag) > -1) {
23412 if (this.cwhite.indexOf(tag) > -1) {
23415 this.cwhite.push(tag);
23420 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23421 if (w.indexOf(tag) > -1) {
23424 this.cblack.push(tag);
23428 Roo.each(b, function(tag) {
23429 if (w.indexOf(tag) > -1) {
23432 if (this.cblack.indexOf(tag) > -1) {
23435 this.cblack.push(tag);
23440 setStylesheets : function(stylesheets)
23442 if(typeof(stylesheets) == 'string'){
23443 Roo.get(this.iframe.contentDocument.head).createChild({
23445 rel : 'stylesheet',
23454 Roo.each(stylesheets, function(s) {
23459 Roo.get(_this.iframe.contentDocument.head).createChild({
23461 rel : 'stylesheet',
23470 removeStylesheets : function()
23474 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23479 setStyle : function(style)
23481 Roo.get(this.iframe.contentDocument.head).createChild({
23490 // hide stuff that is not compatible
23504 * @event specialkey
23508 * @cfg {String} fieldClass @hide
23511 * @cfg {String} focusClass @hide
23514 * @cfg {String} autoCreate @hide
23517 * @cfg {String} inputType @hide
23520 * @cfg {String} invalidClass @hide
23523 * @cfg {String} invalidText @hide
23526 * @cfg {String} msgFx @hide
23529 * @cfg {String} validateOnBlur @hide
23533 Roo.HtmlEditorCore.white = [
23534 'area', 'br', 'img', 'input', 'hr', 'wbr',
23536 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23537 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23538 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23539 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23540 'table', 'ul', 'xmp',
23542 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23545 'dir', 'menu', 'ol', 'ul', 'dl',
23551 Roo.HtmlEditorCore.black = [
23552 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23554 'base', 'basefont', 'bgsound', 'blink', 'body',
23555 'frame', 'frameset', 'head', 'html', 'ilayer',
23556 'iframe', 'layer', 'link', 'meta', 'object',
23557 'script', 'style' ,'title', 'xml' // clean later..
23559 Roo.HtmlEditorCore.clean = [
23560 'script', 'style', 'title', 'xml'
23562 Roo.HtmlEditorCore.remove = [
23567 Roo.HtmlEditorCore.ablack = [
23571 Roo.HtmlEditorCore.aclean = [
23572 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23576 Roo.HtmlEditorCore.pwhite= [
23577 'http', 'https', 'mailto'
23580 // white listed style attributes.
23581 Roo.HtmlEditorCore.cwhite= [
23582 // 'text-align', /// default is to allow most things..
23588 // black listed style attributes.
23589 Roo.HtmlEditorCore.cblack= [
23590 // 'font-size' -- this can be set by the project
23594 Roo.HtmlEditorCore.swapCodes =[
23613 * @class Roo.bootstrap.HtmlEditor
23614 * @extends Roo.bootstrap.TextArea
23615 * Bootstrap HtmlEditor class
23618 * Create a new HtmlEditor
23619 * @param {Object} config The config object
23622 Roo.bootstrap.HtmlEditor = function(config){
23623 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23624 if (!this.toolbars) {
23625 this.toolbars = [];
23628 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23631 * @event initialize
23632 * Fires when the editor is fully initialized (including the iframe)
23633 * @param {HtmlEditor} this
23638 * Fires when the editor is first receives the focus. Any insertion must wait
23639 * until after this event.
23640 * @param {HtmlEditor} this
23644 * @event beforesync
23645 * Fires before the textarea is updated with content from the editor iframe. Return false
23646 * to cancel the sync.
23647 * @param {HtmlEditor} this
23648 * @param {String} html
23652 * @event beforepush
23653 * Fires before the iframe editor is updated with content from the textarea. Return false
23654 * to cancel the push.
23655 * @param {HtmlEditor} this
23656 * @param {String} html
23661 * Fires when the textarea is updated with content from the editor iframe.
23662 * @param {HtmlEditor} this
23663 * @param {String} html
23668 * Fires when the iframe editor is updated with content from the textarea.
23669 * @param {HtmlEditor} this
23670 * @param {String} html
23674 * @event editmodechange
23675 * Fires when the editor switches edit modes
23676 * @param {HtmlEditor} this
23677 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23679 editmodechange: true,
23681 * @event editorevent
23682 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23683 * @param {HtmlEditor} this
23687 * @event firstfocus
23688 * Fires when on first focus - needed by toolbars..
23689 * @param {HtmlEditor} this
23694 * Auto save the htmlEditor value as a file into Events
23695 * @param {HtmlEditor} this
23699 * @event savedpreview
23700 * preview the saved version of htmlEditor
23701 * @param {HtmlEditor} this
23708 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23712 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23717 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23722 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23727 * @cfg {Number} height (in pixels)
23731 * @cfg {Number} width (in pixels)
23736 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23739 stylesheets: false,
23744 // private properties
23745 validationEvent : false,
23747 initialized : false,
23750 onFocus : Roo.emptyFn,
23752 hideMode:'offsets',
23754 tbContainer : false,
23758 toolbarContainer :function() {
23759 return this.wrap.select('.x-html-editor-tb',true).first();
23763 * Protected method that will not generally be called directly. It
23764 * is called when the editor creates its toolbar. Override this method if you need to
23765 * add custom toolbar buttons.
23766 * @param {HtmlEditor} editor
23768 createToolbar : function(){
23769 Roo.log('renewing');
23770 Roo.log("create toolbars");
23772 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23773 this.toolbars[0].render(this.toolbarContainer());
23777 // if (!editor.toolbars || !editor.toolbars.length) {
23778 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23781 // for (var i =0 ; i < editor.toolbars.length;i++) {
23782 // editor.toolbars[i] = Roo.factory(
23783 // typeof(editor.toolbars[i]) == 'string' ?
23784 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23785 // Roo.bootstrap.HtmlEditor);
23786 // editor.toolbars[i].init(editor);
23792 onRender : function(ct, position)
23794 // Roo.log("Call onRender: " + this.xtype);
23796 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23798 this.wrap = this.inputEl().wrap({
23799 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23802 this.editorcore.onRender(ct, position);
23804 if (this.resizable) {
23805 this.resizeEl = new Roo.Resizable(this.wrap, {
23809 minHeight : this.height,
23810 height: this.height,
23811 handles : this.resizable,
23814 resize : function(r, w, h) {
23815 _t.onResize(w,h); // -something
23821 this.createToolbar(this);
23824 if(!this.width && this.resizable){
23825 this.setSize(this.wrap.getSize());
23827 if (this.resizeEl) {
23828 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23829 // should trigger onReize..
23835 onResize : function(w, h)
23837 Roo.log('resize: ' +w + ',' + h );
23838 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23842 if(this.inputEl() ){
23843 if(typeof w == 'number'){
23844 var aw = w - this.wrap.getFrameWidth('lr');
23845 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23848 if(typeof h == 'number'){
23849 var tbh = -11; // fixme it needs to tool bar size!
23850 for (var i =0; i < this.toolbars.length;i++) {
23851 // fixme - ask toolbars for heights?
23852 tbh += this.toolbars[i].el.getHeight();
23853 //if (this.toolbars[i].footer) {
23854 // tbh += this.toolbars[i].footer.el.getHeight();
23862 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23863 ah -= 5; // knock a few pixes off for look..
23864 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23868 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23869 this.editorcore.onResize(ew,eh);
23874 * Toggles the editor between standard and source edit mode.
23875 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23877 toggleSourceEdit : function(sourceEditMode)
23879 this.editorcore.toggleSourceEdit(sourceEditMode);
23881 if(this.editorcore.sourceEditMode){
23882 Roo.log('editor - showing textarea');
23885 // Roo.log(this.syncValue());
23887 this.inputEl().removeClass(['hide', 'x-hidden']);
23888 this.inputEl().dom.removeAttribute('tabIndex');
23889 this.inputEl().focus();
23891 Roo.log('editor - hiding textarea');
23893 // Roo.log(this.pushValue());
23896 this.inputEl().addClass(['hide', 'x-hidden']);
23897 this.inputEl().dom.setAttribute('tabIndex', -1);
23898 //this.deferFocus();
23901 if(this.resizable){
23902 this.setSize(this.wrap.getSize());
23905 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23908 // private (for BoxComponent)
23909 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23911 // private (for BoxComponent)
23912 getResizeEl : function(){
23916 // private (for BoxComponent)
23917 getPositionEl : function(){
23922 initEvents : function(){
23923 this.originalValue = this.getValue();
23927 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23930 // markInvalid : Roo.emptyFn,
23932 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23935 // clearInvalid : Roo.emptyFn,
23937 setValue : function(v){
23938 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23939 this.editorcore.pushValue();
23944 deferFocus : function(){
23945 this.focus.defer(10, this);
23949 focus : function(){
23950 this.editorcore.focus();
23956 onDestroy : function(){
23962 for (var i =0; i < this.toolbars.length;i++) {
23963 // fixme - ask toolbars for heights?
23964 this.toolbars[i].onDestroy();
23967 this.wrap.dom.innerHTML = '';
23968 this.wrap.remove();
23973 onFirstFocus : function(){
23974 //Roo.log("onFirstFocus");
23975 this.editorcore.onFirstFocus();
23976 for (var i =0; i < this.toolbars.length;i++) {
23977 this.toolbars[i].onFirstFocus();
23983 syncValue : function()
23985 this.editorcore.syncValue();
23988 pushValue : function()
23990 this.editorcore.pushValue();
23994 // hide stuff that is not compatible
24008 * @event specialkey
24012 * @cfg {String} fieldClass @hide
24015 * @cfg {String} focusClass @hide
24018 * @cfg {String} autoCreate @hide
24021 * @cfg {String} inputType @hide
24025 * @cfg {String} invalidText @hide
24028 * @cfg {String} msgFx @hide
24031 * @cfg {String} validateOnBlur @hide
24040 Roo.namespace('Roo.bootstrap.htmleditor');
24042 * @class Roo.bootstrap.HtmlEditorToolbar1
24047 new Roo.bootstrap.HtmlEditor({
24050 new Roo.bootstrap.HtmlEditorToolbar1({
24051 disable : { fonts: 1 , format: 1, ..., ... , ...],
24057 * @cfg {Object} disable List of elements to disable..
24058 * @cfg {Array} btns List of additional buttons.
24062 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24065 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24068 Roo.apply(this, config);
24070 // default disabled, based on 'good practice'..
24071 this.disable = this.disable || {};
24072 Roo.applyIf(this.disable, {
24075 specialElements : true
24077 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24079 this.editor = config.editor;
24080 this.editorcore = config.editor.editorcore;
24082 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24084 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24085 // dont call parent... till later.
24087 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24092 editorcore : false,
24097 "h1","h2","h3","h4","h5","h6",
24099 "abbr", "acronym", "address", "cite", "samp", "var",
24103 onRender : function(ct, position)
24105 // Roo.log("Call onRender: " + this.xtype);
24107 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24109 this.el.dom.style.marginBottom = '0';
24111 var editorcore = this.editorcore;
24112 var editor= this.editor;
24115 var btn = function(id,cmd , toggle, handler, html){
24117 var event = toggle ? 'toggle' : 'click';
24122 xns: Roo.bootstrap,
24126 enableToggle:toggle !== false,
24128 pressed : toggle ? false : null,
24131 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24132 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24138 // var cb_box = function...
24143 xns: Roo.bootstrap,
24148 xns: Roo.bootstrap,
24152 Roo.each(this.formats, function(f) {
24153 style.menu.items.push({
24155 xns: Roo.bootstrap,
24156 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24161 editorcore.insertTag(this.tagname);
24168 children.push(style);
24170 btn('bold',false,true);
24171 btn('italic',false,true);
24172 btn('align-left', 'justifyleft',true);
24173 btn('align-center', 'justifycenter',true);
24174 btn('align-right' , 'justifyright',true);
24175 btn('link', false, false, function(btn) {
24176 //Roo.log("create link?");
24177 var url = prompt(this.createLinkText, this.defaultLinkValue);
24178 if(url && url != 'http:/'+'/'){
24179 this.editorcore.relayCmd('createlink', url);
24182 btn('list','insertunorderedlist',true);
24183 btn('pencil', false,true, function(btn){
24185 this.toggleSourceEdit(btn.pressed);
24188 if (this.editor.btns.length > 0) {
24189 for (var i = 0; i<this.editor.btns.length; i++) {
24190 children.push(this.editor.btns[i]);
24198 xns: Roo.bootstrap,
24203 xns: Roo.bootstrap,
24208 cog.menu.items.push({
24210 xns: Roo.bootstrap,
24211 html : Clean styles,
24216 editorcore.insertTag(this.tagname);
24225 this.xtype = 'NavSimplebar';
24227 for(var i=0;i< children.length;i++) {
24229 this.buttons.add(this.addxtypeChild(children[i]));
24233 editor.on('editorevent', this.updateToolbar, this);
24235 onBtnClick : function(id)
24237 this.editorcore.relayCmd(id);
24238 this.editorcore.focus();
24242 * Protected method that will not generally be called directly. It triggers
24243 * a toolbar update by reading the markup state of the current selection in the editor.
24245 updateToolbar: function(){
24247 if(!this.editorcore.activated){
24248 this.editor.onFirstFocus(); // is this neeed?
24252 var btns = this.buttons;
24253 var doc = this.editorcore.doc;
24254 btns.get('bold').setActive(doc.queryCommandState('bold'));
24255 btns.get('italic').setActive(doc.queryCommandState('italic'));
24256 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24258 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24259 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24260 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24262 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24263 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24266 var ans = this.editorcore.getAllAncestors();
24267 if (this.formatCombo) {
24270 var store = this.formatCombo.store;
24271 this.formatCombo.setValue("");
24272 for (var i =0; i < ans.length;i++) {
24273 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24275 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24283 // hides menus... - so this cant be on a menu...
24284 Roo.bootstrap.MenuMgr.hideAll();
24286 Roo.bootstrap.MenuMgr.hideAll();
24287 //this.editorsyncValue();
24289 onFirstFocus: function() {
24290 this.buttons.each(function(item){
24294 toggleSourceEdit : function(sourceEditMode){
24297 if(sourceEditMode){
24298 Roo.log("disabling buttons");
24299 this.buttons.each( function(item){
24300 if(item.cmd != 'pencil'){
24306 Roo.log("enabling buttons");
24307 if(this.editorcore.initialized){
24308 this.buttons.each( function(item){
24314 Roo.log("calling toggole on editor");
24315 // tell the editor that it's been pressed..
24316 this.editor.toggleSourceEdit(sourceEditMode);
24326 * @class Roo.bootstrap.Table.AbstractSelectionModel
24327 * @extends Roo.util.Observable
24328 * Abstract base class for grid SelectionModels. It provides the interface that should be
24329 * implemented by descendant classes. This class should not be directly instantiated.
24332 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24333 this.locked = false;
24334 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24338 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24339 /** @ignore Called by the grid automatically. Do not call directly. */
24340 init : function(grid){
24346 * Locks the selections.
24349 this.locked = true;
24353 * Unlocks the selections.
24355 unlock : function(){
24356 this.locked = false;
24360 * Returns true if the selections are locked.
24361 * @return {Boolean}
24363 isLocked : function(){
24364 return this.locked;
24368 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24369 * @class Roo.bootstrap.Table.RowSelectionModel
24370 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24371 * It supports multiple selections and keyboard selection/navigation.
24373 * @param {Object} config
24376 Roo.bootstrap.Table.RowSelectionModel = function(config){
24377 Roo.apply(this, config);
24378 this.selections = new Roo.util.MixedCollection(false, function(o){
24383 this.lastActive = false;
24387 * @event selectionchange
24388 * Fires when the selection changes
24389 * @param {SelectionModel} this
24391 "selectionchange" : true,
24393 * @event afterselectionchange
24394 * Fires after the selection changes (eg. by key press or clicking)
24395 * @param {SelectionModel} this
24397 "afterselectionchange" : true,
24399 * @event beforerowselect
24400 * Fires when a row is selected being selected, return false to cancel.
24401 * @param {SelectionModel} this
24402 * @param {Number} rowIndex The selected index
24403 * @param {Boolean} keepExisting False if other selections will be cleared
24405 "beforerowselect" : true,
24408 * Fires when a row is selected.
24409 * @param {SelectionModel} this
24410 * @param {Number} rowIndex The selected index
24411 * @param {Roo.data.Record} r The record
24413 "rowselect" : true,
24415 * @event rowdeselect
24416 * Fires when a row is deselected.
24417 * @param {SelectionModel} this
24418 * @param {Number} rowIndex The selected index
24420 "rowdeselect" : true
24422 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24423 this.locked = false;
24426 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24428 * @cfg {Boolean} singleSelect
24429 * True to allow selection of only one row at a time (defaults to false)
24431 singleSelect : false,
24434 initEvents : function()
24437 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24438 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24439 //}else{ // allow click to work like normal
24440 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24442 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24443 this.grid.on("rowclick", this.handleMouseDown, this);
24445 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24446 "up" : function(e){
24448 this.selectPrevious(e.shiftKey);
24449 }else if(this.last !== false && this.lastActive !== false){
24450 var last = this.last;
24451 this.selectRange(this.last, this.lastActive-1);
24452 this.grid.getView().focusRow(this.lastActive);
24453 if(last !== false){
24457 this.selectFirstRow();
24459 this.fireEvent("afterselectionchange", this);
24461 "down" : function(e){
24463 this.selectNext(e.shiftKey);
24464 }else if(this.last !== false && this.lastActive !== false){
24465 var last = this.last;
24466 this.selectRange(this.last, this.lastActive+1);
24467 this.grid.getView().focusRow(this.lastActive);
24468 if(last !== false){
24472 this.selectFirstRow();
24474 this.fireEvent("afterselectionchange", this);
24478 this.grid.store.on('load', function(){
24479 this.selections.clear();
24482 var view = this.grid.view;
24483 view.on("refresh", this.onRefresh, this);
24484 view.on("rowupdated", this.onRowUpdated, this);
24485 view.on("rowremoved", this.onRemove, this);
24490 onRefresh : function()
24492 var ds = this.grid.store, i, v = this.grid.view;
24493 var s = this.selections;
24494 s.each(function(r){
24495 if((i = ds.indexOfId(r.id)) != -1){
24504 onRemove : function(v, index, r){
24505 this.selections.remove(r);
24509 onRowUpdated : function(v, index, r){
24510 if(this.isSelected(r)){
24511 v.onRowSelect(index);
24517 * @param {Array} records The records to select
24518 * @param {Boolean} keepExisting (optional) True to keep existing selections
24520 selectRecords : function(records, keepExisting)
24523 this.clearSelections();
24525 var ds = this.grid.store;
24526 for(var i = 0, len = records.length; i < len; i++){
24527 this.selectRow(ds.indexOf(records[i]), true);
24532 * Gets the number of selected rows.
24535 getCount : function(){
24536 return this.selections.length;
24540 * Selects the first row in the grid.
24542 selectFirstRow : function(){
24547 * Select the last row.
24548 * @param {Boolean} keepExisting (optional) True to keep existing selections
24550 selectLastRow : function(keepExisting){
24551 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24552 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24556 * Selects the row immediately following the last selected row.
24557 * @param {Boolean} keepExisting (optional) True to keep existing selections
24559 selectNext : function(keepExisting)
24561 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24562 this.selectRow(this.last+1, keepExisting);
24563 this.grid.getView().focusRow(this.last);
24568 * Selects the row that precedes the last selected row.
24569 * @param {Boolean} keepExisting (optional) True to keep existing selections
24571 selectPrevious : function(keepExisting){
24573 this.selectRow(this.last-1, keepExisting);
24574 this.grid.getView().focusRow(this.last);
24579 * Returns the selected records
24580 * @return {Array} Array of selected records
24582 getSelections : function(){
24583 return [].concat(this.selections.items);
24587 * Returns the first selected record.
24590 getSelected : function(){
24591 return this.selections.itemAt(0);
24596 * Clears all selections.
24598 clearSelections : function(fast)
24604 var ds = this.grid.store;
24605 var s = this.selections;
24606 s.each(function(r){
24607 this.deselectRow(ds.indexOfId(r.id));
24611 this.selections.clear();
24618 * Selects all rows.
24620 selectAll : function(){
24624 this.selections.clear();
24625 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24626 this.selectRow(i, true);
24631 * Returns True if there is a selection.
24632 * @return {Boolean}
24634 hasSelection : function(){
24635 return this.selections.length > 0;
24639 * Returns True if the specified row is selected.
24640 * @param {Number/Record} record The record or index of the record to check
24641 * @return {Boolean}
24643 isSelected : function(index){
24644 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24645 return (r && this.selections.key(r.id) ? true : false);
24649 * Returns True if the specified record id is selected.
24650 * @param {String} id The id of record to check
24651 * @return {Boolean}
24653 isIdSelected : function(id){
24654 return (this.selections.key(id) ? true : false);
24659 handleMouseDBClick : function(e, t){
24663 handleMouseDown : function(e, t)
24665 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24666 if(this.isLocked() || rowIndex < 0 ){
24669 if(e.shiftKey && this.last !== false){
24670 var last = this.last;
24671 this.selectRange(last, rowIndex, e.ctrlKey);
24672 this.last = last; // reset the last
24676 var isSelected = this.isSelected(rowIndex);
24677 //Roo.log("select row:" + rowIndex);
24679 this.deselectRow(rowIndex);
24681 this.selectRow(rowIndex, true);
24685 if(e.button !== 0 && isSelected){
24686 alert('rowIndex 2: ' + rowIndex);
24687 view.focusRow(rowIndex);
24688 }else if(e.ctrlKey && isSelected){
24689 this.deselectRow(rowIndex);
24690 }else if(!isSelected){
24691 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24692 view.focusRow(rowIndex);
24696 this.fireEvent("afterselectionchange", this);
24699 handleDragableRowClick : function(grid, rowIndex, e)
24701 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24702 this.selectRow(rowIndex, false);
24703 grid.view.focusRow(rowIndex);
24704 this.fireEvent("afterselectionchange", this);
24709 * Selects multiple rows.
24710 * @param {Array} rows Array of the indexes of the row to select
24711 * @param {Boolean} keepExisting (optional) True to keep existing selections
24713 selectRows : function(rows, keepExisting){
24715 this.clearSelections();
24717 for(var i = 0, len = rows.length; i < len; i++){
24718 this.selectRow(rows[i], true);
24723 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24724 * @param {Number} startRow The index of the first row in the range
24725 * @param {Number} endRow The index of the last row in the range
24726 * @param {Boolean} keepExisting (optional) True to retain existing selections
24728 selectRange : function(startRow, endRow, keepExisting){
24733 this.clearSelections();
24735 if(startRow <= endRow){
24736 for(var i = startRow; i <= endRow; i++){
24737 this.selectRow(i, true);
24740 for(var i = startRow; i >= endRow; i--){
24741 this.selectRow(i, true);
24747 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24748 * @param {Number} startRow The index of the first row in the range
24749 * @param {Number} endRow The index of the last row in the range
24751 deselectRange : function(startRow, endRow, preventViewNotify){
24755 for(var i = startRow; i <= endRow; i++){
24756 this.deselectRow(i, preventViewNotify);
24762 * @param {Number} row The index of the row to select
24763 * @param {Boolean} keepExisting (optional) True to keep existing selections
24765 selectRow : function(index, keepExisting, preventViewNotify)
24767 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24770 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24771 if(!keepExisting || this.singleSelect){
24772 this.clearSelections();
24775 var r = this.grid.store.getAt(index);
24776 //console.log('selectRow - record id :' + r.id);
24778 this.selections.add(r);
24779 this.last = this.lastActive = index;
24780 if(!preventViewNotify){
24781 var proxy = new Roo.Element(
24782 this.grid.getRowDom(index)
24784 proxy.addClass('bg-info info');
24786 this.fireEvent("rowselect", this, index, r);
24787 this.fireEvent("selectionchange", this);
24793 * @param {Number} row The index of the row to deselect
24795 deselectRow : function(index, preventViewNotify)
24800 if(this.last == index){
24803 if(this.lastActive == index){
24804 this.lastActive = false;
24807 var r = this.grid.store.getAt(index);
24812 this.selections.remove(r);
24813 //.console.log('deselectRow - record id :' + r.id);
24814 if(!preventViewNotify){
24816 var proxy = new Roo.Element(
24817 this.grid.getRowDom(index)
24819 proxy.removeClass('bg-info info');
24821 this.fireEvent("rowdeselect", this, index);
24822 this.fireEvent("selectionchange", this);
24826 restoreLast : function(){
24828 this.last = this._last;
24833 acceptsNav : function(row, col, cm){
24834 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24838 onEditorKey : function(field, e){
24839 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24844 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24846 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24848 }else if(k == e.ENTER && !e.ctrlKey){
24852 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24854 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24856 }else if(k == e.ESC){
24860 g.startEditing(newCell[0], newCell[1]);
24866 * Ext JS Library 1.1.1
24867 * Copyright(c) 2006-2007, Ext JS, LLC.
24869 * Originally Released Under LGPL - original licence link has changed is not relivant.
24872 * <script type="text/javascript">
24876 * @class Roo.bootstrap.PagingToolbar
24877 * @extends Roo.bootstrap.NavSimplebar
24878 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24880 * Create a new PagingToolbar
24881 * @param {Object} config The config object
24882 * @param {Roo.data.Store} store
24884 Roo.bootstrap.PagingToolbar = function(config)
24886 // old args format still supported... - xtype is prefered..
24887 // created from xtype...
24889 this.ds = config.dataSource;
24891 if (config.store && !this.ds) {
24892 this.store= Roo.factory(config.store, Roo.data);
24893 this.ds = this.store;
24894 this.ds.xmodule = this.xmodule || false;
24897 this.toolbarItems = [];
24898 if (config.items) {
24899 this.toolbarItems = config.items;
24902 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24907 this.bind(this.ds);
24910 if (Roo.bootstrap.version == 4) {
24911 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24913 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24918 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24920 * @cfg {Roo.data.Store} dataSource
24921 * The underlying data store providing the paged data
24924 * @cfg {String/HTMLElement/Element} container
24925 * container The id or element that will contain the toolbar
24928 * @cfg {Boolean} displayInfo
24929 * True to display the displayMsg (defaults to false)
24932 * @cfg {Number} pageSize
24933 * The number of records to display per page (defaults to 20)
24937 * @cfg {String} displayMsg
24938 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24940 displayMsg : 'Displaying {0} - {1} of {2}',
24942 * @cfg {String} emptyMsg
24943 * The message to display when no records are found (defaults to "No data to display")
24945 emptyMsg : 'No data to display',
24947 * Customizable piece of the default paging text (defaults to "Page")
24950 beforePageText : "Page",
24952 * Customizable piece of the default paging text (defaults to "of %0")
24955 afterPageText : "of {0}",
24957 * Customizable piece of the default paging text (defaults to "First Page")
24960 firstText : "First Page",
24962 * Customizable piece of the default paging text (defaults to "Previous Page")
24965 prevText : "Previous Page",
24967 * Customizable piece of the default paging text (defaults to "Next Page")
24970 nextText : "Next Page",
24972 * Customizable piece of the default paging text (defaults to "Last Page")
24975 lastText : "Last Page",
24977 * Customizable piece of the default paging text (defaults to "Refresh")
24980 refreshText : "Refresh",
24984 onRender : function(ct, position)
24986 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24987 this.navgroup.parentId = this.id;
24988 this.navgroup.onRender(this.el, null);
24989 // add the buttons to the navgroup
24991 if(this.displayInfo){
24992 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24993 this.displayEl = this.el.select('.x-paging-info', true).first();
24994 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24995 // this.displayEl = navel.el.select('span',true).first();
25001 Roo.each(_this.buttons, function(e){ // this might need to use render????
25002 Roo.factory(e).render(_this.el);
25006 Roo.each(_this.toolbarItems, function(e) {
25007 _this.navgroup.addItem(e);
25011 this.first = this.navgroup.addItem({
25012 tooltip: this.firstText,
25013 cls: "prev btn-outline-secondary",
25014 html : ' <i class="fa fa-step-backward"></i>',
25016 preventDefault: true,
25017 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25020 this.prev = this.navgroup.addItem({
25021 tooltip: this.prevText,
25022 cls: "prev btn-outline-secondary",
25023 html : ' <i class="fa fa-backward"></i>',
25025 preventDefault: true,
25026 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25028 //this.addSeparator();
25031 var field = this.navgroup.addItem( {
25033 cls : 'x-paging-position btn-outline-secondary',
25035 html : this.beforePageText +
25036 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25037 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25040 this.field = field.el.select('input', true).first();
25041 this.field.on("keydown", this.onPagingKeydown, this);
25042 this.field.on("focus", function(){this.dom.select();});
25045 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25046 //this.field.setHeight(18);
25047 //this.addSeparator();
25048 this.next = this.navgroup.addItem({
25049 tooltip: this.nextText,
25050 cls: "next btn-outline-secondary",
25051 html : ' <i class="fa fa-forward"></i>',
25053 preventDefault: true,
25054 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25056 this.last = this.navgroup.addItem({
25057 tooltip: this.lastText,
25058 html : ' <i class="fa fa-step-forward"></i>',
25059 cls: "next btn-outline-secondary",
25061 preventDefault: true,
25062 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25064 //this.addSeparator();
25065 this.loading = this.navgroup.addItem({
25066 tooltip: this.refreshText,
25067 cls: "btn-outline-secondary",
25068 html : ' <i class="fa fa-refresh"></i>',
25069 preventDefault: true,
25070 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25076 updateInfo : function(){
25077 if(this.displayEl){
25078 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25079 var msg = count == 0 ?
25083 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25085 this.displayEl.update(msg);
25090 onLoad : function(ds, r, o)
25092 this.cursor = o.params.start ? o.params.start : 0;
25094 var d = this.getPageData(),
25099 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25100 this.field.dom.value = ap;
25101 this.first.setDisabled(ap == 1);
25102 this.prev.setDisabled(ap == 1);
25103 this.next.setDisabled(ap == ps);
25104 this.last.setDisabled(ap == ps);
25105 this.loading.enable();
25110 getPageData : function(){
25111 var total = this.ds.getTotalCount();
25114 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25115 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25120 onLoadError : function(){
25121 this.loading.enable();
25125 onPagingKeydown : function(e){
25126 var k = e.getKey();
25127 var d = this.getPageData();
25129 var v = this.field.dom.value, pageNum;
25130 if(!v || isNaN(pageNum = parseInt(v, 10))){
25131 this.field.dom.value = d.activePage;
25134 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25135 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25138 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))
25140 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25141 this.field.dom.value = pageNum;
25142 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25145 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25147 var v = this.field.dom.value, pageNum;
25148 var increment = (e.shiftKey) ? 10 : 1;
25149 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25152 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25153 this.field.dom.value = d.activePage;
25156 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25158 this.field.dom.value = parseInt(v, 10) + increment;
25159 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25160 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25167 beforeLoad : function(){
25169 this.loading.disable();
25174 onClick : function(which){
25183 ds.load({params:{start: 0, limit: this.pageSize}});
25186 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25189 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25192 var total = ds.getTotalCount();
25193 var extra = total % this.pageSize;
25194 var lastStart = extra ? (total - extra) : total-this.pageSize;
25195 ds.load({params:{start: lastStart, limit: this.pageSize}});
25198 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25204 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25205 * @param {Roo.data.Store} store The data store to unbind
25207 unbind : function(ds){
25208 ds.un("beforeload", this.beforeLoad, this);
25209 ds.un("load", this.onLoad, this);
25210 ds.un("loadexception", this.onLoadError, this);
25211 ds.un("remove", this.updateInfo, this);
25212 ds.un("add", this.updateInfo, this);
25213 this.ds = undefined;
25217 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25218 * @param {Roo.data.Store} store The data store to bind
25220 bind : function(ds){
25221 ds.on("beforeload", this.beforeLoad, this);
25222 ds.on("load", this.onLoad, this);
25223 ds.on("loadexception", this.onLoadError, this);
25224 ds.on("remove", this.updateInfo, this);
25225 ds.on("add", this.updateInfo, this);
25236 * @class Roo.bootstrap.MessageBar
25237 * @extends Roo.bootstrap.Component
25238 * Bootstrap MessageBar class
25239 * @cfg {String} html contents of the MessageBar
25240 * @cfg {String} weight (info | success | warning | danger) default info
25241 * @cfg {String} beforeClass insert the bar before the given class
25242 * @cfg {Boolean} closable (true | false) default false
25243 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25246 * Create a new Element
25247 * @param {Object} config The config object
25250 Roo.bootstrap.MessageBar = function(config){
25251 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25254 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25260 beforeClass: 'bootstrap-sticky-wrap',
25262 getAutoCreate : function(){
25266 cls: 'alert alert-dismissable alert-' + this.weight,
25271 html: this.html || ''
25277 cfg.cls += ' alert-messages-fixed';
25291 onRender : function(ct, position)
25293 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25296 var cfg = Roo.apply({}, this.getAutoCreate());
25300 cfg.cls += ' ' + this.cls;
25303 cfg.style = this.style;
25305 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25307 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25310 this.el.select('>button.close').on('click', this.hide, this);
25316 if (!this.rendered) {
25322 this.fireEvent('show', this);
25328 if (!this.rendered) {
25334 this.fireEvent('hide', this);
25337 update : function()
25339 // var e = this.el.dom.firstChild;
25341 // if(this.closable){
25342 // e = e.nextSibling;
25345 // e.data = this.html || '';
25347 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25363 * @class Roo.bootstrap.Graph
25364 * @extends Roo.bootstrap.Component
25365 * Bootstrap Graph class
25369 @cfg {String} graphtype bar | vbar | pie
25370 @cfg {number} g_x coodinator | centre x (pie)
25371 @cfg {number} g_y coodinator | centre y (pie)
25372 @cfg {number} g_r radius (pie)
25373 @cfg {number} g_height height of the chart (respected by all elements in the set)
25374 @cfg {number} g_width width of the chart (respected by all elements in the set)
25375 @cfg {Object} title The title of the chart
25378 -opts (object) options for the chart
25380 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25381 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25383 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.
25384 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25386 o stretch (boolean)
25388 -opts (object) options for the pie
25391 o startAngle (number)
25392 o endAngle (number)
25396 * Create a new Input
25397 * @param {Object} config The config object
25400 Roo.bootstrap.Graph = function(config){
25401 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25407 * The img click event for the img.
25408 * @param {Roo.EventObject} e
25414 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25425 //g_colors: this.colors,
25432 getAutoCreate : function(){
25443 onRender : function(ct,position){
25446 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25448 if (typeof(Raphael) == 'undefined') {
25449 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25453 this.raphael = Raphael(this.el.dom);
25455 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25456 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25457 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25458 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25460 r.text(160, 10, "Single Series Chart").attr(txtattr);
25461 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25462 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25463 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25465 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25466 r.barchart(330, 10, 300, 220, data1);
25467 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25468 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25471 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25472 // r.barchart(30, 30, 560, 250, xdata, {
25473 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25474 // axis : "0 0 1 1",
25475 // axisxlabels : xdata
25476 // //yvalues : cols,
25479 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25481 // this.load(null,xdata,{
25482 // axis : "0 0 1 1",
25483 // axisxlabels : xdata
25488 load : function(graphtype,xdata,opts)
25490 this.raphael.clear();
25492 graphtype = this.graphtype;
25497 var r = this.raphael,
25498 fin = function () {
25499 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25501 fout = function () {
25502 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25504 pfin = function() {
25505 this.sector.stop();
25506 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25509 this.label[0].stop();
25510 this.label[0].attr({ r: 7.5 });
25511 this.label[1].attr({ "font-weight": 800 });
25514 pfout = function() {
25515 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25518 this.label[0].animate({ r: 5 }, 500, "bounce");
25519 this.label[1].attr({ "font-weight": 400 });
25525 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25528 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25531 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25532 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25534 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25541 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25546 setTitle: function(o)
25551 initEvents: function() {
25554 this.el.on('click', this.onClick, this);
25558 onClick : function(e)
25560 Roo.log('img onclick');
25561 this.fireEvent('click', this, e);
25573 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25576 * @class Roo.bootstrap.dash.NumberBox
25577 * @extends Roo.bootstrap.Component
25578 * Bootstrap NumberBox class
25579 * @cfg {String} headline Box headline
25580 * @cfg {String} content Box content
25581 * @cfg {String} icon Box icon
25582 * @cfg {String} footer Footer text
25583 * @cfg {String} fhref Footer href
25586 * Create a new NumberBox
25587 * @param {Object} config The config object
25591 Roo.bootstrap.dash.NumberBox = function(config){
25592 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25596 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25605 getAutoCreate : function(){
25609 cls : 'small-box ',
25617 cls : 'roo-headline',
25618 html : this.headline
25622 cls : 'roo-content',
25623 html : this.content
25637 cls : 'ion ' + this.icon
25646 cls : 'small-box-footer',
25647 href : this.fhref || '#',
25651 cfg.cn.push(footer);
25658 onRender : function(ct,position){
25659 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25666 setHeadline: function (value)
25668 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25671 setFooter: function (value, href)
25673 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25676 this.el.select('a.small-box-footer',true).first().attr('href', href);
25681 setContent: function (value)
25683 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25686 initEvents: function()
25700 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25703 * @class Roo.bootstrap.dash.TabBox
25704 * @extends Roo.bootstrap.Component
25705 * Bootstrap TabBox class
25706 * @cfg {String} title Title of the TabBox
25707 * @cfg {String} icon Icon of the TabBox
25708 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25709 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25712 * Create a new TabBox
25713 * @param {Object} config The config object
25717 Roo.bootstrap.dash.TabBox = function(config){
25718 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25723 * When a pane is added
25724 * @param {Roo.bootstrap.dash.TabPane} pane
25728 * @event activatepane
25729 * When a pane is activated
25730 * @param {Roo.bootstrap.dash.TabPane} pane
25732 "activatepane" : true
25740 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25745 tabScrollable : false,
25747 getChildContainer : function()
25749 return this.el.select('.tab-content', true).first();
25752 getAutoCreate : function(){
25756 cls: 'pull-left header',
25764 cls: 'fa ' + this.icon
25770 cls: 'nav nav-tabs pull-right',
25776 if(this.tabScrollable){
25783 cls: 'nav nav-tabs pull-right',
25794 cls: 'nav-tabs-custom',
25799 cls: 'tab-content no-padding',
25807 initEvents : function()
25809 //Roo.log('add add pane handler');
25810 this.on('addpane', this.onAddPane, this);
25813 * Updates the box title
25814 * @param {String} html to set the title to.
25816 setTitle : function(value)
25818 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25820 onAddPane : function(pane)
25822 this.panes.push(pane);
25823 //Roo.log('addpane');
25825 // tabs are rendere left to right..
25826 if(!this.showtabs){
25830 var ctr = this.el.select('.nav-tabs', true).first();
25833 var existing = ctr.select('.nav-tab',true);
25834 var qty = existing.getCount();;
25837 var tab = ctr.createChild({
25839 cls : 'nav-tab' + (qty ? '' : ' active'),
25847 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25850 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25852 pane.el.addClass('active');
25857 onTabClick : function(ev,un,ob,pane)
25859 //Roo.log('tab - prev default');
25860 ev.preventDefault();
25863 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25864 pane.tab.addClass('active');
25865 //Roo.log(pane.title);
25866 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25867 // technically we should have a deactivate event.. but maybe add later.
25868 // and it should not de-activate the selected tab...
25869 this.fireEvent('activatepane', pane);
25870 pane.el.addClass('active');
25871 pane.fireEvent('activate');
25876 getActivePane : function()
25879 Roo.each(this.panes, function(p) {
25880 if(p.el.hasClass('active')){
25901 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25903 * @class Roo.bootstrap.TabPane
25904 * @extends Roo.bootstrap.Component
25905 * Bootstrap TabPane class
25906 * @cfg {Boolean} active (false | true) Default false
25907 * @cfg {String} title title of panel
25911 * Create a new TabPane
25912 * @param {Object} config The config object
25915 Roo.bootstrap.dash.TabPane = function(config){
25916 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25922 * When a pane is activated
25923 * @param {Roo.bootstrap.dash.TabPane} pane
25930 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25935 // the tabBox that this is attached to.
25938 getAutoCreate : function()
25946 cfg.cls += ' active';
25951 initEvents : function()
25953 //Roo.log('trigger add pane handler');
25954 this.parent().fireEvent('addpane', this)
25958 * Updates the tab title
25959 * @param {String} html to set the title to.
25961 setTitle: function(str)
25967 this.tab.select('a', true).first().dom.innerHTML = str;
25984 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25987 * @class Roo.bootstrap.menu.Menu
25988 * @extends Roo.bootstrap.Component
25989 * Bootstrap Menu class - container for Menu
25990 * @cfg {String} html Text of the menu
25991 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25992 * @cfg {String} icon Font awesome icon
25993 * @cfg {String} pos Menu align to (top | bottom) default bottom
25997 * Create a new Menu
25998 * @param {Object} config The config object
26002 Roo.bootstrap.menu.Menu = function(config){
26003 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26007 * @event beforeshow
26008 * Fires before this menu is displayed
26009 * @param {Roo.bootstrap.menu.Menu} this
26013 * @event beforehide
26014 * Fires before this menu is hidden
26015 * @param {Roo.bootstrap.menu.Menu} this
26020 * Fires after this menu is displayed
26021 * @param {Roo.bootstrap.menu.Menu} this
26026 * Fires after this menu is hidden
26027 * @param {Roo.bootstrap.menu.Menu} this
26032 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26033 * @param {Roo.bootstrap.menu.Menu} this
26034 * @param {Roo.EventObject} e
26041 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26045 weight : 'default',
26050 getChildContainer : function() {
26051 if(this.isSubMenu){
26055 return this.el.select('ul.dropdown-menu', true).first();
26058 getAutoCreate : function()
26063 cls : 'roo-menu-text',
26071 cls : 'fa ' + this.icon
26082 cls : 'dropdown-button btn btn-' + this.weight,
26087 cls : 'dropdown-toggle btn btn-' + this.weight,
26097 cls : 'dropdown-menu'
26103 if(this.pos == 'top'){
26104 cfg.cls += ' dropup';
26107 if(this.isSubMenu){
26110 cls : 'dropdown-menu'
26117 onRender : function(ct, position)
26119 this.isSubMenu = ct.hasClass('dropdown-submenu');
26121 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26124 initEvents : function()
26126 if(this.isSubMenu){
26130 this.hidden = true;
26132 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26133 this.triggerEl.on('click', this.onTriggerPress, this);
26135 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26136 this.buttonEl.on('click', this.onClick, this);
26142 if(this.isSubMenu){
26146 return this.el.select('ul.dropdown-menu', true).first();
26149 onClick : function(e)
26151 this.fireEvent("click", this, e);
26154 onTriggerPress : function(e)
26156 if (this.isVisible()) {
26163 isVisible : function(){
26164 return !this.hidden;
26169 this.fireEvent("beforeshow", this);
26171 this.hidden = false;
26172 this.el.addClass('open');
26174 Roo.get(document).on("mouseup", this.onMouseUp, this);
26176 this.fireEvent("show", this);
26183 this.fireEvent("beforehide", this);
26185 this.hidden = true;
26186 this.el.removeClass('open');
26188 Roo.get(document).un("mouseup", this.onMouseUp);
26190 this.fireEvent("hide", this);
26193 onMouseUp : function()
26207 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26210 * @class Roo.bootstrap.menu.Item
26211 * @extends Roo.bootstrap.Component
26212 * Bootstrap MenuItem class
26213 * @cfg {Boolean} submenu (true | false) default false
26214 * @cfg {String} html text of the item
26215 * @cfg {String} href the link
26216 * @cfg {Boolean} disable (true | false) default false
26217 * @cfg {Boolean} preventDefault (true | false) default true
26218 * @cfg {String} icon Font awesome icon
26219 * @cfg {String} pos Submenu align to (left | right) default right
26223 * Create a new Item
26224 * @param {Object} config The config object
26228 Roo.bootstrap.menu.Item = function(config){
26229 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26233 * Fires when the mouse is hovering over this menu
26234 * @param {Roo.bootstrap.menu.Item} this
26235 * @param {Roo.EventObject} e
26240 * Fires when the mouse exits this menu
26241 * @param {Roo.bootstrap.menu.Item} this
26242 * @param {Roo.EventObject} e
26248 * The raw click event for the entire grid.
26249 * @param {Roo.EventObject} e
26255 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26260 preventDefault: true,
26265 getAutoCreate : function()
26270 cls : 'roo-menu-item-text',
26278 cls : 'fa ' + this.icon
26287 href : this.href || '#',
26294 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26298 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26300 if(this.pos == 'left'){
26301 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26308 initEvents : function()
26310 this.el.on('mouseover', this.onMouseOver, this);
26311 this.el.on('mouseout', this.onMouseOut, this);
26313 this.el.select('a', true).first().on('click', this.onClick, this);
26317 onClick : function(e)
26319 if(this.preventDefault){
26320 e.preventDefault();
26323 this.fireEvent("click", this, e);
26326 onMouseOver : function(e)
26328 if(this.submenu && this.pos == 'left'){
26329 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26332 this.fireEvent("mouseover", this, e);
26335 onMouseOut : function(e)
26337 this.fireEvent("mouseout", this, e);
26349 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26352 * @class Roo.bootstrap.menu.Separator
26353 * @extends Roo.bootstrap.Component
26354 * Bootstrap Separator class
26357 * Create a new Separator
26358 * @param {Object} config The config object
26362 Roo.bootstrap.menu.Separator = function(config){
26363 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26366 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26368 getAutoCreate : function(){
26389 * @class Roo.bootstrap.Tooltip
26390 * Bootstrap Tooltip class
26391 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26392 * to determine which dom element triggers the tooltip.
26394 * It needs to add support for additional attributes like tooltip-position
26397 * Create a new Toolti
26398 * @param {Object} config The config object
26401 Roo.bootstrap.Tooltip = function(config){
26402 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26404 this.alignment = Roo.bootstrap.Tooltip.alignment;
26406 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26407 this.alignment = config.alignment;
26412 Roo.apply(Roo.bootstrap.Tooltip, {
26414 * @function init initialize tooltip monitoring.
26418 currentTip : false,
26419 currentRegion : false,
26425 Roo.get(document).on('mouseover', this.enter ,this);
26426 Roo.get(document).on('mouseout', this.leave, this);
26429 this.currentTip = new Roo.bootstrap.Tooltip();
26432 enter : function(ev)
26434 var dom = ev.getTarget();
26436 //Roo.log(['enter',dom]);
26437 var el = Roo.fly(dom);
26438 if (this.currentEl) {
26440 //Roo.log(this.currentEl);
26441 //Roo.log(this.currentEl.contains(dom));
26442 if (this.currentEl == el) {
26445 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26451 if (this.currentTip.el) {
26452 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26456 if(!el || el.dom == document){
26462 // you can not look for children, as if el is the body.. then everythign is the child..
26463 if (!el.attr('tooltip')) { //
26464 if (!el.select("[tooltip]").elements.length) {
26467 // is the mouse over this child...?
26468 bindEl = el.select("[tooltip]").first();
26469 var xy = ev.getXY();
26470 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26471 //Roo.log("not in region.");
26474 //Roo.log("child element over..");
26477 this.currentEl = bindEl;
26478 this.currentTip.bind(bindEl);
26479 this.currentRegion = Roo.lib.Region.getRegion(dom);
26480 this.currentTip.enter();
26483 leave : function(ev)
26485 var dom = ev.getTarget();
26486 //Roo.log(['leave',dom]);
26487 if (!this.currentEl) {
26492 if (dom != this.currentEl.dom) {
26495 var xy = ev.getXY();
26496 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26499 // only activate leave if mouse cursor is outside... bounding box..
26504 if (this.currentTip) {
26505 this.currentTip.leave();
26507 //Roo.log('clear currentEl');
26508 this.currentEl = false;
26513 'left' : ['r-l', [-2,0], 'right'],
26514 'right' : ['l-r', [2,0], 'left'],
26515 'bottom' : ['t-b', [0,2], 'top'],
26516 'top' : [ 'b-t', [0,-2], 'bottom']
26522 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26527 delay : null, // can be { show : 300 , hide: 500}
26531 hoverState : null, //???
26533 placement : 'bottom',
26537 getAutoCreate : function(){
26544 cls : 'tooltip-arrow'
26547 cls : 'tooltip-inner'
26554 bind : function(el)
26560 enter : function () {
26562 if (this.timeout != null) {
26563 clearTimeout(this.timeout);
26566 this.hoverState = 'in';
26567 //Roo.log("enter - show");
26568 if (!this.delay || !this.delay.show) {
26573 this.timeout = setTimeout(function () {
26574 if (_t.hoverState == 'in') {
26577 }, this.delay.show);
26581 clearTimeout(this.timeout);
26583 this.hoverState = 'out';
26584 if (!this.delay || !this.delay.hide) {
26590 this.timeout = setTimeout(function () {
26591 //Roo.log("leave - timeout");
26593 if (_t.hoverState == 'out') {
26595 Roo.bootstrap.Tooltip.currentEl = false;
26600 show : function (msg)
26603 this.render(document.body);
26606 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26608 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26610 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26612 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26614 var placement = typeof this.placement == 'function' ?
26615 this.placement.call(this, this.el, on_el) :
26618 var autoToken = /\s?auto?\s?/i;
26619 var autoPlace = autoToken.test(placement);
26621 placement = placement.replace(autoToken, '') || 'top';
26625 //this.el.setXY([0,0]);
26627 //this.el.dom.style.display='block';
26629 //this.el.appendTo(on_el);
26631 var p = this.getPosition();
26632 var box = this.el.getBox();
26638 var align = this.alignment[placement];
26640 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26642 if(placement == 'top' || placement == 'bottom'){
26644 placement = 'right';
26647 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26648 placement = 'left';
26651 var scroll = Roo.select('body', true).first().getScroll();
26653 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26657 align = this.alignment[placement];
26660 this.el.alignTo(this.bindEl, align[0],align[1]);
26661 //var arrow = this.el.select('.arrow',true).first();
26662 //arrow.set(align[2],
26664 this.el.addClass(placement);
26666 this.el.addClass('in fade');
26668 this.hoverState = null;
26670 if (this.el.hasClass('fade')) {
26681 //this.el.setXY([0,0]);
26682 this.el.removeClass('in');
26698 * @class Roo.bootstrap.LocationPicker
26699 * @extends Roo.bootstrap.Component
26700 * Bootstrap LocationPicker class
26701 * @cfg {Number} latitude Position when init default 0
26702 * @cfg {Number} longitude Position when init default 0
26703 * @cfg {Number} zoom default 15
26704 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26705 * @cfg {Boolean} mapTypeControl default false
26706 * @cfg {Boolean} disableDoubleClickZoom default false
26707 * @cfg {Boolean} scrollwheel default true
26708 * @cfg {Boolean} streetViewControl default false
26709 * @cfg {Number} radius default 0
26710 * @cfg {String} locationName
26711 * @cfg {Boolean} draggable default true
26712 * @cfg {Boolean} enableAutocomplete default false
26713 * @cfg {Boolean} enableReverseGeocode default true
26714 * @cfg {String} markerTitle
26717 * Create a new LocationPicker
26718 * @param {Object} config The config object
26722 Roo.bootstrap.LocationPicker = function(config){
26724 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26729 * Fires when the picker initialized.
26730 * @param {Roo.bootstrap.LocationPicker} this
26731 * @param {Google Location} location
26735 * @event positionchanged
26736 * Fires when the picker position changed.
26737 * @param {Roo.bootstrap.LocationPicker} this
26738 * @param {Google Location} location
26740 positionchanged : true,
26743 * Fires when the map resize.
26744 * @param {Roo.bootstrap.LocationPicker} this
26749 * Fires when the map show.
26750 * @param {Roo.bootstrap.LocationPicker} this
26755 * Fires when the map hide.
26756 * @param {Roo.bootstrap.LocationPicker} this
26761 * Fires when click the map.
26762 * @param {Roo.bootstrap.LocationPicker} this
26763 * @param {Map event} e
26767 * @event mapRightClick
26768 * Fires when right click the map.
26769 * @param {Roo.bootstrap.LocationPicker} this
26770 * @param {Map event} e
26772 mapRightClick : true,
26774 * @event markerClick
26775 * Fires when click the marker.
26776 * @param {Roo.bootstrap.LocationPicker} this
26777 * @param {Map event} e
26779 markerClick : true,
26781 * @event markerRightClick
26782 * Fires when right click the marker.
26783 * @param {Roo.bootstrap.LocationPicker} this
26784 * @param {Map event} e
26786 markerRightClick : true,
26788 * @event OverlayViewDraw
26789 * Fires when OverlayView Draw
26790 * @param {Roo.bootstrap.LocationPicker} this
26792 OverlayViewDraw : true,
26794 * @event OverlayViewOnAdd
26795 * Fires when OverlayView Draw
26796 * @param {Roo.bootstrap.LocationPicker} this
26798 OverlayViewOnAdd : true,
26800 * @event OverlayViewOnRemove
26801 * Fires when OverlayView Draw
26802 * @param {Roo.bootstrap.LocationPicker} this
26804 OverlayViewOnRemove : true,
26806 * @event OverlayViewShow
26807 * Fires when OverlayView Draw
26808 * @param {Roo.bootstrap.LocationPicker} this
26809 * @param {Pixel} cpx
26811 OverlayViewShow : true,
26813 * @event OverlayViewHide
26814 * Fires when OverlayView Draw
26815 * @param {Roo.bootstrap.LocationPicker} this
26817 OverlayViewHide : true,
26819 * @event loadexception
26820 * Fires when load google lib failed.
26821 * @param {Roo.bootstrap.LocationPicker} this
26823 loadexception : true
26828 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26830 gMapContext: false,
26836 mapTypeControl: false,
26837 disableDoubleClickZoom: false,
26839 streetViewControl: false,
26843 enableAutocomplete: false,
26844 enableReverseGeocode: true,
26847 getAutoCreate: function()
26852 cls: 'roo-location-picker'
26858 initEvents: function(ct, position)
26860 if(!this.el.getWidth() || this.isApplied()){
26864 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26869 initial: function()
26871 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26872 this.fireEvent('loadexception', this);
26876 if(!this.mapTypeId){
26877 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26880 this.gMapContext = this.GMapContext();
26882 this.initOverlayView();
26884 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26888 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26889 _this.setPosition(_this.gMapContext.marker.position);
26892 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26893 _this.fireEvent('mapClick', this, event);
26897 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26898 _this.fireEvent('mapRightClick', this, event);
26902 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26903 _this.fireEvent('markerClick', this, event);
26907 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26908 _this.fireEvent('markerRightClick', this, event);
26912 this.setPosition(this.gMapContext.location);
26914 this.fireEvent('initial', this, this.gMapContext.location);
26917 initOverlayView: function()
26921 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26925 _this.fireEvent('OverlayViewDraw', _this);
26930 _this.fireEvent('OverlayViewOnAdd', _this);
26933 onRemove: function()
26935 _this.fireEvent('OverlayViewOnRemove', _this);
26938 show: function(cpx)
26940 _this.fireEvent('OverlayViewShow', _this, cpx);
26945 _this.fireEvent('OverlayViewHide', _this);
26951 fromLatLngToContainerPixel: function(event)
26953 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26956 isApplied: function()
26958 return this.getGmapContext() == false ? false : true;
26961 getGmapContext: function()
26963 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26966 GMapContext: function()
26968 var position = new google.maps.LatLng(this.latitude, this.longitude);
26970 var _map = new google.maps.Map(this.el.dom, {
26973 mapTypeId: this.mapTypeId,
26974 mapTypeControl: this.mapTypeControl,
26975 disableDoubleClickZoom: this.disableDoubleClickZoom,
26976 scrollwheel: this.scrollwheel,
26977 streetViewControl: this.streetViewControl,
26978 locationName: this.locationName,
26979 draggable: this.draggable,
26980 enableAutocomplete: this.enableAutocomplete,
26981 enableReverseGeocode: this.enableReverseGeocode
26984 var _marker = new google.maps.Marker({
26985 position: position,
26987 title: this.markerTitle,
26988 draggable: this.draggable
26995 location: position,
26996 radius: this.radius,
26997 locationName: this.locationName,
26998 addressComponents: {
26999 formatted_address: null,
27000 addressLine1: null,
27001 addressLine2: null,
27003 streetNumber: null,
27007 stateOrProvince: null
27010 domContainer: this.el.dom,
27011 geodecoder: new google.maps.Geocoder()
27015 drawCircle: function(center, radius, options)
27017 if (this.gMapContext.circle != null) {
27018 this.gMapContext.circle.setMap(null);
27022 options = Roo.apply({}, options, {
27023 strokeColor: "#0000FF",
27024 strokeOpacity: .35,
27026 fillColor: "#0000FF",
27030 options.map = this.gMapContext.map;
27031 options.radius = radius;
27032 options.center = center;
27033 this.gMapContext.circle = new google.maps.Circle(options);
27034 return this.gMapContext.circle;
27040 setPosition: function(location)
27042 this.gMapContext.location = location;
27043 this.gMapContext.marker.setPosition(location);
27044 this.gMapContext.map.panTo(location);
27045 this.drawCircle(location, this.gMapContext.radius, {});
27049 if (this.gMapContext.settings.enableReverseGeocode) {
27050 this.gMapContext.geodecoder.geocode({
27051 latLng: this.gMapContext.location
27052 }, function(results, status) {
27054 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27055 _this.gMapContext.locationName = results[0].formatted_address;
27056 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27058 _this.fireEvent('positionchanged', this, location);
27065 this.fireEvent('positionchanged', this, location);
27070 google.maps.event.trigger(this.gMapContext.map, "resize");
27072 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27074 this.fireEvent('resize', this);
27077 setPositionByLatLng: function(latitude, longitude)
27079 this.setPosition(new google.maps.LatLng(latitude, longitude));
27082 getCurrentPosition: function()
27085 latitude: this.gMapContext.location.lat(),
27086 longitude: this.gMapContext.location.lng()
27090 getAddressName: function()
27092 return this.gMapContext.locationName;
27095 getAddressComponents: function()
27097 return this.gMapContext.addressComponents;
27100 address_component_from_google_geocode: function(address_components)
27104 for (var i = 0; i < address_components.length; i++) {
27105 var component = address_components[i];
27106 if (component.types.indexOf("postal_code") >= 0) {
27107 result.postalCode = component.short_name;
27108 } else if (component.types.indexOf("street_number") >= 0) {
27109 result.streetNumber = component.short_name;
27110 } else if (component.types.indexOf("route") >= 0) {
27111 result.streetName = component.short_name;
27112 } else if (component.types.indexOf("neighborhood") >= 0) {
27113 result.city = component.short_name;
27114 } else if (component.types.indexOf("locality") >= 0) {
27115 result.city = component.short_name;
27116 } else if (component.types.indexOf("sublocality") >= 0) {
27117 result.district = component.short_name;
27118 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27119 result.stateOrProvince = component.short_name;
27120 } else if (component.types.indexOf("country") >= 0) {
27121 result.country = component.short_name;
27125 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27126 result.addressLine2 = "";
27130 setZoomLevel: function(zoom)
27132 this.gMapContext.map.setZoom(zoom);
27145 this.fireEvent('show', this);
27156 this.fireEvent('hide', this);
27161 Roo.apply(Roo.bootstrap.LocationPicker, {
27163 OverlayView : function(map, options)
27165 options = options || {};
27179 * @class Roo.bootstrap.Alert
27180 * @extends Roo.bootstrap.Component
27181 * Bootstrap Alert class
27182 * @cfg {String} title The title of alert
27183 * @cfg {String} html The content of alert
27184 * @cfg {String} weight ( success | info | warning | danger )
27185 * @cfg {String} faicon font-awesomeicon
27188 * Create a new alert
27189 * @param {Object} config The config object
27193 Roo.bootstrap.Alert = function(config){
27194 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27198 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27205 getAutoCreate : function()
27214 cls : 'roo-alert-icon'
27219 cls : 'roo-alert-title',
27224 cls : 'roo-alert-text',
27231 cfg.cn[0].cls += ' fa ' + this.faicon;
27235 cfg.cls += ' alert-' + this.weight;
27241 initEvents: function()
27243 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27246 setTitle : function(str)
27248 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27251 setText : function(str)
27253 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27256 setWeight : function(weight)
27259 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27262 this.weight = weight;
27264 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27267 setIcon : function(icon)
27270 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27273 this.faicon = icon;
27275 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27296 * @class Roo.bootstrap.UploadCropbox
27297 * @extends Roo.bootstrap.Component
27298 * Bootstrap UploadCropbox class
27299 * @cfg {String} emptyText show when image has been loaded
27300 * @cfg {String} rotateNotify show when image too small to rotate
27301 * @cfg {Number} errorTimeout default 3000
27302 * @cfg {Number} minWidth default 300
27303 * @cfg {Number} minHeight default 300
27304 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27305 * @cfg {Boolean} isDocument (true|false) default false
27306 * @cfg {String} url action url
27307 * @cfg {String} paramName default 'imageUpload'
27308 * @cfg {String} method default POST
27309 * @cfg {Boolean} loadMask (true|false) default true
27310 * @cfg {Boolean} loadingText default 'Loading...'
27313 * Create a new UploadCropbox
27314 * @param {Object} config The config object
27317 Roo.bootstrap.UploadCropbox = function(config){
27318 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27322 * @event beforeselectfile
27323 * Fire before select file
27324 * @param {Roo.bootstrap.UploadCropbox} this
27326 "beforeselectfile" : true,
27329 * Fire after initEvent
27330 * @param {Roo.bootstrap.UploadCropbox} this
27335 * Fire after initEvent
27336 * @param {Roo.bootstrap.UploadCropbox} this
27337 * @param {String} data
27342 * Fire when preparing the file data
27343 * @param {Roo.bootstrap.UploadCropbox} this
27344 * @param {Object} file
27349 * Fire when get exception
27350 * @param {Roo.bootstrap.UploadCropbox} this
27351 * @param {XMLHttpRequest} xhr
27353 "exception" : true,
27355 * @event beforeloadcanvas
27356 * Fire before load the canvas
27357 * @param {Roo.bootstrap.UploadCropbox} this
27358 * @param {String} src
27360 "beforeloadcanvas" : true,
27363 * Fire when trash image
27364 * @param {Roo.bootstrap.UploadCropbox} this
27369 * Fire when download the image
27370 * @param {Roo.bootstrap.UploadCropbox} this
27374 * @event footerbuttonclick
27375 * Fire when footerbuttonclick
27376 * @param {Roo.bootstrap.UploadCropbox} this
27377 * @param {String} type
27379 "footerbuttonclick" : true,
27383 * @param {Roo.bootstrap.UploadCropbox} this
27388 * Fire when rotate the image
27389 * @param {Roo.bootstrap.UploadCropbox} this
27390 * @param {String} pos
27395 * Fire when inspect the file
27396 * @param {Roo.bootstrap.UploadCropbox} this
27397 * @param {Object} file
27402 * Fire when xhr upload the file
27403 * @param {Roo.bootstrap.UploadCropbox} this
27404 * @param {Object} data
27409 * Fire when arrange the file data
27410 * @param {Roo.bootstrap.UploadCropbox} this
27411 * @param {Object} formData
27416 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27419 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27421 emptyText : 'Click to upload image',
27422 rotateNotify : 'Image is too small to rotate',
27423 errorTimeout : 3000,
27437 cropType : 'image/jpeg',
27439 canvasLoaded : false,
27440 isDocument : false,
27442 paramName : 'imageUpload',
27444 loadingText : 'Loading...',
27447 getAutoCreate : function()
27451 cls : 'roo-upload-cropbox',
27455 cls : 'roo-upload-cropbox-selector',
27460 cls : 'roo-upload-cropbox-body',
27461 style : 'cursor:pointer',
27465 cls : 'roo-upload-cropbox-preview'
27469 cls : 'roo-upload-cropbox-thumb'
27473 cls : 'roo-upload-cropbox-empty-notify',
27474 html : this.emptyText
27478 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27479 html : this.rotateNotify
27485 cls : 'roo-upload-cropbox-footer',
27488 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27498 onRender : function(ct, position)
27500 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27502 if (this.buttons.length) {
27504 Roo.each(this.buttons, function(bb) {
27506 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27508 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27514 this.maskEl = this.el;
27518 initEvents : function()
27520 this.urlAPI = (window.createObjectURL && window) ||
27521 (window.URL && URL.revokeObjectURL && URL) ||
27522 (window.webkitURL && webkitURL);
27524 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27525 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27527 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27528 this.selectorEl.hide();
27530 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27531 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27533 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27534 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27535 this.thumbEl.hide();
27537 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27538 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27540 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27541 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27542 this.errorEl.hide();
27544 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27545 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27546 this.footerEl.hide();
27548 this.setThumbBoxSize();
27554 this.fireEvent('initial', this);
27561 window.addEventListener("resize", function() { _this.resize(); } );
27563 this.bodyEl.on('click', this.beforeSelectFile, this);
27566 this.bodyEl.on('touchstart', this.onTouchStart, this);
27567 this.bodyEl.on('touchmove', this.onTouchMove, this);
27568 this.bodyEl.on('touchend', this.onTouchEnd, this);
27572 this.bodyEl.on('mousedown', this.onMouseDown, this);
27573 this.bodyEl.on('mousemove', this.onMouseMove, this);
27574 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27575 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27576 Roo.get(document).on('mouseup', this.onMouseUp, this);
27579 this.selectorEl.on('change', this.onFileSelected, this);
27585 this.baseScale = 1;
27587 this.baseRotate = 1;
27588 this.dragable = false;
27589 this.pinching = false;
27592 this.cropData = false;
27593 this.notifyEl.dom.innerHTML = this.emptyText;
27595 this.selectorEl.dom.value = '';
27599 resize : function()
27601 if(this.fireEvent('resize', this) != false){
27602 this.setThumbBoxPosition();
27603 this.setCanvasPosition();
27607 onFooterButtonClick : function(e, el, o, type)
27610 case 'rotate-left' :
27611 this.onRotateLeft(e);
27613 case 'rotate-right' :
27614 this.onRotateRight(e);
27617 this.beforeSelectFile(e);
27632 this.fireEvent('footerbuttonclick', this, type);
27635 beforeSelectFile : function(e)
27637 e.preventDefault();
27639 if(this.fireEvent('beforeselectfile', this) != false){
27640 this.selectorEl.dom.click();
27644 onFileSelected : function(e)
27646 e.preventDefault();
27648 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27652 var file = this.selectorEl.dom.files[0];
27654 if(this.fireEvent('inspect', this, file) != false){
27655 this.prepare(file);
27660 trash : function(e)
27662 this.fireEvent('trash', this);
27665 download : function(e)
27667 this.fireEvent('download', this);
27670 loadCanvas : function(src)
27672 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27676 this.imageEl = document.createElement('img');
27680 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27682 this.imageEl.src = src;
27686 onLoadCanvas : function()
27688 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27689 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27691 this.bodyEl.un('click', this.beforeSelectFile, this);
27693 this.notifyEl.hide();
27694 this.thumbEl.show();
27695 this.footerEl.show();
27697 this.baseRotateLevel();
27699 if(this.isDocument){
27700 this.setThumbBoxSize();
27703 this.setThumbBoxPosition();
27705 this.baseScaleLevel();
27711 this.canvasLoaded = true;
27714 this.maskEl.unmask();
27719 setCanvasPosition : function()
27721 if(!this.canvasEl){
27725 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27726 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27728 this.previewEl.setLeft(pw);
27729 this.previewEl.setTop(ph);
27733 onMouseDown : function(e)
27737 this.dragable = true;
27738 this.pinching = false;
27740 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27741 this.dragable = false;
27745 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27746 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27750 onMouseMove : function(e)
27754 if(!this.canvasLoaded){
27758 if (!this.dragable){
27762 var minX = Math.ceil(this.thumbEl.getLeft(true));
27763 var minY = Math.ceil(this.thumbEl.getTop(true));
27765 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27766 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27768 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27769 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27771 x = x - this.mouseX;
27772 y = y - this.mouseY;
27774 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27775 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27777 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27778 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27780 this.previewEl.setLeft(bgX);
27781 this.previewEl.setTop(bgY);
27783 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27784 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27787 onMouseUp : function(e)
27791 this.dragable = false;
27794 onMouseWheel : function(e)
27798 this.startScale = this.scale;
27800 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27802 if(!this.zoomable()){
27803 this.scale = this.startScale;
27812 zoomable : function()
27814 var minScale = this.thumbEl.getWidth() / this.minWidth;
27816 if(this.minWidth < this.minHeight){
27817 minScale = this.thumbEl.getHeight() / this.minHeight;
27820 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27821 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27825 (this.rotate == 0 || this.rotate == 180) &&
27827 width > this.imageEl.OriginWidth ||
27828 height > this.imageEl.OriginHeight ||
27829 (width < this.minWidth && height < this.minHeight)
27837 (this.rotate == 90 || this.rotate == 270) &&
27839 width > this.imageEl.OriginWidth ||
27840 height > this.imageEl.OriginHeight ||
27841 (width < this.minHeight && height < this.minWidth)
27848 !this.isDocument &&
27849 (this.rotate == 0 || this.rotate == 180) &&
27851 width < this.minWidth ||
27852 width > this.imageEl.OriginWidth ||
27853 height < this.minHeight ||
27854 height > this.imageEl.OriginHeight
27861 !this.isDocument &&
27862 (this.rotate == 90 || this.rotate == 270) &&
27864 width < this.minHeight ||
27865 width > this.imageEl.OriginWidth ||
27866 height < this.minWidth ||
27867 height > this.imageEl.OriginHeight
27877 onRotateLeft : function(e)
27879 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27881 var minScale = this.thumbEl.getWidth() / this.minWidth;
27883 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27884 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27886 this.startScale = this.scale;
27888 while (this.getScaleLevel() < minScale){
27890 this.scale = this.scale + 1;
27892 if(!this.zoomable()){
27897 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27898 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27903 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27910 this.scale = this.startScale;
27912 this.onRotateFail();
27917 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27919 if(this.isDocument){
27920 this.setThumbBoxSize();
27921 this.setThumbBoxPosition();
27922 this.setCanvasPosition();
27927 this.fireEvent('rotate', this, 'left');
27931 onRotateRight : function(e)
27933 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27935 var minScale = this.thumbEl.getWidth() / this.minWidth;
27937 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27938 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27940 this.startScale = this.scale;
27942 while (this.getScaleLevel() < minScale){
27944 this.scale = this.scale + 1;
27946 if(!this.zoomable()){
27951 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27952 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27957 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27964 this.scale = this.startScale;
27966 this.onRotateFail();
27971 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27973 if(this.isDocument){
27974 this.setThumbBoxSize();
27975 this.setThumbBoxPosition();
27976 this.setCanvasPosition();
27981 this.fireEvent('rotate', this, 'right');
27984 onRotateFail : function()
27986 this.errorEl.show(true);
27990 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27995 this.previewEl.dom.innerHTML = '';
27997 var canvasEl = document.createElement("canvas");
27999 var contextEl = canvasEl.getContext("2d");
28001 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28002 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28003 var center = this.imageEl.OriginWidth / 2;
28005 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28006 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28007 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28008 center = this.imageEl.OriginHeight / 2;
28011 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28013 contextEl.translate(center, center);
28014 contextEl.rotate(this.rotate * Math.PI / 180);
28016 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28018 this.canvasEl = document.createElement("canvas");
28020 this.contextEl = this.canvasEl.getContext("2d");
28022 switch (this.rotate) {
28025 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28026 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28028 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28033 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28034 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28036 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28037 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);
28041 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28046 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28047 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28049 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28050 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);
28054 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);
28059 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28060 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28062 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28063 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28067 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);
28074 this.previewEl.appendChild(this.canvasEl);
28076 this.setCanvasPosition();
28081 if(!this.canvasLoaded){
28085 var imageCanvas = document.createElement("canvas");
28087 var imageContext = imageCanvas.getContext("2d");
28089 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28090 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28092 var center = imageCanvas.width / 2;
28094 imageContext.translate(center, center);
28096 imageContext.rotate(this.rotate * Math.PI / 180);
28098 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28100 var canvas = document.createElement("canvas");
28102 var context = canvas.getContext("2d");
28104 canvas.width = this.minWidth;
28105 canvas.height = this.minHeight;
28107 switch (this.rotate) {
28110 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28111 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28113 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28114 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28116 var targetWidth = this.minWidth - 2 * x;
28117 var targetHeight = this.minHeight - 2 * y;
28121 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28122 scale = targetWidth / width;
28125 if(x > 0 && y == 0){
28126 scale = targetHeight / height;
28129 if(x > 0 && y > 0){
28130 scale = targetWidth / width;
28132 if(width < height){
28133 scale = targetHeight / height;
28137 context.scale(scale, scale);
28139 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28140 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28142 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28143 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28145 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28150 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28151 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28153 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28154 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28156 var targetWidth = this.minWidth - 2 * x;
28157 var targetHeight = this.minHeight - 2 * y;
28161 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28162 scale = targetWidth / width;
28165 if(x > 0 && y == 0){
28166 scale = targetHeight / height;
28169 if(x > 0 && y > 0){
28170 scale = targetWidth / width;
28172 if(width < height){
28173 scale = targetHeight / height;
28177 context.scale(scale, scale);
28179 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28180 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28182 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28183 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28185 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28187 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28192 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28193 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28195 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28196 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28198 var targetWidth = this.minWidth - 2 * x;
28199 var targetHeight = this.minHeight - 2 * y;
28203 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28204 scale = targetWidth / width;
28207 if(x > 0 && y == 0){
28208 scale = targetHeight / height;
28211 if(x > 0 && y > 0){
28212 scale = targetWidth / width;
28214 if(width < height){
28215 scale = targetHeight / height;
28219 context.scale(scale, scale);
28221 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28222 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28224 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28225 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28227 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28228 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28230 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28235 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28236 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28238 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28239 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28241 var targetWidth = this.minWidth - 2 * x;
28242 var targetHeight = this.minHeight - 2 * y;
28246 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28247 scale = targetWidth / width;
28250 if(x > 0 && y == 0){
28251 scale = targetHeight / height;
28254 if(x > 0 && y > 0){
28255 scale = targetWidth / width;
28257 if(width < height){
28258 scale = targetHeight / height;
28262 context.scale(scale, scale);
28264 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28265 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28267 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28268 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28270 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28272 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28279 this.cropData = canvas.toDataURL(this.cropType);
28281 if(this.fireEvent('crop', this, this.cropData) !== false){
28282 this.process(this.file, this.cropData);
28289 setThumbBoxSize : function()
28293 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28294 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28295 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28297 this.minWidth = width;
28298 this.minHeight = height;
28300 if(this.rotate == 90 || this.rotate == 270){
28301 this.minWidth = height;
28302 this.minHeight = width;
28307 width = Math.ceil(this.minWidth * height / this.minHeight);
28309 if(this.minWidth > this.minHeight){
28311 height = Math.ceil(this.minHeight * width / this.minWidth);
28314 this.thumbEl.setStyle({
28315 width : width + 'px',
28316 height : height + 'px'
28323 setThumbBoxPosition : function()
28325 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28326 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28328 this.thumbEl.setLeft(x);
28329 this.thumbEl.setTop(y);
28333 baseRotateLevel : function()
28335 this.baseRotate = 1;
28338 typeof(this.exif) != 'undefined' &&
28339 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28340 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28342 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28345 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28349 baseScaleLevel : function()
28353 if(this.isDocument){
28355 if(this.baseRotate == 6 || this.baseRotate == 8){
28357 height = this.thumbEl.getHeight();
28358 this.baseScale = height / this.imageEl.OriginWidth;
28360 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28361 width = this.thumbEl.getWidth();
28362 this.baseScale = width / this.imageEl.OriginHeight;
28368 height = this.thumbEl.getHeight();
28369 this.baseScale = height / this.imageEl.OriginHeight;
28371 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28372 width = this.thumbEl.getWidth();
28373 this.baseScale = width / this.imageEl.OriginWidth;
28379 if(this.baseRotate == 6 || this.baseRotate == 8){
28381 width = this.thumbEl.getHeight();
28382 this.baseScale = width / this.imageEl.OriginHeight;
28384 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28385 height = this.thumbEl.getWidth();
28386 this.baseScale = height / this.imageEl.OriginHeight;
28389 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28390 height = this.thumbEl.getWidth();
28391 this.baseScale = height / this.imageEl.OriginHeight;
28393 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28394 width = this.thumbEl.getHeight();
28395 this.baseScale = width / this.imageEl.OriginWidth;
28402 width = this.thumbEl.getWidth();
28403 this.baseScale = width / this.imageEl.OriginWidth;
28405 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28406 height = this.thumbEl.getHeight();
28407 this.baseScale = height / this.imageEl.OriginHeight;
28410 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28412 height = this.thumbEl.getHeight();
28413 this.baseScale = height / this.imageEl.OriginHeight;
28415 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28416 width = this.thumbEl.getWidth();
28417 this.baseScale = width / this.imageEl.OriginWidth;
28425 getScaleLevel : function()
28427 return this.baseScale * Math.pow(1.1, this.scale);
28430 onTouchStart : function(e)
28432 if(!this.canvasLoaded){
28433 this.beforeSelectFile(e);
28437 var touches = e.browserEvent.touches;
28443 if(touches.length == 1){
28444 this.onMouseDown(e);
28448 if(touches.length != 2){
28454 for(var i = 0, finger; finger = touches[i]; i++){
28455 coords.push(finger.pageX, finger.pageY);
28458 var x = Math.pow(coords[0] - coords[2], 2);
28459 var y = Math.pow(coords[1] - coords[3], 2);
28461 this.startDistance = Math.sqrt(x + y);
28463 this.startScale = this.scale;
28465 this.pinching = true;
28466 this.dragable = false;
28470 onTouchMove : function(e)
28472 if(!this.pinching && !this.dragable){
28476 var touches = e.browserEvent.touches;
28483 this.onMouseMove(e);
28489 for(var i = 0, finger; finger = touches[i]; i++){
28490 coords.push(finger.pageX, finger.pageY);
28493 var x = Math.pow(coords[0] - coords[2], 2);
28494 var y = Math.pow(coords[1] - coords[3], 2);
28496 this.endDistance = Math.sqrt(x + y);
28498 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28500 if(!this.zoomable()){
28501 this.scale = this.startScale;
28509 onTouchEnd : function(e)
28511 this.pinching = false;
28512 this.dragable = false;
28516 process : function(file, crop)
28519 this.maskEl.mask(this.loadingText);
28522 this.xhr = new XMLHttpRequest();
28524 file.xhr = this.xhr;
28526 this.xhr.open(this.method, this.url, true);
28529 "Accept": "application/json",
28530 "Cache-Control": "no-cache",
28531 "X-Requested-With": "XMLHttpRequest"
28534 for (var headerName in headers) {
28535 var headerValue = headers[headerName];
28537 this.xhr.setRequestHeader(headerName, headerValue);
28543 this.xhr.onload = function()
28545 _this.xhrOnLoad(_this.xhr);
28548 this.xhr.onerror = function()
28550 _this.xhrOnError(_this.xhr);
28553 var formData = new FormData();
28555 formData.append('returnHTML', 'NO');
28558 formData.append('crop', crop);
28561 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28562 formData.append(this.paramName, file, file.name);
28565 if(typeof(file.filename) != 'undefined'){
28566 formData.append('filename', file.filename);
28569 if(typeof(file.mimetype) != 'undefined'){
28570 formData.append('mimetype', file.mimetype);
28573 if(this.fireEvent('arrange', this, formData) != false){
28574 this.xhr.send(formData);
28578 xhrOnLoad : function(xhr)
28581 this.maskEl.unmask();
28584 if (xhr.readyState !== 4) {
28585 this.fireEvent('exception', this, xhr);
28589 var response = Roo.decode(xhr.responseText);
28591 if(!response.success){
28592 this.fireEvent('exception', this, xhr);
28596 var response = Roo.decode(xhr.responseText);
28598 this.fireEvent('upload', this, response);
28602 xhrOnError : function()
28605 this.maskEl.unmask();
28608 Roo.log('xhr on error');
28610 var response = Roo.decode(xhr.responseText);
28616 prepare : function(file)
28619 this.maskEl.mask(this.loadingText);
28625 if(typeof(file) === 'string'){
28626 this.loadCanvas(file);
28630 if(!file || !this.urlAPI){
28635 this.cropType = file.type;
28639 if(this.fireEvent('prepare', this, this.file) != false){
28641 var reader = new FileReader();
28643 reader.onload = function (e) {
28644 if (e.target.error) {
28645 Roo.log(e.target.error);
28649 var buffer = e.target.result,
28650 dataView = new DataView(buffer),
28652 maxOffset = dataView.byteLength - 4,
28656 if (dataView.getUint16(0) === 0xffd8) {
28657 while (offset < maxOffset) {
28658 markerBytes = dataView.getUint16(offset);
28660 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28661 markerLength = dataView.getUint16(offset + 2) + 2;
28662 if (offset + markerLength > dataView.byteLength) {
28663 Roo.log('Invalid meta data: Invalid segment size.');
28667 if(markerBytes == 0xffe1){
28668 _this.parseExifData(
28675 offset += markerLength;
28685 var url = _this.urlAPI.createObjectURL(_this.file);
28687 _this.loadCanvas(url);
28692 reader.readAsArrayBuffer(this.file);
28698 parseExifData : function(dataView, offset, length)
28700 var tiffOffset = offset + 10,
28704 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28705 // No Exif data, might be XMP data instead
28709 // Check for the ASCII code for "Exif" (0x45786966):
28710 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28711 // No Exif data, might be XMP data instead
28714 if (tiffOffset + 8 > dataView.byteLength) {
28715 Roo.log('Invalid Exif data: Invalid segment size.');
28718 // Check for the two null bytes:
28719 if (dataView.getUint16(offset + 8) !== 0x0000) {
28720 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28723 // Check the byte alignment:
28724 switch (dataView.getUint16(tiffOffset)) {
28726 littleEndian = true;
28729 littleEndian = false;
28732 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28735 // Check for the TIFF tag marker (0x002A):
28736 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28737 Roo.log('Invalid Exif data: Missing TIFF marker.');
28740 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28741 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28743 this.parseExifTags(
28746 tiffOffset + dirOffset,
28751 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28756 if (dirOffset + 6 > dataView.byteLength) {
28757 Roo.log('Invalid Exif data: Invalid directory offset.');
28760 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28761 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28762 if (dirEndOffset + 4 > dataView.byteLength) {
28763 Roo.log('Invalid Exif data: Invalid directory size.');
28766 for (i = 0; i < tagsNumber; i += 1) {
28770 dirOffset + 2 + 12 * i, // tag offset
28774 // Return the offset to the next directory:
28775 return dataView.getUint32(dirEndOffset, littleEndian);
28778 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28780 var tag = dataView.getUint16(offset, littleEndian);
28782 this.exif[tag] = this.getExifValue(
28786 dataView.getUint16(offset + 2, littleEndian), // tag type
28787 dataView.getUint32(offset + 4, littleEndian), // tag length
28792 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28794 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28803 Roo.log('Invalid Exif data: Invalid tag type.');
28807 tagSize = tagType.size * length;
28808 // Determine if the value is contained in the dataOffset bytes,
28809 // or if the value at the dataOffset is a pointer to the actual data:
28810 dataOffset = tagSize > 4 ?
28811 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28812 if (dataOffset + tagSize > dataView.byteLength) {
28813 Roo.log('Invalid Exif data: Invalid data offset.');
28816 if (length === 1) {
28817 return tagType.getValue(dataView, dataOffset, littleEndian);
28820 for (i = 0; i < length; i += 1) {
28821 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28824 if (tagType.ascii) {
28826 // Concatenate the chars:
28827 for (i = 0; i < values.length; i += 1) {
28829 // Ignore the terminating NULL byte(s):
28830 if (c === '\u0000') {
28842 Roo.apply(Roo.bootstrap.UploadCropbox, {
28844 'Orientation': 0x0112
28848 1: 0, //'top-left',
28850 3: 180, //'bottom-right',
28851 // 4: 'bottom-left',
28853 6: 90, //'right-top',
28854 // 7: 'right-bottom',
28855 8: 270 //'left-bottom'
28859 // byte, 8-bit unsigned int:
28861 getValue: function (dataView, dataOffset) {
28862 return dataView.getUint8(dataOffset);
28866 // ascii, 8-bit byte:
28868 getValue: function (dataView, dataOffset) {
28869 return String.fromCharCode(dataView.getUint8(dataOffset));
28874 // short, 16 bit int:
28876 getValue: function (dataView, dataOffset, littleEndian) {
28877 return dataView.getUint16(dataOffset, littleEndian);
28881 // long, 32 bit int:
28883 getValue: function (dataView, dataOffset, littleEndian) {
28884 return dataView.getUint32(dataOffset, littleEndian);
28888 // rational = two long values, first is numerator, second is denominator:
28890 getValue: function (dataView, dataOffset, littleEndian) {
28891 return dataView.getUint32(dataOffset, littleEndian) /
28892 dataView.getUint32(dataOffset + 4, littleEndian);
28896 // slong, 32 bit signed int:
28898 getValue: function (dataView, dataOffset, littleEndian) {
28899 return dataView.getInt32(dataOffset, littleEndian);
28903 // srational, two slongs, first is numerator, second is denominator:
28905 getValue: function (dataView, dataOffset, littleEndian) {
28906 return dataView.getInt32(dataOffset, littleEndian) /
28907 dataView.getInt32(dataOffset + 4, littleEndian);
28917 cls : 'btn-group roo-upload-cropbox-rotate-left',
28918 action : 'rotate-left',
28922 cls : 'btn btn-default',
28923 html : '<i class="fa fa-undo"></i>'
28929 cls : 'btn-group roo-upload-cropbox-picture',
28930 action : 'picture',
28934 cls : 'btn btn-default',
28935 html : '<i class="fa fa-picture-o"></i>'
28941 cls : 'btn-group roo-upload-cropbox-rotate-right',
28942 action : 'rotate-right',
28946 cls : 'btn btn-default',
28947 html : '<i class="fa fa-repeat"></i>'
28955 cls : 'btn-group roo-upload-cropbox-rotate-left',
28956 action : 'rotate-left',
28960 cls : 'btn btn-default',
28961 html : '<i class="fa fa-undo"></i>'
28967 cls : 'btn-group roo-upload-cropbox-download',
28968 action : 'download',
28972 cls : 'btn btn-default',
28973 html : '<i class="fa fa-download"></i>'
28979 cls : 'btn-group roo-upload-cropbox-crop',
28984 cls : 'btn btn-default',
28985 html : '<i class="fa fa-crop"></i>'
28991 cls : 'btn-group roo-upload-cropbox-trash',
28996 cls : 'btn btn-default',
28997 html : '<i class="fa fa-trash"></i>'
29003 cls : 'btn-group roo-upload-cropbox-rotate-right',
29004 action : 'rotate-right',
29008 cls : 'btn btn-default',
29009 html : '<i class="fa fa-repeat"></i>'
29017 cls : 'btn-group roo-upload-cropbox-rotate-left',
29018 action : 'rotate-left',
29022 cls : 'btn btn-default',
29023 html : '<i class="fa fa-undo"></i>'
29029 cls : 'btn-group roo-upload-cropbox-rotate-right',
29030 action : 'rotate-right',
29034 cls : 'btn btn-default',
29035 html : '<i class="fa fa-repeat"></i>'
29048 * @class Roo.bootstrap.DocumentManager
29049 * @extends Roo.bootstrap.Component
29050 * Bootstrap DocumentManager class
29051 * @cfg {String} paramName default 'imageUpload'
29052 * @cfg {String} toolTipName default 'filename'
29053 * @cfg {String} method default POST
29054 * @cfg {String} url action url
29055 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29056 * @cfg {Boolean} multiple multiple upload default true
29057 * @cfg {Number} thumbSize default 300
29058 * @cfg {String} fieldLabel
29059 * @cfg {Number} labelWidth default 4
29060 * @cfg {String} labelAlign (left|top) default left
29061 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29062 * @cfg {Number} labellg set the width of label (1-12)
29063 * @cfg {Number} labelmd set the width of label (1-12)
29064 * @cfg {Number} labelsm set the width of label (1-12)
29065 * @cfg {Number} labelxs set the width of label (1-12)
29068 * Create a new DocumentManager
29069 * @param {Object} config The config object
29072 Roo.bootstrap.DocumentManager = function(config){
29073 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29076 this.delegates = [];
29081 * Fire when initial the DocumentManager
29082 * @param {Roo.bootstrap.DocumentManager} this
29087 * inspect selected file
29088 * @param {Roo.bootstrap.DocumentManager} this
29089 * @param {File} file
29094 * Fire when xhr load exception
29095 * @param {Roo.bootstrap.DocumentManager} this
29096 * @param {XMLHttpRequest} xhr
29098 "exception" : true,
29100 * @event afterupload
29101 * Fire when xhr load exception
29102 * @param {Roo.bootstrap.DocumentManager} this
29103 * @param {XMLHttpRequest} xhr
29105 "afterupload" : true,
29108 * prepare the form data
29109 * @param {Roo.bootstrap.DocumentManager} this
29110 * @param {Object} formData
29115 * Fire when remove the file
29116 * @param {Roo.bootstrap.DocumentManager} this
29117 * @param {Object} file
29122 * Fire after refresh the file
29123 * @param {Roo.bootstrap.DocumentManager} this
29128 * Fire after click the image
29129 * @param {Roo.bootstrap.DocumentManager} this
29130 * @param {Object} file
29135 * Fire when upload a image and editable set to true
29136 * @param {Roo.bootstrap.DocumentManager} this
29137 * @param {Object} file
29141 * @event beforeselectfile
29142 * Fire before select file
29143 * @param {Roo.bootstrap.DocumentManager} this
29145 "beforeselectfile" : true,
29148 * Fire before process file
29149 * @param {Roo.bootstrap.DocumentManager} this
29150 * @param {Object} file
29154 * @event previewrendered
29155 * Fire when preview rendered
29156 * @param {Roo.bootstrap.DocumentManager} this
29157 * @param {Object} file
29159 "previewrendered" : true,
29162 "previewResize" : true
29167 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29176 paramName : 'imageUpload',
29177 toolTipName : 'filename',
29180 labelAlign : 'left',
29190 getAutoCreate : function()
29192 var managerWidget = {
29194 cls : 'roo-document-manager',
29198 cls : 'roo-document-manager-selector',
29203 cls : 'roo-document-manager-uploader',
29207 cls : 'roo-document-manager-upload-btn',
29208 html : '<i class="fa fa-plus"></i>'
29219 cls : 'column col-md-12',
29224 if(this.fieldLabel.length){
29229 cls : 'column col-md-12',
29230 html : this.fieldLabel
29234 cls : 'column col-md-12',
29239 if(this.labelAlign == 'left'){
29244 html : this.fieldLabel
29253 if(this.labelWidth > 12){
29254 content[0].style = "width: " + this.labelWidth + 'px';
29257 if(this.labelWidth < 13 && this.labelmd == 0){
29258 this.labelmd = this.labelWidth;
29261 if(this.labellg > 0){
29262 content[0].cls += ' col-lg-' + this.labellg;
29263 content[1].cls += ' col-lg-' + (12 - this.labellg);
29266 if(this.labelmd > 0){
29267 content[0].cls += ' col-md-' + this.labelmd;
29268 content[1].cls += ' col-md-' + (12 - this.labelmd);
29271 if(this.labelsm > 0){
29272 content[0].cls += ' col-sm-' + this.labelsm;
29273 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29276 if(this.labelxs > 0){
29277 content[0].cls += ' col-xs-' + this.labelxs;
29278 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29286 cls : 'row clearfix',
29294 initEvents : function()
29296 this.managerEl = this.el.select('.roo-document-manager', true).first();
29297 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29299 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29300 this.selectorEl.hide();
29303 this.selectorEl.attr('multiple', 'multiple');
29306 this.selectorEl.on('change', this.onFileSelected, this);
29308 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29309 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29311 this.uploader.on('click', this.onUploaderClick, this);
29313 this.renderProgressDialog();
29317 window.addEventListener("resize", function() { _this.refresh(); } );
29319 this.fireEvent('initial', this);
29322 renderProgressDialog : function()
29326 this.progressDialog = new Roo.bootstrap.Modal({
29327 cls : 'roo-document-manager-progress-dialog',
29328 allow_close : false,
29339 btnclick : function() {
29340 _this.uploadCancel();
29346 this.progressDialog.render(Roo.get(document.body));
29348 this.progress = new Roo.bootstrap.Progress({
29349 cls : 'roo-document-manager-progress',
29354 this.progress.render(this.progressDialog.getChildContainer());
29356 this.progressBar = new Roo.bootstrap.ProgressBar({
29357 cls : 'roo-document-manager-progress-bar',
29360 aria_valuemax : 12,
29364 this.progressBar.render(this.progress.getChildContainer());
29367 onUploaderClick : function(e)
29369 e.preventDefault();
29371 if(this.fireEvent('beforeselectfile', this) != false){
29372 this.selectorEl.dom.click();
29377 onFileSelected : function(e)
29379 e.preventDefault();
29381 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29385 Roo.each(this.selectorEl.dom.files, function(file){
29386 if(this.fireEvent('inspect', this, file) != false){
29387 this.files.push(file);
29397 this.selectorEl.dom.value = '';
29399 if(!this.files || !this.files.length){
29403 if(this.boxes > 0 && this.files.length > this.boxes){
29404 this.files = this.files.slice(0, this.boxes);
29407 this.uploader.show();
29409 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29410 this.uploader.hide();
29419 Roo.each(this.files, function(file){
29421 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29422 var f = this.renderPreview(file);
29427 if(file.type.indexOf('image') != -1){
29428 this.delegates.push(
29430 _this.process(file);
29431 }).createDelegate(this)
29439 _this.process(file);
29440 }).createDelegate(this)
29445 this.files = files;
29447 this.delegates = this.delegates.concat(docs);
29449 if(!this.delegates.length){
29454 this.progressBar.aria_valuemax = this.delegates.length;
29461 arrange : function()
29463 if(!this.delegates.length){
29464 this.progressDialog.hide();
29469 var delegate = this.delegates.shift();
29471 this.progressDialog.show();
29473 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29475 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29480 refresh : function()
29482 this.uploader.show();
29484 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29485 this.uploader.hide();
29488 Roo.isTouch ? this.closable(false) : this.closable(true);
29490 this.fireEvent('refresh', this);
29493 onRemove : function(e, el, o)
29495 e.preventDefault();
29497 this.fireEvent('remove', this, o);
29501 remove : function(o)
29505 Roo.each(this.files, function(file){
29506 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29515 this.files = files;
29522 Roo.each(this.files, function(file){
29527 file.target.remove();
29536 onClick : function(e, el, o)
29538 e.preventDefault();
29540 this.fireEvent('click', this, o);
29544 closable : function(closable)
29546 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29548 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29560 xhrOnLoad : function(xhr)
29562 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29566 if (xhr.readyState !== 4) {
29568 this.fireEvent('exception', this, xhr);
29572 var response = Roo.decode(xhr.responseText);
29574 if(!response.success){
29576 this.fireEvent('exception', this, xhr);
29580 var file = this.renderPreview(response.data);
29582 this.files.push(file);
29586 this.fireEvent('afterupload', this, xhr);
29590 xhrOnError : function(xhr)
29592 Roo.log('xhr on error');
29594 var response = Roo.decode(xhr.responseText);
29601 process : function(file)
29603 if(this.fireEvent('process', this, file) !== false){
29604 if(this.editable && file.type.indexOf('image') != -1){
29605 this.fireEvent('edit', this, file);
29609 this.uploadStart(file, false);
29616 uploadStart : function(file, crop)
29618 this.xhr = new XMLHttpRequest();
29620 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29625 file.xhr = this.xhr;
29627 this.managerEl.createChild({
29629 cls : 'roo-document-manager-loading',
29633 tooltip : file.name,
29634 cls : 'roo-document-manager-thumb',
29635 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29641 this.xhr.open(this.method, this.url, true);
29644 "Accept": "application/json",
29645 "Cache-Control": "no-cache",
29646 "X-Requested-With": "XMLHttpRequest"
29649 for (var headerName in headers) {
29650 var headerValue = headers[headerName];
29652 this.xhr.setRequestHeader(headerName, headerValue);
29658 this.xhr.onload = function()
29660 _this.xhrOnLoad(_this.xhr);
29663 this.xhr.onerror = function()
29665 _this.xhrOnError(_this.xhr);
29668 var formData = new FormData();
29670 formData.append('returnHTML', 'NO');
29673 formData.append('crop', crop);
29676 formData.append(this.paramName, file, file.name);
29683 if(this.fireEvent('prepare', this, formData, options) != false){
29685 if(options.manually){
29689 this.xhr.send(formData);
29693 this.uploadCancel();
29696 uploadCancel : function()
29702 this.delegates = [];
29704 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29711 renderPreview : function(file)
29713 if(typeof(file.target) != 'undefined' && file.target){
29717 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29719 var previewEl = this.managerEl.createChild({
29721 cls : 'roo-document-manager-preview',
29725 tooltip : file[this.toolTipName],
29726 cls : 'roo-document-manager-thumb',
29727 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29732 html : '<i class="fa fa-times-circle"></i>'
29737 var close = previewEl.select('button.close', true).first();
29739 close.on('click', this.onRemove, this, file);
29741 file.target = previewEl;
29743 var image = previewEl.select('img', true).first();
29747 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29749 image.on('click', this.onClick, this, file);
29751 this.fireEvent('previewrendered', this, file);
29757 onPreviewLoad : function(file, image)
29759 if(typeof(file.target) == 'undefined' || !file.target){
29763 var width = image.dom.naturalWidth || image.dom.width;
29764 var height = image.dom.naturalHeight || image.dom.height;
29766 if(!this.previewResize) {
29770 if(width > height){
29771 file.target.addClass('wide');
29775 file.target.addClass('tall');
29780 uploadFromSource : function(file, crop)
29782 this.xhr = new XMLHttpRequest();
29784 this.managerEl.createChild({
29786 cls : 'roo-document-manager-loading',
29790 tooltip : file.name,
29791 cls : 'roo-document-manager-thumb',
29792 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29798 this.xhr.open(this.method, this.url, true);
29801 "Accept": "application/json",
29802 "Cache-Control": "no-cache",
29803 "X-Requested-With": "XMLHttpRequest"
29806 for (var headerName in headers) {
29807 var headerValue = headers[headerName];
29809 this.xhr.setRequestHeader(headerName, headerValue);
29815 this.xhr.onload = function()
29817 _this.xhrOnLoad(_this.xhr);
29820 this.xhr.onerror = function()
29822 _this.xhrOnError(_this.xhr);
29825 var formData = new FormData();
29827 formData.append('returnHTML', 'NO');
29829 formData.append('crop', crop);
29831 if(typeof(file.filename) != 'undefined'){
29832 formData.append('filename', file.filename);
29835 if(typeof(file.mimetype) != 'undefined'){
29836 formData.append('mimetype', file.mimetype);
29841 if(this.fireEvent('prepare', this, formData) != false){
29842 this.xhr.send(formData);
29852 * @class Roo.bootstrap.DocumentViewer
29853 * @extends Roo.bootstrap.Component
29854 * Bootstrap DocumentViewer class
29855 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29856 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29859 * Create a new DocumentViewer
29860 * @param {Object} config The config object
29863 Roo.bootstrap.DocumentViewer = function(config){
29864 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29869 * Fire after initEvent
29870 * @param {Roo.bootstrap.DocumentViewer} this
29876 * @param {Roo.bootstrap.DocumentViewer} this
29881 * Fire after download button
29882 * @param {Roo.bootstrap.DocumentViewer} this
29887 * Fire after trash button
29888 * @param {Roo.bootstrap.DocumentViewer} this
29895 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29897 showDownload : true,
29901 getAutoCreate : function()
29905 cls : 'roo-document-viewer',
29909 cls : 'roo-document-viewer-body',
29913 cls : 'roo-document-viewer-thumb',
29917 cls : 'roo-document-viewer-image'
29925 cls : 'roo-document-viewer-footer',
29928 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29932 cls : 'btn-group roo-document-viewer-download',
29936 cls : 'btn btn-default',
29937 html : '<i class="fa fa-download"></i>'
29943 cls : 'btn-group roo-document-viewer-trash',
29947 cls : 'btn btn-default',
29948 html : '<i class="fa fa-trash"></i>'
29961 initEvents : function()
29963 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29964 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29966 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29967 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29969 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29970 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29972 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29973 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29975 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29976 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29978 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29979 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29981 this.bodyEl.on('click', this.onClick, this);
29982 this.downloadBtn.on('click', this.onDownload, this);
29983 this.trashBtn.on('click', this.onTrash, this);
29985 this.downloadBtn.hide();
29986 this.trashBtn.hide();
29988 if(this.showDownload){
29989 this.downloadBtn.show();
29992 if(this.showTrash){
29993 this.trashBtn.show();
29996 if(!this.showDownload && !this.showTrash) {
29997 this.footerEl.hide();
30002 initial : function()
30004 this.fireEvent('initial', this);
30008 onClick : function(e)
30010 e.preventDefault();
30012 this.fireEvent('click', this);
30015 onDownload : function(e)
30017 e.preventDefault();
30019 this.fireEvent('download', this);
30022 onTrash : function(e)
30024 e.preventDefault();
30026 this.fireEvent('trash', this);
30038 * @class Roo.bootstrap.NavProgressBar
30039 * @extends Roo.bootstrap.Component
30040 * Bootstrap NavProgressBar class
30043 * Create a new nav progress bar
30044 * @param {Object} config The config object
30047 Roo.bootstrap.NavProgressBar = function(config){
30048 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30050 this.bullets = this.bullets || [];
30052 // Roo.bootstrap.NavProgressBar.register(this);
30056 * Fires when the active item changes
30057 * @param {Roo.bootstrap.NavProgressBar} this
30058 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30059 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30066 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30071 getAutoCreate : function()
30073 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30077 cls : 'roo-navigation-bar-group',
30081 cls : 'roo-navigation-top-bar'
30085 cls : 'roo-navigation-bullets-bar',
30089 cls : 'roo-navigation-bar'
30096 cls : 'roo-navigation-bottom-bar'
30106 initEvents: function()
30111 onRender : function(ct, position)
30113 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30115 if(this.bullets.length){
30116 Roo.each(this.bullets, function(b){
30125 addItem : function(cfg)
30127 var item = new Roo.bootstrap.NavProgressItem(cfg);
30129 item.parentId = this.id;
30130 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30133 var top = new Roo.bootstrap.Element({
30135 cls : 'roo-navigation-bar-text'
30138 var bottom = new Roo.bootstrap.Element({
30140 cls : 'roo-navigation-bar-text'
30143 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30144 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30146 var topText = new Roo.bootstrap.Element({
30148 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30151 var bottomText = new Roo.bootstrap.Element({
30153 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30156 topText.onRender(top.el, null);
30157 bottomText.onRender(bottom.el, null);
30160 item.bottomEl = bottom;
30163 this.barItems.push(item);
30168 getActive : function()
30170 var active = false;
30172 Roo.each(this.barItems, function(v){
30174 if (!v.isActive()) {
30186 setActiveItem : function(item)
30190 Roo.each(this.barItems, function(v){
30191 if (v.rid == item.rid) {
30195 if (v.isActive()) {
30196 v.setActive(false);
30201 item.setActive(true);
30203 this.fireEvent('changed', this, item, prev);
30206 getBarItem: function(rid)
30210 Roo.each(this.barItems, function(e) {
30211 if (e.rid != rid) {
30222 indexOfItem : function(item)
30226 Roo.each(this.barItems, function(v, i){
30228 if (v.rid != item.rid) {
30239 setActiveNext : function()
30241 var i = this.indexOfItem(this.getActive());
30243 if (i > this.barItems.length) {
30247 this.setActiveItem(this.barItems[i+1]);
30250 setActivePrev : function()
30252 var i = this.indexOfItem(this.getActive());
30258 this.setActiveItem(this.barItems[i-1]);
30261 format : function()
30263 if(!this.barItems.length){
30267 var width = 100 / this.barItems.length;
30269 Roo.each(this.barItems, function(i){
30270 i.el.setStyle('width', width + '%');
30271 i.topEl.el.setStyle('width', width + '%');
30272 i.bottomEl.el.setStyle('width', width + '%');
30281 * Nav Progress Item
30286 * @class Roo.bootstrap.NavProgressItem
30287 * @extends Roo.bootstrap.Component
30288 * Bootstrap NavProgressItem class
30289 * @cfg {String} rid the reference id
30290 * @cfg {Boolean} active (true|false) Is item active default false
30291 * @cfg {Boolean} disabled (true|false) Is item active default false
30292 * @cfg {String} html
30293 * @cfg {String} position (top|bottom) text position default bottom
30294 * @cfg {String} icon show icon instead of number
30297 * Create a new NavProgressItem
30298 * @param {Object} config The config object
30300 Roo.bootstrap.NavProgressItem = function(config){
30301 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30306 * The raw click event for the entire grid.
30307 * @param {Roo.bootstrap.NavProgressItem} this
30308 * @param {Roo.EventObject} e
30315 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30321 position : 'bottom',
30324 getAutoCreate : function()
30326 var iconCls = 'roo-navigation-bar-item-icon';
30328 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30332 cls: 'roo-navigation-bar-item',
30342 cfg.cls += ' active';
30345 cfg.cls += ' disabled';
30351 disable : function()
30353 this.setDisabled(true);
30356 enable : function()
30358 this.setDisabled(false);
30361 initEvents: function()
30363 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30365 this.iconEl.on('click', this.onClick, this);
30368 onClick : function(e)
30370 e.preventDefault();
30376 if(this.fireEvent('click', this, e) === false){
30380 this.parent().setActiveItem(this);
30383 isActive: function ()
30385 return this.active;
30388 setActive : function(state)
30390 if(this.active == state){
30394 this.active = state;
30397 this.el.addClass('active');
30401 this.el.removeClass('active');
30406 setDisabled : function(state)
30408 if(this.disabled == state){
30412 this.disabled = state;
30415 this.el.addClass('disabled');
30419 this.el.removeClass('disabled');
30422 tooltipEl : function()
30424 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30437 * @class Roo.bootstrap.FieldLabel
30438 * @extends Roo.bootstrap.Component
30439 * Bootstrap FieldLabel class
30440 * @cfg {String} html contents of the element
30441 * @cfg {String} tag tag of the element default label
30442 * @cfg {String} cls class of the element
30443 * @cfg {String} target label target
30444 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30445 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30446 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30447 * @cfg {String} iconTooltip default "This field is required"
30448 * @cfg {String} indicatorpos (left|right) default left
30451 * Create a new FieldLabel
30452 * @param {Object} config The config object
30455 Roo.bootstrap.FieldLabel = function(config){
30456 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30461 * Fires after the field has been marked as invalid.
30462 * @param {Roo.form.FieldLabel} this
30463 * @param {String} msg The validation message
30468 * Fires after the field has been validated with no errors.
30469 * @param {Roo.form.FieldLabel} this
30475 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30482 invalidClass : 'has-warning',
30483 validClass : 'has-success',
30484 iconTooltip : 'This field is required',
30485 indicatorpos : 'left',
30487 getAutoCreate : function(){
30490 if (!this.allowBlank) {
30496 cls : 'roo-bootstrap-field-label ' + this.cls,
30501 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30502 tooltip : this.iconTooltip
30511 if(this.indicatorpos == 'right'){
30514 cls : 'roo-bootstrap-field-label ' + this.cls,
30523 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30524 tooltip : this.iconTooltip
30533 initEvents: function()
30535 Roo.bootstrap.Element.superclass.initEvents.call(this);
30537 this.indicator = this.indicatorEl();
30539 if(this.indicator){
30540 this.indicator.removeClass('visible');
30541 this.indicator.addClass('invisible');
30544 Roo.bootstrap.FieldLabel.register(this);
30547 indicatorEl : function()
30549 var indicator = this.el.select('i.roo-required-indicator',true).first();
30560 * Mark this field as valid
30562 markValid : function()
30564 if(this.indicator){
30565 this.indicator.removeClass('visible');
30566 this.indicator.addClass('invisible');
30568 if (Roo.bootstrap.version == 3) {
30569 this.el.removeClass(this.invalidClass);
30570 this.el.addClass(this.validClass);
30572 this.el.removeClass('is-invalid');
30573 this.el.addClass('is-valid');
30577 this.fireEvent('valid', this);
30581 * Mark this field as invalid
30582 * @param {String} msg The validation message
30584 markInvalid : function(msg)
30586 if(this.indicator){
30587 this.indicator.removeClass('invisible');
30588 this.indicator.addClass('visible');
30590 if (Roo.bootstrap.version == 3) {
30591 this.el.removeClass(this.validClass);
30592 this.el.addClass(this.invalidClass);
30594 this.el.removeClass('is-valid');
30595 this.el.addClass('is-invalid');
30599 this.fireEvent('invalid', this, msg);
30605 Roo.apply(Roo.bootstrap.FieldLabel, {
30610 * register a FieldLabel Group
30611 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30613 register : function(label)
30615 if(this.groups.hasOwnProperty(label.target)){
30619 this.groups[label.target] = label;
30623 * fetch a FieldLabel Group based on the target
30624 * @param {string} target
30625 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30627 get: function(target) {
30628 if (typeof(this.groups[target]) == 'undefined') {
30632 return this.groups[target] ;
30641 * page DateSplitField.
30647 * @class Roo.bootstrap.DateSplitField
30648 * @extends Roo.bootstrap.Component
30649 * Bootstrap DateSplitField class
30650 * @cfg {string} fieldLabel - the label associated
30651 * @cfg {Number} labelWidth set the width of label (0-12)
30652 * @cfg {String} labelAlign (top|left)
30653 * @cfg {Boolean} dayAllowBlank (true|false) default false
30654 * @cfg {Boolean} monthAllowBlank (true|false) default false
30655 * @cfg {Boolean} yearAllowBlank (true|false) default false
30656 * @cfg {string} dayPlaceholder
30657 * @cfg {string} monthPlaceholder
30658 * @cfg {string} yearPlaceholder
30659 * @cfg {string} dayFormat default 'd'
30660 * @cfg {string} monthFormat default 'm'
30661 * @cfg {string} yearFormat default 'Y'
30662 * @cfg {Number} labellg set the width of label (1-12)
30663 * @cfg {Number} labelmd set the width of label (1-12)
30664 * @cfg {Number} labelsm set the width of label (1-12)
30665 * @cfg {Number} labelxs set the width of label (1-12)
30669 * Create a new DateSplitField
30670 * @param {Object} config The config object
30673 Roo.bootstrap.DateSplitField = function(config){
30674 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30680 * getting the data of years
30681 * @param {Roo.bootstrap.DateSplitField} this
30682 * @param {Object} years
30687 * getting the data of days
30688 * @param {Roo.bootstrap.DateSplitField} this
30689 * @param {Object} days
30694 * Fires after the field has been marked as invalid.
30695 * @param {Roo.form.Field} this
30696 * @param {String} msg The validation message
30701 * Fires after the field has been validated with no errors.
30702 * @param {Roo.form.Field} this
30708 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30711 labelAlign : 'top',
30713 dayAllowBlank : false,
30714 monthAllowBlank : false,
30715 yearAllowBlank : false,
30716 dayPlaceholder : '',
30717 monthPlaceholder : '',
30718 yearPlaceholder : '',
30722 isFormField : true,
30728 getAutoCreate : function()
30732 cls : 'row roo-date-split-field-group',
30737 cls : 'form-hidden-field roo-date-split-field-group-value',
30743 var labelCls = 'col-md-12';
30744 var contentCls = 'col-md-4';
30746 if(this.fieldLabel){
30750 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30754 html : this.fieldLabel
30759 if(this.labelAlign == 'left'){
30761 if(this.labelWidth > 12){
30762 label.style = "width: " + this.labelWidth + 'px';
30765 if(this.labelWidth < 13 && this.labelmd == 0){
30766 this.labelmd = this.labelWidth;
30769 if(this.labellg > 0){
30770 labelCls = ' col-lg-' + this.labellg;
30771 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30774 if(this.labelmd > 0){
30775 labelCls = ' col-md-' + this.labelmd;
30776 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30779 if(this.labelsm > 0){
30780 labelCls = ' col-sm-' + this.labelsm;
30781 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30784 if(this.labelxs > 0){
30785 labelCls = ' col-xs-' + this.labelxs;
30786 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30790 label.cls += ' ' + labelCls;
30792 cfg.cn.push(label);
30795 Roo.each(['day', 'month', 'year'], function(t){
30798 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30805 inputEl: function ()
30807 return this.el.select('.roo-date-split-field-group-value', true).first();
30810 onRender : function(ct, position)
30814 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30816 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30818 this.dayField = new Roo.bootstrap.ComboBox({
30819 allowBlank : this.dayAllowBlank,
30820 alwaysQuery : true,
30821 displayField : 'value',
30824 forceSelection : true,
30826 placeholder : this.dayPlaceholder,
30827 selectOnFocus : true,
30828 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30829 triggerAction : 'all',
30831 valueField : 'value',
30832 store : new Roo.data.SimpleStore({
30833 data : (function() {
30835 _this.fireEvent('days', _this, days);
30838 fields : [ 'value' ]
30841 select : function (_self, record, index)
30843 _this.setValue(_this.getValue());
30848 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30850 this.monthField = new Roo.bootstrap.MonthField({
30851 after : '<i class=\"fa fa-calendar\"></i>',
30852 allowBlank : this.monthAllowBlank,
30853 placeholder : this.monthPlaceholder,
30856 render : function (_self)
30858 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30859 e.preventDefault();
30863 select : function (_self, oldvalue, newvalue)
30865 _this.setValue(_this.getValue());
30870 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30872 this.yearField = new Roo.bootstrap.ComboBox({
30873 allowBlank : this.yearAllowBlank,
30874 alwaysQuery : true,
30875 displayField : 'value',
30878 forceSelection : true,
30880 placeholder : this.yearPlaceholder,
30881 selectOnFocus : true,
30882 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30883 triggerAction : 'all',
30885 valueField : 'value',
30886 store : new Roo.data.SimpleStore({
30887 data : (function() {
30889 _this.fireEvent('years', _this, years);
30892 fields : [ 'value' ]
30895 select : function (_self, record, index)
30897 _this.setValue(_this.getValue());
30902 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30905 setValue : function(v, format)
30907 this.inputEl.dom.value = v;
30909 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30911 var d = Date.parseDate(v, f);
30918 this.setDay(d.format(this.dayFormat));
30919 this.setMonth(d.format(this.monthFormat));
30920 this.setYear(d.format(this.yearFormat));
30927 setDay : function(v)
30929 this.dayField.setValue(v);
30930 this.inputEl.dom.value = this.getValue();
30935 setMonth : function(v)
30937 this.monthField.setValue(v, true);
30938 this.inputEl.dom.value = this.getValue();
30943 setYear : function(v)
30945 this.yearField.setValue(v);
30946 this.inputEl.dom.value = this.getValue();
30951 getDay : function()
30953 return this.dayField.getValue();
30956 getMonth : function()
30958 return this.monthField.getValue();
30961 getYear : function()
30963 return this.yearField.getValue();
30966 getValue : function()
30968 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30970 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30980 this.inputEl.dom.value = '';
30985 validate : function()
30987 var d = this.dayField.validate();
30988 var m = this.monthField.validate();
30989 var y = this.yearField.validate();
30994 (!this.dayAllowBlank && !d) ||
30995 (!this.monthAllowBlank && !m) ||
30996 (!this.yearAllowBlank && !y)
31001 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31010 this.markInvalid();
31015 markValid : function()
31018 var label = this.el.select('label', true).first();
31019 var icon = this.el.select('i.fa-star', true).first();
31025 this.fireEvent('valid', this);
31029 * Mark this field as invalid
31030 * @param {String} msg The validation message
31032 markInvalid : function(msg)
31035 var label = this.el.select('label', true).first();
31036 var icon = this.el.select('i.fa-star', true).first();
31038 if(label && !icon){
31039 this.el.select('.roo-date-split-field-label', true).createChild({
31041 cls : 'text-danger fa fa-lg fa-star',
31042 tooltip : 'This field is required',
31043 style : 'margin-right:5px;'
31047 this.fireEvent('invalid', this, msg);
31050 clearInvalid : function()
31052 var label = this.el.select('label', true).first();
31053 var icon = this.el.select('i.fa-star', true).first();
31059 this.fireEvent('valid', this);
31062 getName: function()
31072 * http://masonry.desandro.com
31074 * The idea is to render all the bricks based on vertical width...
31076 * The original code extends 'outlayer' - we might need to use that....
31082 * @class Roo.bootstrap.LayoutMasonry
31083 * @extends Roo.bootstrap.Component
31084 * Bootstrap Layout Masonry class
31087 * Create a new Element
31088 * @param {Object} config The config object
31091 Roo.bootstrap.LayoutMasonry = function(config){
31093 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31097 Roo.bootstrap.LayoutMasonry.register(this);
31103 * Fire after layout the items
31104 * @param {Roo.bootstrap.LayoutMasonry} this
31105 * @param {Roo.EventObject} e
31112 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31115 * @cfg {Boolean} isLayoutInstant = no animation?
31117 isLayoutInstant : false, // needed?
31120 * @cfg {Number} boxWidth width of the columns
31125 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31130 * @cfg {Number} padWidth padding below box..
31135 * @cfg {Number} gutter gutter width..
31140 * @cfg {Number} maxCols maximum number of columns
31146 * @cfg {Boolean} isAutoInitial defalut true
31148 isAutoInitial : true,
31153 * @cfg {Boolean} isHorizontal defalut false
31155 isHorizontal : false,
31157 currentSize : null,
31163 bricks: null, //CompositeElement
31167 _isLayoutInited : false,
31169 // isAlternative : false, // only use for vertical layout...
31172 * @cfg {Number} alternativePadWidth padding below box..
31174 alternativePadWidth : 50,
31176 selectedBrick : [],
31178 getAutoCreate : function(){
31180 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31184 cls: 'blog-masonary-wrapper ' + this.cls,
31186 cls : 'mas-boxes masonary'
31193 getChildContainer: function( )
31195 if (this.boxesEl) {
31196 return this.boxesEl;
31199 this.boxesEl = this.el.select('.mas-boxes').first();
31201 return this.boxesEl;
31205 initEvents : function()
31209 if(this.isAutoInitial){
31210 Roo.log('hook children rendered');
31211 this.on('childrenrendered', function() {
31212 Roo.log('children rendered');
31218 initial : function()
31220 this.selectedBrick = [];
31222 this.currentSize = this.el.getBox(true);
31224 Roo.EventManager.onWindowResize(this.resize, this);
31226 if(!this.isAutoInitial){
31234 //this.layout.defer(500,this);
31238 resize : function()
31240 var cs = this.el.getBox(true);
31243 this.currentSize.width == cs.width &&
31244 this.currentSize.x == cs.x &&
31245 this.currentSize.height == cs.height &&
31246 this.currentSize.y == cs.y
31248 Roo.log("no change in with or X or Y");
31252 this.currentSize = cs;
31258 layout : function()
31260 this._resetLayout();
31262 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31264 this.layoutItems( isInstant );
31266 this._isLayoutInited = true;
31268 this.fireEvent('layout', this);
31272 _resetLayout : function()
31274 if(this.isHorizontal){
31275 this.horizontalMeasureColumns();
31279 this.verticalMeasureColumns();
31283 verticalMeasureColumns : function()
31285 this.getContainerWidth();
31287 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31288 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31292 var boxWidth = this.boxWidth + this.padWidth;
31294 if(this.containerWidth < this.boxWidth){
31295 boxWidth = this.containerWidth
31298 var containerWidth = this.containerWidth;
31300 var cols = Math.floor(containerWidth / boxWidth);
31302 this.cols = Math.max( cols, 1 );
31304 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31306 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31308 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31310 this.colWidth = boxWidth + avail - this.padWidth;
31312 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31313 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31316 horizontalMeasureColumns : function()
31318 this.getContainerWidth();
31320 var boxWidth = this.boxWidth;
31322 if(this.containerWidth < boxWidth){
31323 boxWidth = this.containerWidth;
31326 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31328 this.el.setHeight(boxWidth);
31332 getContainerWidth : function()
31334 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31337 layoutItems : function( isInstant )
31339 Roo.log(this.bricks);
31341 var items = Roo.apply([], this.bricks);
31343 if(this.isHorizontal){
31344 this._horizontalLayoutItems( items , isInstant );
31348 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31349 // this._verticalAlternativeLayoutItems( items , isInstant );
31353 this._verticalLayoutItems( items , isInstant );
31357 _verticalLayoutItems : function ( items , isInstant)
31359 if ( !items || !items.length ) {
31364 ['xs', 'xs', 'xs', 'tall'],
31365 ['xs', 'xs', 'tall'],
31366 ['xs', 'xs', 'sm'],
31367 ['xs', 'xs', 'xs'],
31373 ['sm', 'xs', 'xs'],
31377 ['tall', 'xs', 'xs', 'xs'],
31378 ['tall', 'xs', 'xs'],
31390 Roo.each(items, function(item, k){
31392 switch (item.size) {
31393 // these layouts take up a full box,
31404 boxes.push([item]);
31427 var filterPattern = function(box, length)
31435 var pattern = box.slice(0, length);
31439 Roo.each(pattern, function(i){
31440 format.push(i.size);
31443 Roo.each(standard, function(s){
31445 if(String(s) != String(format)){
31454 if(!match && length == 1){
31459 filterPattern(box, length - 1);
31463 queue.push(pattern);
31465 box = box.slice(length, box.length);
31467 filterPattern(box, 4);
31473 Roo.each(boxes, function(box, k){
31479 if(box.length == 1){
31484 filterPattern(box, 4);
31488 this._processVerticalLayoutQueue( queue, isInstant );
31492 // _verticalAlternativeLayoutItems : function( items , isInstant )
31494 // if ( !items || !items.length ) {
31498 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31502 _horizontalLayoutItems : function ( items , isInstant)
31504 if ( !items || !items.length || items.length < 3) {
31510 var eItems = items.slice(0, 3);
31512 items = items.slice(3, items.length);
31515 ['xs', 'xs', 'xs', 'wide'],
31516 ['xs', 'xs', 'wide'],
31517 ['xs', 'xs', 'sm'],
31518 ['xs', 'xs', 'xs'],
31524 ['sm', 'xs', 'xs'],
31528 ['wide', 'xs', 'xs', 'xs'],
31529 ['wide', 'xs', 'xs'],
31542 Roo.each(items, function(item, k){
31544 switch (item.size) {
31555 boxes.push([item]);
31579 var filterPattern = function(box, length)
31587 var pattern = box.slice(0, length);
31591 Roo.each(pattern, function(i){
31592 format.push(i.size);
31595 Roo.each(standard, function(s){
31597 if(String(s) != String(format)){
31606 if(!match && length == 1){
31611 filterPattern(box, length - 1);
31615 queue.push(pattern);
31617 box = box.slice(length, box.length);
31619 filterPattern(box, 4);
31625 Roo.each(boxes, function(box, k){
31631 if(box.length == 1){
31636 filterPattern(box, 4);
31643 var pos = this.el.getBox(true);
31647 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31649 var hit_end = false;
31651 Roo.each(queue, function(box){
31655 Roo.each(box, function(b){
31657 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31667 Roo.each(box, function(b){
31669 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31672 mx = Math.max(mx, b.x);
31676 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31680 Roo.each(box, function(b){
31682 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31696 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31699 /** Sets position of item in DOM
31700 * @param {Element} item
31701 * @param {Number} x - horizontal position
31702 * @param {Number} y - vertical position
31703 * @param {Boolean} isInstant - disables transitions
31705 _processVerticalLayoutQueue : function( queue, isInstant )
31707 var pos = this.el.getBox(true);
31712 for (var i = 0; i < this.cols; i++){
31716 Roo.each(queue, function(box, k){
31718 var col = k % this.cols;
31720 Roo.each(box, function(b,kk){
31722 b.el.position('absolute');
31724 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31725 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31727 if(b.size == 'md-left' || b.size == 'md-right'){
31728 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31729 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31732 b.el.setWidth(width);
31733 b.el.setHeight(height);
31735 b.el.select('iframe',true).setSize(width,height);
31739 for (var i = 0; i < this.cols; i++){
31741 if(maxY[i] < maxY[col]){
31746 col = Math.min(col, i);
31750 x = pos.x + col * (this.colWidth + this.padWidth);
31754 var positions = [];
31756 switch (box.length){
31758 positions = this.getVerticalOneBoxColPositions(x, y, box);
31761 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31764 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31767 positions = this.getVerticalFourBoxColPositions(x, y, box);
31773 Roo.each(box, function(b,kk){
31775 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31777 var sz = b.el.getSize();
31779 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31787 for (var i = 0; i < this.cols; i++){
31788 mY = Math.max(mY, maxY[i]);
31791 this.el.setHeight(mY - pos.y);
31795 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31797 // var pos = this.el.getBox(true);
31800 // var maxX = pos.right;
31802 // var maxHeight = 0;
31804 // Roo.each(items, function(item, k){
31808 // item.el.position('absolute');
31810 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31812 // item.el.setWidth(width);
31814 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31816 // item.el.setHeight(height);
31819 // item.el.setXY([x, y], isInstant ? false : true);
31821 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31824 // y = y + height + this.alternativePadWidth;
31826 // maxHeight = maxHeight + height + this.alternativePadWidth;
31830 // this.el.setHeight(maxHeight);
31834 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31836 var pos = this.el.getBox(true);
31841 var maxX = pos.right;
31843 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31845 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31847 Roo.each(queue, function(box, k){
31849 Roo.each(box, function(b, kk){
31851 b.el.position('absolute');
31853 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31854 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31856 if(b.size == 'md-left' || b.size == 'md-right'){
31857 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31858 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31861 b.el.setWidth(width);
31862 b.el.setHeight(height);
31870 var positions = [];
31872 switch (box.length){
31874 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31877 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31880 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31883 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31889 Roo.each(box, function(b,kk){
31891 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31893 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31901 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31903 Roo.each(eItems, function(b,k){
31905 b.size = (k == 0) ? 'sm' : 'xs';
31906 b.x = (k == 0) ? 2 : 1;
31907 b.y = (k == 0) ? 2 : 1;
31909 b.el.position('absolute');
31911 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31913 b.el.setWidth(width);
31915 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31917 b.el.setHeight(height);
31921 var positions = [];
31924 x : maxX - this.unitWidth * 2 - this.gutter,
31929 x : maxX - this.unitWidth,
31930 y : minY + (this.unitWidth + this.gutter) * 2
31934 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31938 Roo.each(eItems, function(b,k){
31940 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31946 getVerticalOneBoxColPositions : function(x, y, box)
31950 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31952 if(box[0].size == 'md-left'){
31956 if(box[0].size == 'md-right'){
31961 x : x + (this.unitWidth + this.gutter) * rand,
31968 getVerticalTwoBoxColPositions : function(x, y, box)
31972 if(box[0].size == 'xs'){
31976 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31980 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31994 x : x + (this.unitWidth + this.gutter) * 2,
31995 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32002 getVerticalThreeBoxColPositions : function(x, y, box)
32006 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32014 x : x + (this.unitWidth + this.gutter) * 1,
32019 x : x + (this.unitWidth + this.gutter) * 2,
32027 if(box[0].size == 'xs' && box[1].size == 'xs'){
32036 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32040 x : x + (this.unitWidth + this.gutter) * 1,
32054 x : x + (this.unitWidth + this.gutter) * 2,
32059 x : x + (this.unitWidth + this.gutter) * 2,
32060 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32067 getVerticalFourBoxColPositions : function(x, y, box)
32071 if(box[0].size == 'xs'){
32080 y : y + (this.unitHeight + this.gutter) * 1
32085 y : y + (this.unitHeight + this.gutter) * 2
32089 x : x + (this.unitWidth + this.gutter) * 1,
32103 x : x + (this.unitWidth + this.gutter) * 2,
32108 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32109 y : y + (this.unitHeight + this.gutter) * 1
32113 x : x + (this.unitWidth + this.gutter) * 2,
32114 y : y + (this.unitWidth + this.gutter) * 2
32121 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32125 if(box[0].size == 'md-left'){
32127 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32134 if(box[0].size == 'md-right'){
32136 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32137 y : minY + (this.unitWidth + this.gutter) * 1
32143 var rand = Math.floor(Math.random() * (4 - box[0].y));
32146 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32147 y : minY + (this.unitWidth + this.gutter) * rand
32154 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32158 if(box[0].size == 'xs'){
32161 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32166 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32167 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32175 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32180 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32181 y : minY + (this.unitWidth + this.gutter) * 2
32188 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32192 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32195 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32200 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32201 y : minY + (this.unitWidth + this.gutter) * 1
32205 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32206 y : minY + (this.unitWidth + this.gutter) * 2
32213 if(box[0].size == 'xs' && box[1].size == 'xs'){
32216 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32221 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32226 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32227 y : minY + (this.unitWidth + this.gutter) * 1
32235 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32240 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32241 y : minY + (this.unitWidth + this.gutter) * 2
32245 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32246 y : minY + (this.unitWidth + this.gutter) * 2
32253 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32257 if(box[0].size == 'xs'){
32260 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32265 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32270 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),
32275 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32276 y : minY + (this.unitWidth + this.gutter) * 1
32284 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32289 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32290 y : minY + (this.unitWidth + this.gutter) * 2
32294 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32295 y : minY + (this.unitWidth + this.gutter) * 2
32299 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),
32300 y : minY + (this.unitWidth + this.gutter) * 2
32308 * remove a Masonry Brick
32309 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32311 removeBrick : function(brick_id)
32317 for (var i = 0; i<this.bricks.length; i++) {
32318 if (this.bricks[i].id == brick_id) {
32319 this.bricks.splice(i,1);
32320 this.el.dom.removeChild(Roo.get(brick_id).dom);
32327 * adds a Masonry Brick
32328 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32330 addBrick : function(cfg)
32332 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32333 //this.register(cn);
32334 cn.parentId = this.id;
32335 cn.render(this.el);
32340 * register a Masonry Brick
32341 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32344 register : function(brick)
32346 this.bricks.push(brick);
32347 brick.masonryId = this.id;
32351 * clear all the Masonry Brick
32353 clearAll : function()
32356 //this.getChildContainer().dom.innerHTML = "";
32357 this.el.dom.innerHTML = '';
32360 getSelected : function()
32362 if (!this.selectedBrick) {
32366 return this.selectedBrick;
32370 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32374 * register a Masonry Layout
32375 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32378 register : function(layout)
32380 this.groups[layout.id] = layout;
32383 * fetch a Masonry Layout based on the masonry layout ID
32384 * @param {string} the masonry layout to add
32385 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32388 get: function(layout_id) {
32389 if (typeof(this.groups[layout_id]) == 'undefined') {
32392 return this.groups[layout_id] ;
32404 * http://masonry.desandro.com
32406 * The idea is to render all the bricks based on vertical width...
32408 * The original code extends 'outlayer' - we might need to use that....
32414 * @class Roo.bootstrap.LayoutMasonryAuto
32415 * @extends Roo.bootstrap.Component
32416 * Bootstrap Layout Masonry class
32419 * Create a new Element
32420 * @param {Object} config The config object
32423 Roo.bootstrap.LayoutMasonryAuto = function(config){
32424 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32427 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32430 * @cfg {Boolean} isFitWidth - resize the width..
32432 isFitWidth : false, // options..
32434 * @cfg {Boolean} isOriginLeft = left align?
32436 isOriginLeft : true,
32438 * @cfg {Boolean} isOriginTop = top align?
32440 isOriginTop : false,
32442 * @cfg {Boolean} isLayoutInstant = no animation?
32444 isLayoutInstant : false, // needed?
32446 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32448 isResizingContainer : true,
32450 * @cfg {Number} columnWidth width of the columns
32456 * @cfg {Number} maxCols maximum number of columns
32461 * @cfg {Number} padHeight padding below box..
32467 * @cfg {Boolean} isAutoInitial defalut true
32470 isAutoInitial : true,
32476 initialColumnWidth : 0,
32477 currentSize : null,
32479 colYs : null, // array.
32486 bricks: null, //CompositeElement
32487 cols : 0, // array?
32488 // element : null, // wrapped now this.el
32489 _isLayoutInited : null,
32492 getAutoCreate : function(){
32496 cls: 'blog-masonary-wrapper ' + this.cls,
32498 cls : 'mas-boxes masonary'
32505 getChildContainer: function( )
32507 if (this.boxesEl) {
32508 return this.boxesEl;
32511 this.boxesEl = this.el.select('.mas-boxes').first();
32513 return this.boxesEl;
32517 initEvents : function()
32521 if(this.isAutoInitial){
32522 Roo.log('hook children rendered');
32523 this.on('childrenrendered', function() {
32524 Roo.log('children rendered');
32531 initial : function()
32533 this.reloadItems();
32535 this.currentSize = this.el.getBox(true);
32537 /// was window resize... - let's see if this works..
32538 Roo.EventManager.onWindowResize(this.resize, this);
32540 if(!this.isAutoInitial){
32545 this.layout.defer(500,this);
32548 reloadItems: function()
32550 this.bricks = this.el.select('.masonry-brick', true);
32552 this.bricks.each(function(b) {
32553 //Roo.log(b.getSize());
32554 if (!b.attr('originalwidth')) {
32555 b.attr('originalwidth', b.getSize().width);
32560 Roo.log(this.bricks.elements.length);
32563 resize : function()
32566 var cs = this.el.getBox(true);
32568 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32569 Roo.log("no change in with or X");
32572 this.currentSize = cs;
32576 layout : function()
32579 this._resetLayout();
32580 //this._manageStamps();
32582 // don't animate first layout
32583 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32584 this.layoutItems( isInstant );
32586 // flag for initalized
32587 this._isLayoutInited = true;
32590 layoutItems : function( isInstant )
32592 //var items = this._getItemsForLayout( this.items );
32593 // original code supports filtering layout items.. we just ignore it..
32595 this._layoutItems( this.bricks , isInstant );
32597 this._postLayout();
32599 _layoutItems : function ( items , isInstant)
32601 //this.fireEvent( 'layout', this, items );
32604 if ( !items || !items.elements.length ) {
32605 // no items, emit event with empty array
32610 items.each(function(item) {
32611 Roo.log("layout item");
32613 // get x/y object from method
32614 var position = this._getItemLayoutPosition( item );
32616 position.item = item;
32617 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32618 queue.push( position );
32621 this._processLayoutQueue( queue );
32623 /** Sets position of item in DOM
32624 * @param {Element} item
32625 * @param {Number} x - horizontal position
32626 * @param {Number} y - vertical position
32627 * @param {Boolean} isInstant - disables transitions
32629 _processLayoutQueue : function( queue )
32631 for ( var i=0, len = queue.length; i < len; i++ ) {
32632 var obj = queue[i];
32633 obj.item.position('absolute');
32634 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32640 * Any logic you want to do after each layout,
32641 * i.e. size the container
32643 _postLayout : function()
32645 this.resizeContainer();
32648 resizeContainer : function()
32650 if ( !this.isResizingContainer ) {
32653 var size = this._getContainerSize();
32655 this.el.setSize(size.width,size.height);
32656 this.boxesEl.setSize(size.width,size.height);
32662 _resetLayout : function()
32664 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32665 this.colWidth = this.el.getWidth();
32666 //this.gutter = this.el.getWidth();
32668 this.measureColumns();
32674 this.colYs.push( 0 );
32680 measureColumns : function()
32682 this.getContainerWidth();
32683 // if columnWidth is 0, default to outerWidth of first item
32684 if ( !this.columnWidth ) {
32685 var firstItem = this.bricks.first();
32686 Roo.log(firstItem);
32687 this.columnWidth = this.containerWidth;
32688 if (firstItem && firstItem.attr('originalwidth') ) {
32689 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32691 // columnWidth fall back to item of first element
32692 Roo.log("set column width?");
32693 this.initialColumnWidth = this.columnWidth ;
32695 // if first elem has no width, default to size of container
32700 if (this.initialColumnWidth) {
32701 this.columnWidth = this.initialColumnWidth;
32706 // column width is fixed at the top - however if container width get's smaller we should
32709 // this bit calcs how man columns..
32711 var columnWidth = this.columnWidth += this.gutter;
32713 // calculate columns
32714 var containerWidth = this.containerWidth + this.gutter;
32716 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32717 // fix rounding errors, typically with gutters
32718 var excess = columnWidth - containerWidth % columnWidth;
32721 // if overshoot is less than a pixel, round up, otherwise floor it
32722 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32723 cols = Math[ mathMethod ]( cols );
32724 this.cols = Math.max( cols, 1 );
32725 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32727 // padding positioning..
32728 var totalColWidth = this.cols * this.columnWidth;
32729 var padavail = this.containerWidth - totalColWidth;
32730 // so for 2 columns - we need 3 'pads'
32732 var padNeeded = (1+this.cols) * this.padWidth;
32734 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32736 this.columnWidth += padExtra
32737 //this.padWidth = Math.floor(padavail / ( this.cols));
32739 // adjust colum width so that padding is fixed??
32741 // we have 3 columns ... total = width * 3
32742 // we have X left over... that should be used by
32744 //if (this.expandC) {
32752 getContainerWidth : function()
32754 /* // container is parent if fit width
32755 var container = this.isFitWidth ? this.element.parentNode : this.element;
32756 // check that this.size and size are there
32757 // IE8 triggers resize on body size change, so they might not be
32759 var size = getSize( container ); //FIXME
32760 this.containerWidth = size && size.innerWidth; //FIXME
32763 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32767 _getItemLayoutPosition : function( item ) // what is item?
32769 // we resize the item to our columnWidth..
32771 item.setWidth(this.columnWidth);
32772 item.autoBoxAdjust = false;
32774 var sz = item.getSize();
32776 // how many columns does this brick span
32777 var remainder = this.containerWidth % this.columnWidth;
32779 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32780 // round if off by 1 pixel, otherwise use ceil
32781 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32782 colSpan = Math.min( colSpan, this.cols );
32784 // normally this should be '1' as we dont' currently allow multi width columns..
32786 var colGroup = this._getColGroup( colSpan );
32787 // get the minimum Y value from the columns
32788 var minimumY = Math.min.apply( Math, colGroup );
32789 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32791 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32793 // position the brick
32795 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32796 y: this.currentSize.y + minimumY + this.padHeight
32800 // apply setHeight to necessary columns
32801 var setHeight = minimumY + sz.height + this.padHeight;
32802 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32804 var setSpan = this.cols + 1 - colGroup.length;
32805 for ( var i = 0; i < setSpan; i++ ) {
32806 this.colYs[ shortColIndex + i ] = setHeight ;
32813 * @param {Number} colSpan - number of columns the element spans
32814 * @returns {Array} colGroup
32816 _getColGroup : function( colSpan )
32818 if ( colSpan < 2 ) {
32819 // if brick spans only one column, use all the column Ys
32824 // how many different places could this brick fit horizontally
32825 var groupCount = this.cols + 1 - colSpan;
32826 // for each group potential horizontal position
32827 for ( var i = 0; i < groupCount; i++ ) {
32828 // make an array of colY values for that one group
32829 var groupColYs = this.colYs.slice( i, i + colSpan );
32830 // and get the max value of the array
32831 colGroup[i] = Math.max.apply( Math, groupColYs );
32836 _manageStamp : function( stamp )
32838 var stampSize = stamp.getSize();
32839 var offset = stamp.getBox();
32840 // get the columns that this stamp affects
32841 var firstX = this.isOriginLeft ? offset.x : offset.right;
32842 var lastX = firstX + stampSize.width;
32843 var firstCol = Math.floor( firstX / this.columnWidth );
32844 firstCol = Math.max( 0, firstCol );
32846 var lastCol = Math.floor( lastX / this.columnWidth );
32847 // lastCol should not go over if multiple of columnWidth #425
32848 lastCol -= lastX % this.columnWidth ? 0 : 1;
32849 lastCol = Math.min( this.cols - 1, lastCol );
32851 // set colYs to bottom of the stamp
32852 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32855 for ( var i = firstCol; i <= lastCol; i++ ) {
32856 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32861 _getContainerSize : function()
32863 this.maxY = Math.max.apply( Math, this.colYs );
32868 if ( this.isFitWidth ) {
32869 size.width = this._getContainerFitWidth();
32875 _getContainerFitWidth : function()
32877 var unusedCols = 0;
32878 // count unused columns
32881 if ( this.colYs[i] !== 0 ) {
32886 // fit container to columns that have been used
32887 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32890 needsResizeLayout : function()
32892 var previousWidth = this.containerWidth;
32893 this.getContainerWidth();
32894 return previousWidth !== this.containerWidth;
32909 * @class Roo.bootstrap.MasonryBrick
32910 * @extends Roo.bootstrap.Component
32911 * Bootstrap MasonryBrick class
32914 * Create a new MasonryBrick
32915 * @param {Object} config The config object
32918 Roo.bootstrap.MasonryBrick = function(config){
32920 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32922 Roo.bootstrap.MasonryBrick.register(this);
32928 * When a MasonryBrick is clcik
32929 * @param {Roo.bootstrap.MasonryBrick} this
32930 * @param {Roo.EventObject} e
32936 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32939 * @cfg {String} title
32943 * @cfg {String} html
32947 * @cfg {String} bgimage
32951 * @cfg {String} videourl
32955 * @cfg {String} cls
32959 * @cfg {String} href
32963 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32968 * @cfg {String} placetitle (center|bottom)
32973 * @cfg {Boolean} isFitContainer defalut true
32975 isFitContainer : true,
32978 * @cfg {Boolean} preventDefault defalut false
32980 preventDefault : false,
32983 * @cfg {Boolean} inverse defalut false
32985 maskInverse : false,
32987 getAutoCreate : function()
32989 if(!this.isFitContainer){
32990 return this.getSplitAutoCreate();
32993 var cls = 'masonry-brick masonry-brick-full';
32995 if(this.href.length){
32996 cls += ' masonry-brick-link';
32999 if(this.bgimage.length){
33000 cls += ' masonry-brick-image';
33003 if(this.maskInverse){
33004 cls += ' mask-inverse';
33007 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33008 cls += ' enable-mask';
33012 cls += ' masonry-' + this.size + '-brick';
33015 if(this.placetitle.length){
33017 switch (this.placetitle) {
33019 cls += ' masonry-center-title';
33022 cls += ' masonry-bottom-title';
33029 if(!this.html.length && !this.bgimage.length){
33030 cls += ' masonry-center-title';
33033 if(!this.html.length && this.bgimage.length){
33034 cls += ' masonry-bottom-title';
33039 cls += ' ' + this.cls;
33043 tag: (this.href.length) ? 'a' : 'div',
33048 cls: 'masonry-brick-mask'
33052 cls: 'masonry-brick-paragraph',
33058 if(this.href.length){
33059 cfg.href = this.href;
33062 var cn = cfg.cn[1].cn;
33064 if(this.title.length){
33067 cls: 'masonry-brick-title',
33072 if(this.html.length){
33075 cls: 'masonry-brick-text',
33080 if (!this.title.length && !this.html.length) {
33081 cfg.cn[1].cls += ' hide';
33084 if(this.bgimage.length){
33087 cls: 'masonry-brick-image-view',
33092 if(this.videourl.length){
33093 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33094 // youtube support only?
33097 cls: 'masonry-brick-image-view',
33100 allowfullscreen : true
33108 getSplitAutoCreate : function()
33110 var cls = 'masonry-brick masonry-brick-split';
33112 if(this.href.length){
33113 cls += ' masonry-brick-link';
33116 if(this.bgimage.length){
33117 cls += ' masonry-brick-image';
33121 cls += ' masonry-' + this.size + '-brick';
33124 switch (this.placetitle) {
33126 cls += ' masonry-center-title';
33129 cls += ' masonry-bottom-title';
33132 if(!this.bgimage.length){
33133 cls += ' masonry-center-title';
33136 if(this.bgimage.length){
33137 cls += ' masonry-bottom-title';
33143 cls += ' ' + this.cls;
33147 tag: (this.href.length) ? 'a' : 'div',
33152 cls: 'masonry-brick-split-head',
33156 cls: 'masonry-brick-paragraph',
33163 cls: 'masonry-brick-split-body',
33169 if(this.href.length){
33170 cfg.href = this.href;
33173 if(this.title.length){
33174 cfg.cn[0].cn[0].cn.push({
33176 cls: 'masonry-brick-title',
33181 if(this.html.length){
33182 cfg.cn[1].cn.push({
33184 cls: 'masonry-brick-text',
33189 if(this.bgimage.length){
33190 cfg.cn[0].cn.push({
33192 cls: 'masonry-brick-image-view',
33197 if(this.videourl.length){
33198 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33199 // youtube support only?
33200 cfg.cn[0].cn.cn.push({
33202 cls: 'masonry-brick-image-view',
33205 allowfullscreen : true
33212 initEvents: function()
33214 switch (this.size) {
33247 this.el.on('touchstart', this.onTouchStart, this);
33248 this.el.on('touchmove', this.onTouchMove, this);
33249 this.el.on('touchend', this.onTouchEnd, this);
33250 this.el.on('contextmenu', this.onContextMenu, this);
33252 this.el.on('mouseenter' ,this.enter, this);
33253 this.el.on('mouseleave', this.leave, this);
33254 this.el.on('click', this.onClick, this);
33257 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33258 this.parent().bricks.push(this);
33263 onClick: function(e, el)
33265 var time = this.endTimer - this.startTimer;
33266 // Roo.log(e.preventDefault());
33269 e.preventDefault();
33274 if(!this.preventDefault){
33278 e.preventDefault();
33280 if (this.activeClass != '') {
33281 this.selectBrick();
33284 this.fireEvent('click', this, e);
33287 enter: function(e, el)
33289 e.preventDefault();
33291 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33295 if(this.bgimage.length && this.html.length){
33296 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33300 leave: function(e, el)
33302 e.preventDefault();
33304 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33308 if(this.bgimage.length && this.html.length){
33309 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33313 onTouchStart: function(e, el)
33315 // e.preventDefault();
33317 this.touchmoved = false;
33319 if(!this.isFitContainer){
33323 if(!this.bgimage.length || !this.html.length){
33327 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33329 this.timer = new Date().getTime();
33333 onTouchMove: function(e, el)
33335 this.touchmoved = true;
33338 onContextMenu : function(e,el)
33340 e.preventDefault();
33341 e.stopPropagation();
33345 onTouchEnd: function(e, el)
33347 // e.preventDefault();
33349 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33356 if(!this.bgimage.length || !this.html.length){
33358 if(this.href.length){
33359 window.location.href = this.href;
33365 if(!this.isFitContainer){
33369 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33371 window.location.href = this.href;
33374 //selection on single brick only
33375 selectBrick : function() {
33377 if (!this.parentId) {
33381 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33382 var index = m.selectedBrick.indexOf(this.id);
33385 m.selectedBrick.splice(index,1);
33386 this.el.removeClass(this.activeClass);
33390 for(var i = 0; i < m.selectedBrick.length; i++) {
33391 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33392 b.el.removeClass(b.activeClass);
33395 m.selectedBrick = [];
33397 m.selectedBrick.push(this.id);
33398 this.el.addClass(this.activeClass);
33402 isSelected : function(){
33403 return this.el.hasClass(this.activeClass);
33408 Roo.apply(Roo.bootstrap.MasonryBrick, {
33411 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33413 * register a Masonry Brick
33414 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33417 register : function(brick)
33419 //this.groups[brick.id] = brick;
33420 this.groups.add(brick.id, brick);
33423 * fetch a masonry brick based on the masonry brick ID
33424 * @param {string} the masonry brick to add
33425 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33428 get: function(brick_id)
33430 // if (typeof(this.groups[brick_id]) == 'undefined') {
33433 // return this.groups[brick_id] ;
33435 if(this.groups.key(brick_id)) {
33436 return this.groups.key(brick_id);
33454 * @class Roo.bootstrap.Brick
33455 * @extends Roo.bootstrap.Component
33456 * Bootstrap Brick class
33459 * Create a new Brick
33460 * @param {Object} config The config object
33463 Roo.bootstrap.Brick = function(config){
33464 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33470 * When a Brick is click
33471 * @param {Roo.bootstrap.Brick} this
33472 * @param {Roo.EventObject} e
33478 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33481 * @cfg {String} title
33485 * @cfg {String} html
33489 * @cfg {String} bgimage
33493 * @cfg {String} cls
33497 * @cfg {String} href
33501 * @cfg {String} video
33505 * @cfg {Boolean} square
33509 getAutoCreate : function()
33511 var cls = 'roo-brick';
33513 if(this.href.length){
33514 cls += ' roo-brick-link';
33517 if(this.bgimage.length){
33518 cls += ' roo-brick-image';
33521 if(!this.html.length && !this.bgimage.length){
33522 cls += ' roo-brick-center-title';
33525 if(!this.html.length && this.bgimage.length){
33526 cls += ' roo-brick-bottom-title';
33530 cls += ' ' + this.cls;
33534 tag: (this.href.length) ? 'a' : 'div',
33539 cls: 'roo-brick-paragraph',
33545 if(this.href.length){
33546 cfg.href = this.href;
33549 var cn = cfg.cn[0].cn;
33551 if(this.title.length){
33554 cls: 'roo-brick-title',
33559 if(this.html.length){
33562 cls: 'roo-brick-text',
33569 if(this.bgimage.length){
33572 cls: 'roo-brick-image-view',
33580 initEvents: function()
33582 if(this.title.length || this.html.length){
33583 this.el.on('mouseenter' ,this.enter, this);
33584 this.el.on('mouseleave', this.leave, this);
33587 Roo.EventManager.onWindowResize(this.resize, this);
33589 if(this.bgimage.length){
33590 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33591 this.imageEl.on('load', this.onImageLoad, this);
33598 onImageLoad : function()
33603 resize : function()
33605 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33607 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33609 if(this.bgimage.length){
33610 var image = this.el.select('.roo-brick-image-view', true).first();
33612 image.setWidth(paragraph.getWidth());
33615 image.setHeight(paragraph.getWidth());
33618 this.el.setHeight(image.getHeight());
33619 paragraph.setHeight(image.getHeight());
33625 enter: function(e, el)
33627 e.preventDefault();
33629 if(this.bgimage.length){
33630 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33631 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33635 leave: function(e, el)
33637 e.preventDefault();
33639 if(this.bgimage.length){
33640 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33641 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33656 * @class Roo.bootstrap.NumberField
33657 * @extends Roo.bootstrap.Input
33658 * Bootstrap NumberField class
33664 * Create a new NumberField
33665 * @param {Object} config The config object
33668 Roo.bootstrap.NumberField = function(config){
33669 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33672 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33675 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33677 allowDecimals : true,
33679 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33681 decimalSeparator : ".",
33683 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33685 decimalPrecision : 2,
33687 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33689 allowNegative : true,
33692 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33696 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33698 minValue : Number.NEGATIVE_INFINITY,
33700 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33702 maxValue : Number.MAX_VALUE,
33704 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33706 minText : "The minimum value for this field is {0}",
33708 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33710 maxText : "The maximum value for this field is {0}",
33712 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33713 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33715 nanText : "{0} is not a valid number",
33717 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33719 thousandsDelimiter : false,
33721 * @cfg {String} valueAlign alignment of value
33723 valueAlign : "left",
33725 getAutoCreate : function()
33727 var hiddenInput = {
33731 cls: 'hidden-number-input'
33735 hiddenInput.name = this.name;
33740 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33742 this.name = hiddenInput.name;
33744 if(cfg.cn.length > 0) {
33745 cfg.cn.push(hiddenInput);
33752 initEvents : function()
33754 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33756 var allowed = "0123456789";
33758 if(this.allowDecimals){
33759 allowed += this.decimalSeparator;
33762 if(this.allowNegative){
33766 if(this.thousandsDelimiter) {
33770 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33772 var keyPress = function(e){
33774 var k = e.getKey();
33776 var c = e.getCharCode();
33779 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33780 allowed.indexOf(String.fromCharCode(c)) === -1
33786 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33790 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33795 this.el.on("keypress", keyPress, this);
33798 validateValue : function(value)
33801 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33805 var num = this.parseValue(value);
33808 this.markInvalid(String.format(this.nanText, value));
33812 if(num < this.minValue){
33813 this.markInvalid(String.format(this.minText, this.minValue));
33817 if(num > this.maxValue){
33818 this.markInvalid(String.format(this.maxText, this.maxValue));
33825 getValue : function()
33827 var v = this.hiddenEl().getValue();
33829 return this.fixPrecision(this.parseValue(v));
33832 parseValue : function(value)
33834 if(this.thousandsDelimiter) {
33836 r = new RegExp(",", "g");
33837 value = value.replace(r, "");
33840 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33841 return isNaN(value) ? '' : value;
33844 fixPrecision : function(value)
33846 if(this.thousandsDelimiter) {
33848 r = new RegExp(",", "g");
33849 value = value.replace(r, "");
33852 var nan = isNaN(value);
33854 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33855 return nan ? '' : value;
33857 return parseFloat(value).toFixed(this.decimalPrecision);
33860 setValue : function(v)
33862 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33868 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33870 this.inputEl().dom.value = (v == '') ? '' :
33871 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33873 if(!this.allowZero && v === '0') {
33874 this.hiddenEl().dom.value = '';
33875 this.inputEl().dom.value = '';
33882 decimalPrecisionFcn : function(v)
33884 return Math.floor(v);
33887 beforeBlur : function()
33889 var v = this.parseValue(this.getRawValue());
33891 if(v || v === 0 || v === ''){
33896 hiddenEl : function()
33898 return this.el.select('input.hidden-number-input',true).first();
33910 * @class Roo.bootstrap.DocumentSlider
33911 * @extends Roo.bootstrap.Component
33912 * Bootstrap DocumentSlider class
33915 * Create a new DocumentViewer
33916 * @param {Object} config The config object
33919 Roo.bootstrap.DocumentSlider = function(config){
33920 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33927 * Fire after initEvent
33928 * @param {Roo.bootstrap.DocumentSlider} this
33933 * Fire after update
33934 * @param {Roo.bootstrap.DocumentSlider} this
33940 * @param {Roo.bootstrap.DocumentSlider} this
33946 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33952 getAutoCreate : function()
33956 cls : 'roo-document-slider',
33960 cls : 'roo-document-slider-header',
33964 cls : 'roo-document-slider-header-title'
33970 cls : 'roo-document-slider-body',
33974 cls : 'roo-document-slider-prev',
33978 cls : 'fa fa-chevron-left'
33984 cls : 'roo-document-slider-thumb',
33988 cls : 'roo-document-slider-image'
33994 cls : 'roo-document-slider-next',
33998 cls : 'fa fa-chevron-right'
34010 initEvents : function()
34012 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34013 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34015 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34016 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34018 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34019 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34021 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34022 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34024 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34025 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34027 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34028 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34030 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34031 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34033 this.thumbEl.on('click', this.onClick, this);
34035 this.prevIndicator.on('click', this.prev, this);
34037 this.nextIndicator.on('click', this.next, this);
34041 initial : function()
34043 if(this.files.length){
34044 this.indicator = 1;
34048 this.fireEvent('initial', this);
34051 update : function()
34053 this.imageEl.attr('src', this.files[this.indicator - 1]);
34055 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34057 this.prevIndicator.show();
34059 if(this.indicator == 1){
34060 this.prevIndicator.hide();
34063 this.nextIndicator.show();
34065 if(this.indicator == this.files.length){
34066 this.nextIndicator.hide();
34069 this.thumbEl.scrollTo('top');
34071 this.fireEvent('update', this);
34074 onClick : function(e)
34076 e.preventDefault();
34078 this.fireEvent('click', this);
34083 e.preventDefault();
34085 this.indicator = Math.max(1, this.indicator - 1);
34092 e.preventDefault();
34094 this.indicator = Math.min(this.files.length, this.indicator + 1);
34108 * @class Roo.bootstrap.RadioSet
34109 * @extends Roo.bootstrap.Input
34110 * Bootstrap RadioSet class
34111 * @cfg {String} indicatorpos (left|right) default left
34112 * @cfg {Boolean} inline (true|false) inline the element (default true)
34113 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34115 * Create a new RadioSet
34116 * @param {Object} config The config object
34119 Roo.bootstrap.RadioSet = function(config){
34121 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34125 Roo.bootstrap.RadioSet.register(this);
34130 * Fires when the element is checked or unchecked.
34131 * @param {Roo.bootstrap.RadioSet} this This radio
34132 * @param {Roo.bootstrap.Radio} item The checked item
34137 * Fires when the element is click.
34138 * @param {Roo.bootstrap.RadioSet} this This radio set
34139 * @param {Roo.bootstrap.Radio} item The checked item
34140 * @param {Roo.EventObject} e The event object
34147 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34155 indicatorpos : 'left',
34157 getAutoCreate : function()
34161 cls : 'roo-radio-set-label',
34165 html : this.fieldLabel
34169 if (Roo.bootstrap.version == 3) {
34172 if(this.indicatorpos == 'left'){
34175 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34176 tooltip : 'This field is required'
34181 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34182 tooltip : 'This field is required'
34188 cls : 'roo-radio-set-items'
34191 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34193 if (align === 'left' && this.fieldLabel.length) {
34196 cls : "roo-radio-set-right",
34202 if(this.labelWidth > 12){
34203 label.style = "width: " + this.labelWidth + 'px';
34206 if(this.labelWidth < 13 && this.labelmd == 0){
34207 this.labelmd = this.labelWidth;
34210 if(this.labellg > 0){
34211 label.cls += ' col-lg-' + this.labellg;
34212 items.cls += ' col-lg-' + (12 - this.labellg);
34215 if(this.labelmd > 0){
34216 label.cls += ' col-md-' + this.labelmd;
34217 items.cls += ' col-md-' + (12 - this.labelmd);
34220 if(this.labelsm > 0){
34221 label.cls += ' col-sm-' + this.labelsm;
34222 items.cls += ' col-sm-' + (12 - this.labelsm);
34225 if(this.labelxs > 0){
34226 label.cls += ' col-xs-' + this.labelxs;
34227 items.cls += ' col-xs-' + (12 - this.labelxs);
34233 cls : 'roo-radio-set',
34237 cls : 'roo-radio-set-input',
34240 value : this.value ? this.value : ''
34247 if(this.weight.length){
34248 cfg.cls += ' roo-radio-' + this.weight;
34252 cfg.cls += ' roo-radio-set-inline';
34256 ['xs','sm','md','lg'].map(function(size){
34257 if (settings[size]) {
34258 cfg.cls += ' col-' + size + '-' + settings[size];
34266 initEvents : function()
34268 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34269 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34271 if(!this.fieldLabel.length){
34272 this.labelEl.hide();
34275 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34276 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34278 this.indicator = this.indicatorEl();
34280 if(this.indicator){
34281 this.indicator.addClass('invisible');
34284 this.originalValue = this.getValue();
34288 inputEl: function ()
34290 return this.el.select('.roo-radio-set-input', true).first();
34293 getChildContainer : function()
34295 return this.itemsEl;
34298 register : function(item)
34300 this.radioes.push(item);
34304 validate : function()
34306 if(this.getVisibilityEl().hasClass('hidden')){
34312 Roo.each(this.radioes, function(i){
34321 if(this.allowBlank) {
34325 if(this.disabled || valid){
34330 this.markInvalid();
34335 markValid : function()
34337 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34338 this.indicatorEl().removeClass('visible');
34339 this.indicatorEl().addClass('invisible');
34343 if (Roo.bootstrap.version == 3) {
34344 this.el.removeClass([this.invalidClass, this.validClass]);
34345 this.el.addClass(this.validClass);
34347 this.el.removeClass(['is-invalid','is-valid']);
34348 this.el.addClass(['is-valid']);
34350 this.fireEvent('valid', this);
34353 markInvalid : function(msg)
34355 if(this.allowBlank || this.disabled){
34359 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34360 this.indicatorEl().removeClass('invisible');
34361 this.indicatorEl().addClass('visible');
34363 if (Roo.bootstrap.version == 3) {
34364 this.el.removeClass([this.invalidClass, this.validClass]);
34365 this.el.addClass(this.invalidClass);
34367 this.el.removeClass(['is-invalid','is-valid']);
34368 this.el.addClass(['is-invalid']);
34371 this.fireEvent('invalid', this, msg);
34375 setValue : function(v, suppressEvent)
34377 if(this.value === v){
34384 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34387 Roo.each(this.radioes, function(i){
34389 i.el.removeClass('checked');
34392 Roo.each(this.radioes, function(i){
34394 if(i.value === v || i.value.toString() === v.toString()){
34396 i.el.addClass('checked');
34398 if(suppressEvent !== true){
34399 this.fireEvent('check', this, i);
34410 clearInvalid : function(){
34412 if(!this.el || this.preventMark){
34416 this.el.removeClass([this.invalidClass]);
34418 this.fireEvent('valid', this);
34423 Roo.apply(Roo.bootstrap.RadioSet, {
34427 register : function(set)
34429 this.groups[set.name] = set;
34432 get: function(name)
34434 if (typeof(this.groups[name]) == 'undefined') {
34438 return this.groups[name] ;
34444 * Ext JS Library 1.1.1
34445 * Copyright(c) 2006-2007, Ext JS, LLC.
34447 * Originally Released Under LGPL - original licence link has changed is not relivant.
34450 * <script type="text/javascript">
34455 * @class Roo.bootstrap.SplitBar
34456 * @extends Roo.util.Observable
34457 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34461 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34462 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34463 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34464 split.minSize = 100;
34465 split.maxSize = 600;
34466 split.animate = true;
34467 split.on('moved', splitterMoved);
34470 * Create a new SplitBar
34471 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34472 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34473 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34474 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34475 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34476 position of the SplitBar).
34478 Roo.bootstrap.SplitBar = function(cfg){
34483 // dragElement : elm
34484 // resizingElement: el,
34486 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34487 // placement : Roo.bootstrap.SplitBar.LEFT ,
34488 // existingProxy ???
34491 this.el = Roo.get(cfg.dragElement, true);
34492 this.el.dom.unselectable = "on";
34494 this.resizingEl = Roo.get(cfg.resizingElement, true);
34498 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34499 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34502 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34505 * The minimum size of the resizing element. (Defaults to 0)
34511 * The maximum size of the resizing element. (Defaults to 2000)
34514 this.maxSize = 2000;
34517 * Whether to animate the transition to the new size
34520 this.animate = false;
34523 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34526 this.useShim = false;
34531 if(!cfg.existingProxy){
34533 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34535 this.proxy = Roo.get(cfg.existingProxy).dom;
34538 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34541 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34544 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34547 this.dragSpecs = {};
34550 * @private The adapter to use to positon and resize elements
34552 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34553 this.adapter.init(this);
34555 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34557 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34558 this.el.addClass("roo-splitbar-h");
34561 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34562 this.el.addClass("roo-splitbar-v");
34568 * Fires when the splitter is moved (alias for {@link #event-moved})
34569 * @param {Roo.bootstrap.SplitBar} this
34570 * @param {Number} newSize the new width or height
34575 * Fires when the splitter is moved
34576 * @param {Roo.bootstrap.SplitBar} this
34577 * @param {Number} newSize the new width or height
34581 * @event beforeresize
34582 * Fires before the splitter is dragged
34583 * @param {Roo.bootstrap.SplitBar} this
34585 "beforeresize" : true,
34587 "beforeapply" : true
34590 Roo.util.Observable.call(this);
34593 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34594 onStartProxyDrag : function(x, y){
34595 this.fireEvent("beforeresize", this);
34597 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34599 o.enableDisplayMode("block");
34600 // all splitbars share the same overlay
34601 Roo.bootstrap.SplitBar.prototype.overlay = o;
34603 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34604 this.overlay.show();
34605 Roo.get(this.proxy).setDisplayed("block");
34606 var size = this.adapter.getElementSize(this);
34607 this.activeMinSize = this.getMinimumSize();;
34608 this.activeMaxSize = this.getMaximumSize();;
34609 var c1 = size - this.activeMinSize;
34610 var c2 = Math.max(this.activeMaxSize - size, 0);
34611 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34612 this.dd.resetConstraints();
34613 this.dd.setXConstraint(
34614 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34615 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34617 this.dd.setYConstraint(0, 0);
34619 this.dd.resetConstraints();
34620 this.dd.setXConstraint(0, 0);
34621 this.dd.setYConstraint(
34622 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34623 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34626 this.dragSpecs.startSize = size;
34627 this.dragSpecs.startPoint = [x, y];
34628 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34632 * @private Called after the drag operation by the DDProxy
34634 onEndProxyDrag : function(e){
34635 Roo.get(this.proxy).setDisplayed(false);
34636 var endPoint = Roo.lib.Event.getXY(e);
34638 this.overlay.hide();
34641 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34642 newSize = this.dragSpecs.startSize +
34643 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34644 endPoint[0] - this.dragSpecs.startPoint[0] :
34645 this.dragSpecs.startPoint[0] - endPoint[0]
34648 newSize = this.dragSpecs.startSize +
34649 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34650 endPoint[1] - this.dragSpecs.startPoint[1] :
34651 this.dragSpecs.startPoint[1] - endPoint[1]
34654 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34655 if(newSize != this.dragSpecs.startSize){
34656 if(this.fireEvent('beforeapply', this, newSize) !== false){
34657 this.adapter.setElementSize(this, newSize);
34658 this.fireEvent("moved", this, newSize);
34659 this.fireEvent("resize", this, newSize);
34665 * Get the adapter this SplitBar uses
34666 * @return The adapter object
34668 getAdapter : function(){
34669 return this.adapter;
34673 * Set the adapter this SplitBar uses
34674 * @param {Object} adapter A SplitBar adapter object
34676 setAdapter : function(adapter){
34677 this.adapter = adapter;
34678 this.adapter.init(this);
34682 * Gets the minimum size for the resizing element
34683 * @return {Number} The minimum size
34685 getMinimumSize : function(){
34686 return this.minSize;
34690 * Sets the minimum size for the resizing element
34691 * @param {Number} minSize The minimum size
34693 setMinimumSize : function(minSize){
34694 this.minSize = minSize;
34698 * Gets the maximum size for the resizing element
34699 * @return {Number} The maximum size
34701 getMaximumSize : function(){
34702 return this.maxSize;
34706 * Sets the maximum size for the resizing element
34707 * @param {Number} maxSize The maximum size
34709 setMaximumSize : function(maxSize){
34710 this.maxSize = maxSize;
34714 * Sets the initialize size for the resizing element
34715 * @param {Number} size The initial size
34717 setCurrentSize : function(size){
34718 var oldAnimate = this.animate;
34719 this.animate = false;
34720 this.adapter.setElementSize(this, size);
34721 this.animate = oldAnimate;
34725 * Destroy this splitbar.
34726 * @param {Boolean} removeEl True to remove the element
34728 destroy : function(removeEl){
34730 this.shim.remove();
34733 this.proxy.parentNode.removeChild(this.proxy);
34741 * @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.
34743 Roo.bootstrap.SplitBar.createProxy = function(dir){
34744 var proxy = new Roo.Element(document.createElement("div"));
34745 proxy.unselectable();
34746 var cls = 'roo-splitbar-proxy';
34747 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34748 document.body.appendChild(proxy.dom);
34753 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34754 * Default Adapter. It assumes the splitter and resizing element are not positioned
34755 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34757 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34760 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34761 // do nothing for now
34762 init : function(s){
34766 * Called before drag operations to get the current size of the resizing element.
34767 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34769 getElementSize : function(s){
34770 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34771 return s.resizingEl.getWidth();
34773 return s.resizingEl.getHeight();
34778 * Called after drag operations to set the size of the resizing element.
34779 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34780 * @param {Number} newSize The new size to set
34781 * @param {Function} onComplete A function to be invoked when resizing is complete
34783 setElementSize : function(s, newSize, onComplete){
34784 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34786 s.resizingEl.setWidth(newSize);
34788 onComplete(s, newSize);
34791 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34796 s.resizingEl.setHeight(newSize);
34798 onComplete(s, newSize);
34801 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34808 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34809 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34810 * Adapter that moves the splitter element to align with the resized sizing element.
34811 * Used with an absolute positioned SplitBar.
34812 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34813 * document.body, make sure you assign an id to the body element.
34815 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34816 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34817 this.container = Roo.get(container);
34820 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34821 init : function(s){
34822 this.basic.init(s);
34825 getElementSize : function(s){
34826 return this.basic.getElementSize(s);
34829 setElementSize : function(s, newSize, onComplete){
34830 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34833 moveSplitter : function(s){
34834 var yes = Roo.bootstrap.SplitBar;
34835 switch(s.placement){
34837 s.el.setX(s.resizingEl.getRight());
34840 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34843 s.el.setY(s.resizingEl.getBottom());
34846 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34853 * Orientation constant - Create a vertical SplitBar
34857 Roo.bootstrap.SplitBar.VERTICAL = 1;
34860 * Orientation constant - Create a horizontal SplitBar
34864 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34867 * Placement constant - The resizing element is to the left of the splitter element
34871 Roo.bootstrap.SplitBar.LEFT = 1;
34874 * Placement constant - The resizing element is to the right of the splitter element
34878 Roo.bootstrap.SplitBar.RIGHT = 2;
34881 * Placement constant - The resizing element is positioned above the splitter element
34885 Roo.bootstrap.SplitBar.TOP = 3;
34888 * Placement constant - The resizing element is positioned under splitter element
34892 Roo.bootstrap.SplitBar.BOTTOM = 4;
34893 Roo.namespace("Roo.bootstrap.layout");/*
34895 * Ext JS Library 1.1.1
34896 * Copyright(c) 2006-2007, Ext JS, LLC.
34898 * Originally Released Under LGPL - original licence link has changed is not relivant.
34901 * <script type="text/javascript">
34905 * @class Roo.bootstrap.layout.Manager
34906 * @extends Roo.bootstrap.Component
34907 * Base class for layout managers.
34909 Roo.bootstrap.layout.Manager = function(config)
34911 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34917 /** false to disable window resize monitoring @type Boolean */
34918 this.monitorWindowResize = true;
34923 * Fires when a layout is performed.
34924 * @param {Roo.LayoutManager} this
34928 * @event regionresized
34929 * Fires when the user resizes a region.
34930 * @param {Roo.LayoutRegion} region The resized region
34931 * @param {Number} newSize The new size (width for east/west, height for north/south)
34933 "regionresized" : true,
34935 * @event regioncollapsed
34936 * Fires when a region is collapsed.
34937 * @param {Roo.LayoutRegion} region The collapsed region
34939 "regioncollapsed" : true,
34941 * @event regionexpanded
34942 * Fires when a region is expanded.
34943 * @param {Roo.LayoutRegion} region The expanded region
34945 "regionexpanded" : true
34947 this.updating = false;
34950 this.el = Roo.get(config.el);
34956 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34961 monitorWindowResize : true,
34967 onRender : function(ct, position)
34970 this.el = Roo.get(ct);
34973 //this.fireEvent('render',this);
34977 initEvents: function()
34981 // ie scrollbar fix
34982 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34983 document.body.scroll = "no";
34984 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34985 this.el.position('relative');
34987 this.id = this.el.id;
34988 this.el.addClass("roo-layout-container");
34989 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34990 if(this.el.dom != document.body ) {
34991 this.el.on('resize', this.layout,this);
34992 this.el.on('show', this.layout,this);
34998 * Returns true if this layout is currently being updated
34999 * @return {Boolean}
35001 isUpdating : function(){
35002 return this.updating;
35006 * Suspend the LayoutManager from doing auto-layouts while
35007 * making multiple add or remove calls
35009 beginUpdate : function(){
35010 this.updating = true;
35014 * Restore auto-layouts and optionally disable the manager from performing a layout
35015 * @param {Boolean} noLayout true to disable a layout update
35017 endUpdate : function(noLayout){
35018 this.updating = false;
35024 layout: function(){
35028 onRegionResized : function(region, newSize){
35029 this.fireEvent("regionresized", region, newSize);
35033 onRegionCollapsed : function(region){
35034 this.fireEvent("regioncollapsed", region);
35037 onRegionExpanded : function(region){
35038 this.fireEvent("regionexpanded", region);
35042 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35043 * performs box-model adjustments.
35044 * @return {Object} The size as an object {width: (the width), height: (the height)}
35046 getViewSize : function()
35049 if(this.el.dom != document.body){
35050 size = this.el.getSize();
35052 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35054 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35055 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35060 * Returns the Element this layout is bound to.
35061 * @return {Roo.Element}
35063 getEl : function(){
35068 * Returns the specified region.
35069 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35070 * @return {Roo.LayoutRegion}
35072 getRegion : function(target){
35073 return this.regions[target.toLowerCase()];
35076 onWindowResize : function(){
35077 if(this.monitorWindowResize){
35084 * Ext JS Library 1.1.1
35085 * Copyright(c) 2006-2007, Ext JS, LLC.
35087 * Originally Released Under LGPL - original licence link has changed is not relivant.
35090 * <script type="text/javascript">
35093 * @class Roo.bootstrap.layout.Border
35094 * @extends Roo.bootstrap.layout.Manager
35095 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35096 * please see: examples/bootstrap/nested.html<br><br>
35098 <b>The container the layout is rendered into can be either the body element or any other element.
35099 If it is not the body element, the container needs to either be an absolute positioned element,
35100 or you will need to add "position:relative" to the css of the container. You will also need to specify
35101 the container size if it is not the body element.</b>
35104 * Create a new Border
35105 * @param {Object} config Configuration options
35107 Roo.bootstrap.layout.Border = function(config){
35108 config = config || {};
35109 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35113 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35114 if(config[region]){
35115 config[region].region = region;
35116 this.addRegion(config[region]);
35122 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35124 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35126 parent : false, // this might point to a 'nest' or a ???
35129 * Creates and adds a new region if it doesn't already exist.
35130 * @param {String} target The target region key (north, south, east, west or center).
35131 * @param {Object} config The regions config object
35132 * @return {BorderLayoutRegion} The new region
35134 addRegion : function(config)
35136 if(!this.regions[config.region]){
35137 var r = this.factory(config);
35138 this.bindRegion(r);
35140 return this.regions[config.region];
35144 bindRegion : function(r){
35145 this.regions[r.config.region] = r;
35147 r.on("visibilitychange", this.layout, this);
35148 r.on("paneladded", this.layout, this);
35149 r.on("panelremoved", this.layout, this);
35150 r.on("invalidated", this.layout, this);
35151 r.on("resized", this.onRegionResized, this);
35152 r.on("collapsed", this.onRegionCollapsed, this);
35153 r.on("expanded", this.onRegionExpanded, this);
35157 * Performs a layout update.
35159 layout : function()
35161 if(this.updating) {
35165 // render all the rebions if they have not been done alreayd?
35166 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35167 if(this.regions[region] && !this.regions[region].bodyEl){
35168 this.regions[region].onRender(this.el)
35172 var size = this.getViewSize();
35173 var w = size.width;
35174 var h = size.height;
35179 //var x = 0, y = 0;
35181 var rs = this.regions;
35182 var north = rs["north"];
35183 var south = rs["south"];
35184 var west = rs["west"];
35185 var east = rs["east"];
35186 var center = rs["center"];
35187 //if(this.hideOnLayout){ // not supported anymore
35188 //c.el.setStyle("display", "none");
35190 if(north && north.isVisible()){
35191 var b = north.getBox();
35192 var m = north.getMargins();
35193 b.width = w - (m.left+m.right);
35196 centerY = b.height + b.y + m.bottom;
35197 centerH -= centerY;
35198 north.updateBox(this.safeBox(b));
35200 if(south && south.isVisible()){
35201 var b = south.getBox();
35202 var m = south.getMargins();
35203 b.width = w - (m.left+m.right);
35205 var totalHeight = (b.height + m.top + m.bottom);
35206 b.y = h - totalHeight + m.top;
35207 centerH -= totalHeight;
35208 south.updateBox(this.safeBox(b));
35210 if(west && west.isVisible()){
35211 var b = west.getBox();
35212 var m = west.getMargins();
35213 b.height = centerH - (m.top+m.bottom);
35215 b.y = centerY + m.top;
35216 var totalWidth = (b.width + m.left + m.right);
35217 centerX += totalWidth;
35218 centerW -= totalWidth;
35219 west.updateBox(this.safeBox(b));
35221 if(east && east.isVisible()){
35222 var b = east.getBox();
35223 var m = east.getMargins();
35224 b.height = centerH - (m.top+m.bottom);
35225 var totalWidth = (b.width + m.left + m.right);
35226 b.x = w - totalWidth + m.left;
35227 b.y = centerY + m.top;
35228 centerW -= totalWidth;
35229 east.updateBox(this.safeBox(b));
35232 var m = center.getMargins();
35234 x: centerX + m.left,
35235 y: centerY + m.top,
35236 width: centerW - (m.left+m.right),
35237 height: centerH - (m.top+m.bottom)
35239 //if(this.hideOnLayout){
35240 //center.el.setStyle("display", "block");
35242 center.updateBox(this.safeBox(centerBox));
35245 this.fireEvent("layout", this);
35249 safeBox : function(box){
35250 box.width = Math.max(0, box.width);
35251 box.height = Math.max(0, box.height);
35256 * Adds a ContentPanel (or subclass) to this layout.
35257 * @param {String} target The target region key (north, south, east, west or center).
35258 * @param {Roo.ContentPanel} panel The panel to add
35259 * @return {Roo.ContentPanel} The added panel
35261 add : function(target, panel){
35263 target = target.toLowerCase();
35264 return this.regions[target].add(panel);
35268 * Remove a ContentPanel (or subclass) to this layout.
35269 * @param {String} target The target region key (north, south, east, west or center).
35270 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35271 * @return {Roo.ContentPanel} The removed panel
35273 remove : function(target, panel){
35274 target = target.toLowerCase();
35275 return this.regions[target].remove(panel);
35279 * Searches all regions for a panel with the specified id
35280 * @param {String} panelId
35281 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35283 findPanel : function(panelId){
35284 var rs = this.regions;
35285 for(var target in rs){
35286 if(typeof rs[target] != "function"){
35287 var p = rs[target].getPanel(panelId);
35297 * Searches all regions for a panel with the specified id and activates (shows) it.
35298 * @param {String/ContentPanel} panelId The panels id or the panel itself
35299 * @return {Roo.ContentPanel} The shown panel or null
35301 showPanel : function(panelId) {
35302 var rs = this.regions;
35303 for(var target in rs){
35304 var r = rs[target];
35305 if(typeof r != "function"){
35306 if(r.hasPanel(panelId)){
35307 return r.showPanel(panelId);
35315 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35316 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35319 restoreState : function(provider){
35321 provider = Roo.state.Manager;
35323 var sm = new Roo.LayoutStateManager();
35324 sm.init(this, provider);
35330 * Adds a xtype elements to the layout.
35334 xtype : 'ContentPanel',
35341 xtype : 'NestedLayoutPanel',
35347 items : [ ... list of content panels or nested layout panels.. ]
35351 * @param {Object} cfg Xtype definition of item to add.
35353 addxtype : function(cfg)
35355 // basically accepts a pannel...
35356 // can accept a layout region..!?!?
35357 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35360 // theory? children can only be panels??
35362 //if (!cfg.xtype.match(/Panel$/)) {
35367 if (typeof(cfg.region) == 'undefined') {
35368 Roo.log("Failed to add Panel, region was not set");
35372 var region = cfg.region;
35378 xitems = cfg.items;
35383 if ( region == 'center') {
35384 Roo.log("Center: " + cfg.title);
35390 case 'Content': // ContentPanel (el, cfg)
35391 case 'Scroll': // ContentPanel (el, cfg)
35393 cfg.autoCreate = cfg.autoCreate || true;
35394 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35396 // var el = this.el.createChild();
35397 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35400 this.add(region, ret);
35404 case 'TreePanel': // our new panel!
35405 cfg.el = this.el.createChild();
35406 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35407 this.add(region, ret);
35412 // create a new Layout (which is a Border Layout...
35414 var clayout = cfg.layout;
35415 clayout.el = this.el.createChild();
35416 clayout.items = clayout.items || [];
35420 // replace this exitems with the clayout ones..
35421 xitems = clayout.items;
35423 // force background off if it's in center...
35424 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35425 cfg.background = false;
35427 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35430 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35431 //console.log('adding nested layout panel ' + cfg.toSource());
35432 this.add(region, ret);
35433 nb = {}; /// find first...
35438 // needs grid and region
35440 //var el = this.getRegion(region).el.createChild();
35442 *var el = this.el.createChild();
35443 // create the grid first...
35444 cfg.grid.container = el;
35445 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35448 if (region == 'center' && this.active ) {
35449 cfg.background = false;
35452 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35454 this.add(region, ret);
35456 if (cfg.background) {
35457 // render grid on panel activation (if panel background)
35458 ret.on('activate', function(gp) {
35459 if (!gp.grid.rendered) {
35460 // gp.grid.render(el);
35464 // cfg.grid.render(el);
35470 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35471 // it was the old xcomponent building that caused this before.
35472 // espeically if border is the top element in the tree.
35482 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35484 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35485 this.add(region, ret);
35489 throw "Can not add '" + cfg.xtype + "' to Border";
35495 this.beginUpdate();
35499 Roo.each(xitems, function(i) {
35500 region = nb && i.region ? i.region : false;
35502 var add = ret.addxtype(i);
35505 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35506 if (!i.background) {
35507 abn[region] = nb[region] ;
35514 // make the last non-background panel active..
35515 //if (nb) { Roo.log(abn); }
35518 for(var r in abn) {
35519 region = this.getRegion(r);
35521 // tried using nb[r], but it does not work..
35523 region.showPanel(abn[r]);
35534 factory : function(cfg)
35537 var validRegions = Roo.bootstrap.layout.Border.regions;
35539 var target = cfg.region;
35542 var r = Roo.bootstrap.layout;
35546 return new r.North(cfg);
35548 return new r.South(cfg);
35550 return new r.East(cfg);
35552 return new r.West(cfg);
35554 return new r.Center(cfg);
35556 throw 'Layout region "'+target+'" not supported.';
35563 * Ext JS Library 1.1.1
35564 * Copyright(c) 2006-2007, Ext JS, LLC.
35566 * Originally Released Under LGPL - original licence link has changed is not relivant.
35569 * <script type="text/javascript">
35573 * @class Roo.bootstrap.layout.Basic
35574 * @extends Roo.util.Observable
35575 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35576 * and does not have a titlebar, tabs or any other features. All it does is size and position
35577 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35578 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35579 * @cfg {string} region the region that it inhabits..
35580 * @cfg {bool} skipConfig skip config?
35584 Roo.bootstrap.layout.Basic = function(config){
35586 this.mgr = config.mgr;
35588 this.position = config.region;
35590 var skipConfig = config.skipConfig;
35594 * @scope Roo.BasicLayoutRegion
35598 * @event beforeremove
35599 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35600 * @param {Roo.LayoutRegion} this
35601 * @param {Roo.ContentPanel} panel The panel
35602 * @param {Object} e The cancel event object
35604 "beforeremove" : true,
35606 * @event invalidated
35607 * Fires when the layout for this region is changed.
35608 * @param {Roo.LayoutRegion} this
35610 "invalidated" : true,
35612 * @event visibilitychange
35613 * Fires when this region is shown or hidden
35614 * @param {Roo.LayoutRegion} this
35615 * @param {Boolean} visibility true or false
35617 "visibilitychange" : true,
35619 * @event paneladded
35620 * Fires when a panel is added.
35621 * @param {Roo.LayoutRegion} this
35622 * @param {Roo.ContentPanel} panel The panel
35624 "paneladded" : true,
35626 * @event panelremoved
35627 * Fires when a panel is removed.
35628 * @param {Roo.LayoutRegion} this
35629 * @param {Roo.ContentPanel} panel The panel
35631 "panelremoved" : true,
35633 * @event beforecollapse
35634 * Fires when this region before collapse.
35635 * @param {Roo.LayoutRegion} this
35637 "beforecollapse" : true,
35640 * Fires when this region is collapsed.
35641 * @param {Roo.LayoutRegion} this
35643 "collapsed" : true,
35646 * Fires when this region is expanded.
35647 * @param {Roo.LayoutRegion} this
35652 * Fires when this region is slid into view.
35653 * @param {Roo.LayoutRegion} this
35655 "slideshow" : true,
35658 * Fires when this region slides out of view.
35659 * @param {Roo.LayoutRegion} this
35661 "slidehide" : true,
35663 * @event panelactivated
35664 * Fires when a panel is activated.
35665 * @param {Roo.LayoutRegion} this
35666 * @param {Roo.ContentPanel} panel The activated panel
35668 "panelactivated" : true,
35671 * Fires when the user resizes this region.
35672 * @param {Roo.LayoutRegion} this
35673 * @param {Number} newSize The new size (width for east/west, height for north/south)
35677 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35678 this.panels = new Roo.util.MixedCollection();
35679 this.panels.getKey = this.getPanelId.createDelegate(this);
35681 this.activePanel = null;
35682 // ensure listeners are added...
35684 if (config.listeners || config.events) {
35685 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35686 listeners : config.listeners || {},
35687 events : config.events || {}
35691 if(skipConfig !== true){
35692 this.applyConfig(config);
35696 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35698 getPanelId : function(p){
35702 applyConfig : function(config){
35703 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35704 this.config = config;
35709 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35710 * the width, for horizontal (north, south) the height.
35711 * @param {Number} newSize The new width or height
35713 resizeTo : function(newSize){
35714 var el = this.el ? this.el :
35715 (this.activePanel ? this.activePanel.getEl() : null);
35717 switch(this.position){
35720 el.setWidth(newSize);
35721 this.fireEvent("resized", this, newSize);
35725 el.setHeight(newSize);
35726 this.fireEvent("resized", this, newSize);
35732 getBox : function(){
35733 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35736 getMargins : function(){
35737 return this.margins;
35740 updateBox : function(box){
35742 var el = this.activePanel.getEl();
35743 el.dom.style.left = box.x + "px";
35744 el.dom.style.top = box.y + "px";
35745 this.activePanel.setSize(box.width, box.height);
35749 * Returns the container element for this region.
35750 * @return {Roo.Element}
35752 getEl : function(){
35753 return this.activePanel;
35757 * Returns true if this region is currently visible.
35758 * @return {Boolean}
35760 isVisible : function(){
35761 return this.activePanel ? true : false;
35764 setActivePanel : function(panel){
35765 panel = this.getPanel(panel);
35766 if(this.activePanel && this.activePanel != panel){
35767 this.activePanel.setActiveState(false);
35768 this.activePanel.getEl().setLeftTop(-10000,-10000);
35770 this.activePanel = panel;
35771 panel.setActiveState(true);
35773 panel.setSize(this.box.width, this.box.height);
35775 this.fireEvent("panelactivated", this, panel);
35776 this.fireEvent("invalidated");
35780 * Show the specified panel.
35781 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35782 * @return {Roo.ContentPanel} The shown panel or null
35784 showPanel : function(panel){
35785 panel = this.getPanel(panel);
35787 this.setActivePanel(panel);
35793 * Get the active panel for this region.
35794 * @return {Roo.ContentPanel} The active panel or null
35796 getActivePanel : function(){
35797 return this.activePanel;
35801 * Add the passed ContentPanel(s)
35802 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35803 * @return {Roo.ContentPanel} The panel added (if only one was added)
35805 add : function(panel){
35806 if(arguments.length > 1){
35807 for(var i = 0, len = arguments.length; i < len; i++) {
35808 this.add(arguments[i]);
35812 if(this.hasPanel(panel)){
35813 this.showPanel(panel);
35816 var el = panel.getEl();
35817 if(el.dom.parentNode != this.mgr.el.dom){
35818 this.mgr.el.dom.appendChild(el.dom);
35820 if(panel.setRegion){
35821 panel.setRegion(this);
35823 this.panels.add(panel);
35824 el.setStyle("position", "absolute");
35825 if(!panel.background){
35826 this.setActivePanel(panel);
35827 if(this.config.initialSize && this.panels.getCount()==1){
35828 this.resizeTo(this.config.initialSize);
35831 this.fireEvent("paneladded", this, panel);
35836 * Returns true if the panel is in this region.
35837 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35838 * @return {Boolean}
35840 hasPanel : function(panel){
35841 if(typeof panel == "object"){ // must be panel obj
35842 panel = panel.getId();
35844 return this.getPanel(panel) ? true : false;
35848 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35849 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35850 * @param {Boolean} preservePanel Overrides the config preservePanel option
35851 * @return {Roo.ContentPanel} The panel that was removed
35853 remove : function(panel, preservePanel){
35854 panel = this.getPanel(panel);
35859 this.fireEvent("beforeremove", this, panel, e);
35860 if(e.cancel === true){
35863 var panelId = panel.getId();
35864 this.panels.removeKey(panelId);
35869 * Returns the panel specified or null if it's not in this region.
35870 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35871 * @return {Roo.ContentPanel}
35873 getPanel : function(id){
35874 if(typeof id == "object"){ // must be panel obj
35877 return this.panels.get(id);
35881 * Returns this regions position (north/south/east/west/center).
35884 getPosition: function(){
35885 return this.position;
35889 * Ext JS Library 1.1.1
35890 * Copyright(c) 2006-2007, Ext JS, LLC.
35892 * Originally Released Under LGPL - original licence link has changed is not relivant.
35895 * <script type="text/javascript">
35899 * @class Roo.bootstrap.layout.Region
35900 * @extends Roo.bootstrap.layout.Basic
35901 * This class represents a region in a layout manager.
35903 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35904 * @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})
35905 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35906 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35907 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35908 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35909 * @cfg {String} title The title for the region (overrides panel titles)
35910 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35911 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35912 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35913 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35914 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35915 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35916 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35917 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35918 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35919 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35921 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35922 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35923 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35924 * @cfg {Number} width For East/West panels
35925 * @cfg {Number} height For North/South panels
35926 * @cfg {Boolean} split To show the splitter
35927 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35929 * @cfg {string} cls Extra CSS classes to add to region
35931 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35932 * @cfg {string} region the region that it inhabits..
35935 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35936 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35938 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35939 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35940 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35942 Roo.bootstrap.layout.Region = function(config)
35944 this.applyConfig(config);
35946 var mgr = config.mgr;
35947 var pos = config.region;
35948 config.skipConfig = true;
35949 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35952 this.onRender(mgr.el);
35955 this.visible = true;
35956 this.collapsed = false;
35957 this.unrendered_panels = [];
35960 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35962 position: '', // set by wrapper (eg. north/south etc..)
35963 unrendered_panels : null, // unrendered panels.
35965 tabPosition : false,
35967 mgr: false, // points to 'Border'
35970 createBody : function(){
35971 /** This region's body element
35972 * @type Roo.Element */
35973 this.bodyEl = this.el.createChild({
35975 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35979 onRender: function(ctr, pos)
35981 var dh = Roo.DomHelper;
35982 /** This region's container element
35983 * @type Roo.Element */
35984 this.el = dh.append(ctr.dom, {
35986 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35988 /** This region's title element
35989 * @type Roo.Element */
35991 this.titleEl = dh.append(this.el.dom, {
35993 unselectable: "on",
35994 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35996 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35997 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36001 this.titleEl.enableDisplayMode();
36002 /** This region's title text element
36003 * @type HTMLElement */
36004 this.titleTextEl = this.titleEl.dom.firstChild;
36005 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36007 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36008 this.closeBtn.enableDisplayMode();
36009 this.closeBtn.on("click", this.closeClicked, this);
36010 this.closeBtn.hide();
36012 this.createBody(this.config);
36013 if(this.config.hideWhenEmpty){
36015 this.on("paneladded", this.validateVisibility, this);
36016 this.on("panelremoved", this.validateVisibility, this);
36018 if(this.autoScroll){
36019 this.bodyEl.setStyle("overflow", "auto");
36021 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36023 //if(c.titlebar !== false){
36024 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36025 this.titleEl.hide();
36027 this.titleEl.show();
36028 if(this.config.title){
36029 this.titleTextEl.innerHTML = this.config.title;
36033 if(this.config.collapsed){
36034 this.collapse(true);
36036 if(this.config.hidden){
36040 if (this.unrendered_panels && this.unrendered_panels.length) {
36041 for (var i =0;i< this.unrendered_panels.length; i++) {
36042 this.add(this.unrendered_panels[i]);
36044 this.unrendered_panels = null;
36050 applyConfig : function(c)
36053 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36054 var dh = Roo.DomHelper;
36055 if(c.titlebar !== false){
36056 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36057 this.collapseBtn.on("click", this.collapse, this);
36058 this.collapseBtn.enableDisplayMode();
36060 if(c.showPin === true || this.showPin){
36061 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36062 this.stickBtn.enableDisplayMode();
36063 this.stickBtn.on("click", this.expand, this);
36064 this.stickBtn.hide();
36069 /** This region's collapsed element
36070 * @type Roo.Element */
36073 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36074 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36077 if(c.floatable !== false){
36078 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36079 this.collapsedEl.on("click", this.collapseClick, this);
36082 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36083 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36084 id: "message", unselectable: "on", style:{"float":"left"}});
36085 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36087 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36088 this.expandBtn.on("click", this.expand, this);
36092 if(this.collapseBtn){
36093 this.collapseBtn.setVisible(c.collapsible == true);
36096 this.cmargins = c.cmargins || this.cmargins ||
36097 (this.position == "west" || this.position == "east" ?
36098 {top: 0, left: 2, right:2, bottom: 0} :
36099 {top: 2, left: 0, right:0, bottom: 2});
36101 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36104 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36106 this.autoScroll = c.autoScroll || false;
36111 this.duration = c.duration || .30;
36112 this.slideDuration = c.slideDuration || .45;
36117 * Returns true if this region is currently visible.
36118 * @return {Boolean}
36120 isVisible : function(){
36121 return this.visible;
36125 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36126 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36128 //setCollapsedTitle : function(title){
36129 // title = title || " ";
36130 // if(this.collapsedTitleTextEl){
36131 // this.collapsedTitleTextEl.innerHTML = title;
36135 getBox : function(){
36137 // if(!this.collapsed){
36138 b = this.el.getBox(false, true);
36140 // b = this.collapsedEl.getBox(false, true);
36145 getMargins : function(){
36146 return this.margins;
36147 //return this.collapsed ? this.cmargins : this.margins;
36150 highlight : function(){
36151 this.el.addClass("x-layout-panel-dragover");
36154 unhighlight : function(){
36155 this.el.removeClass("x-layout-panel-dragover");
36158 updateBox : function(box)
36160 if (!this.bodyEl) {
36161 return; // not rendered yet..
36165 if(!this.collapsed){
36166 this.el.dom.style.left = box.x + "px";
36167 this.el.dom.style.top = box.y + "px";
36168 this.updateBody(box.width, box.height);
36170 this.collapsedEl.dom.style.left = box.x + "px";
36171 this.collapsedEl.dom.style.top = box.y + "px";
36172 this.collapsedEl.setSize(box.width, box.height);
36175 this.tabs.autoSizeTabs();
36179 updateBody : function(w, h)
36182 this.el.setWidth(w);
36183 w -= this.el.getBorderWidth("rl");
36184 if(this.config.adjustments){
36185 w += this.config.adjustments[0];
36188 if(h !== null && h > 0){
36189 this.el.setHeight(h);
36190 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36191 h -= this.el.getBorderWidth("tb");
36192 if(this.config.adjustments){
36193 h += this.config.adjustments[1];
36195 this.bodyEl.setHeight(h);
36197 h = this.tabs.syncHeight(h);
36200 if(this.panelSize){
36201 w = w !== null ? w : this.panelSize.width;
36202 h = h !== null ? h : this.panelSize.height;
36204 if(this.activePanel){
36205 var el = this.activePanel.getEl();
36206 w = w !== null ? w : el.getWidth();
36207 h = h !== null ? h : el.getHeight();
36208 this.panelSize = {width: w, height: h};
36209 this.activePanel.setSize(w, h);
36211 if(Roo.isIE && this.tabs){
36212 this.tabs.el.repaint();
36217 * Returns the container element for this region.
36218 * @return {Roo.Element}
36220 getEl : function(){
36225 * Hides this region.
36228 //if(!this.collapsed){
36229 this.el.dom.style.left = "-2000px";
36232 // this.collapsedEl.dom.style.left = "-2000px";
36233 // this.collapsedEl.hide();
36235 this.visible = false;
36236 this.fireEvent("visibilitychange", this, false);
36240 * Shows this region if it was previously hidden.
36243 //if(!this.collapsed){
36246 // this.collapsedEl.show();
36248 this.visible = true;
36249 this.fireEvent("visibilitychange", this, true);
36252 closeClicked : function(){
36253 if(this.activePanel){
36254 this.remove(this.activePanel);
36258 collapseClick : function(e){
36260 e.stopPropagation();
36263 e.stopPropagation();
36269 * Collapses this region.
36270 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36273 collapse : function(skipAnim, skipCheck = false){
36274 if(this.collapsed) {
36278 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36280 this.collapsed = true;
36282 this.split.el.hide();
36284 if(this.config.animate && skipAnim !== true){
36285 this.fireEvent("invalidated", this);
36286 this.animateCollapse();
36288 this.el.setLocation(-20000,-20000);
36290 this.collapsedEl.show();
36291 this.fireEvent("collapsed", this);
36292 this.fireEvent("invalidated", this);
36298 animateCollapse : function(){
36303 * Expands this region if it was previously collapsed.
36304 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36305 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36308 expand : function(e, skipAnim){
36310 e.stopPropagation();
36312 if(!this.collapsed || this.el.hasActiveFx()) {
36316 this.afterSlideIn();
36319 this.collapsed = false;
36320 if(this.config.animate && skipAnim !== true){
36321 this.animateExpand();
36325 this.split.el.show();
36327 this.collapsedEl.setLocation(-2000,-2000);
36328 this.collapsedEl.hide();
36329 this.fireEvent("invalidated", this);
36330 this.fireEvent("expanded", this);
36334 animateExpand : function(){
36338 initTabs : function()
36340 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36342 var ts = new Roo.bootstrap.panel.Tabs({
36343 el: this.bodyEl.dom,
36345 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36346 disableTooltips: this.config.disableTabTips,
36347 toolbar : this.config.toolbar
36350 if(this.config.hideTabs){
36351 ts.stripWrap.setDisplayed(false);
36354 ts.resizeTabs = this.config.resizeTabs === true;
36355 ts.minTabWidth = this.config.minTabWidth || 40;
36356 ts.maxTabWidth = this.config.maxTabWidth || 250;
36357 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36358 ts.monitorResize = false;
36359 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36360 ts.bodyEl.addClass('roo-layout-tabs-body');
36361 this.panels.each(this.initPanelAsTab, this);
36364 initPanelAsTab : function(panel){
36365 var ti = this.tabs.addTab(
36369 this.config.closeOnTab && panel.isClosable(),
36372 if(panel.tabTip !== undefined){
36373 ti.setTooltip(panel.tabTip);
36375 ti.on("activate", function(){
36376 this.setActivePanel(panel);
36379 if(this.config.closeOnTab){
36380 ti.on("beforeclose", function(t, e){
36382 this.remove(panel);
36386 panel.tabItem = ti;
36391 updatePanelTitle : function(panel, title)
36393 if(this.activePanel == panel){
36394 this.updateTitle(title);
36397 var ti = this.tabs.getTab(panel.getEl().id);
36399 if(panel.tabTip !== undefined){
36400 ti.setTooltip(panel.tabTip);
36405 updateTitle : function(title){
36406 if(this.titleTextEl && !this.config.title){
36407 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36411 setActivePanel : function(panel)
36413 panel = this.getPanel(panel);
36414 if(this.activePanel && this.activePanel != panel){
36415 if(this.activePanel.setActiveState(false) === false){
36419 this.activePanel = panel;
36420 panel.setActiveState(true);
36421 if(this.panelSize){
36422 panel.setSize(this.panelSize.width, this.panelSize.height);
36425 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36427 this.updateTitle(panel.getTitle());
36429 this.fireEvent("invalidated", this);
36431 this.fireEvent("panelactivated", this, panel);
36435 * Shows the specified panel.
36436 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36437 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36439 showPanel : function(panel)
36441 panel = this.getPanel(panel);
36444 var tab = this.tabs.getTab(panel.getEl().id);
36445 if(tab.isHidden()){
36446 this.tabs.unhideTab(tab.id);
36450 this.setActivePanel(panel);
36457 * Get the active panel for this region.
36458 * @return {Roo.ContentPanel} The active panel or null
36460 getActivePanel : function(){
36461 return this.activePanel;
36464 validateVisibility : function(){
36465 if(this.panels.getCount() < 1){
36466 this.updateTitle(" ");
36467 this.closeBtn.hide();
36470 if(!this.isVisible()){
36477 * Adds the passed ContentPanel(s) to this region.
36478 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36479 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36481 add : function(panel)
36483 if(arguments.length > 1){
36484 for(var i = 0, len = arguments.length; i < len; i++) {
36485 this.add(arguments[i]);
36490 // if we have not been rendered yet, then we can not really do much of this..
36491 if (!this.bodyEl) {
36492 this.unrendered_panels.push(panel);
36499 if(this.hasPanel(panel)){
36500 this.showPanel(panel);
36503 panel.setRegion(this);
36504 this.panels.add(panel);
36505 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36506 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36507 // and hide them... ???
36508 this.bodyEl.dom.appendChild(panel.getEl().dom);
36509 if(panel.background !== true){
36510 this.setActivePanel(panel);
36512 this.fireEvent("paneladded", this, panel);
36519 this.initPanelAsTab(panel);
36523 if(panel.background !== true){
36524 this.tabs.activate(panel.getEl().id);
36526 this.fireEvent("paneladded", this, panel);
36531 * Hides the tab for the specified panel.
36532 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36534 hidePanel : function(panel){
36535 if(this.tabs && (panel = this.getPanel(panel))){
36536 this.tabs.hideTab(panel.getEl().id);
36541 * Unhides the tab for a previously hidden panel.
36542 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36544 unhidePanel : function(panel){
36545 if(this.tabs && (panel = this.getPanel(panel))){
36546 this.tabs.unhideTab(panel.getEl().id);
36550 clearPanels : function(){
36551 while(this.panels.getCount() > 0){
36552 this.remove(this.panels.first());
36557 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36558 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36559 * @param {Boolean} preservePanel Overrides the config preservePanel option
36560 * @return {Roo.ContentPanel} The panel that was removed
36562 remove : function(panel, preservePanel)
36564 panel = this.getPanel(panel);
36569 this.fireEvent("beforeremove", this, panel, e);
36570 if(e.cancel === true){
36573 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36574 var panelId = panel.getId();
36575 this.panels.removeKey(panelId);
36577 document.body.appendChild(panel.getEl().dom);
36580 this.tabs.removeTab(panel.getEl().id);
36581 }else if (!preservePanel){
36582 this.bodyEl.dom.removeChild(panel.getEl().dom);
36584 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36585 var p = this.panels.first();
36586 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36587 tempEl.appendChild(p.getEl().dom);
36588 this.bodyEl.update("");
36589 this.bodyEl.dom.appendChild(p.getEl().dom);
36591 this.updateTitle(p.getTitle());
36593 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36594 this.setActivePanel(p);
36596 panel.setRegion(null);
36597 if(this.activePanel == panel){
36598 this.activePanel = null;
36600 if(this.config.autoDestroy !== false && preservePanel !== true){
36601 try{panel.destroy();}catch(e){}
36603 this.fireEvent("panelremoved", this, panel);
36608 * Returns the TabPanel component used by this region
36609 * @return {Roo.TabPanel}
36611 getTabs : function(){
36615 createTool : function(parentEl, className){
36616 var btn = Roo.DomHelper.append(parentEl, {
36618 cls: "x-layout-tools-button",
36621 cls: "roo-layout-tools-button-inner " + className,
36625 btn.addClassOnOver("roo-layout-tools-button-over");
36630 * Ext JS Library 1.1.1
36631 * Copyright(c) 2006-2007, Ext JS, LLC.
36633 * Originally Released Under LGPL - original licence link has changed is not relivant.
36636 * <script type="text/javascript">
36642 * @class Roo.SplitLayoutRegion
36643 * @extends Roo.LayoutRegion
36644 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36646 Roo.bootstrap.layout.Split = function(config){
36647 this.cursor = config.cursor;
36648 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36651 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36653 splitTip : "Drag to resize.",
36654 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36655 useSplitTips : false,
36657 applyConfig : function(config){
36658 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36661 onRender : function(ctr,pos) {
36663 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36664 if(!this.config.split){
36669 var splitEl = Roo.DomHelper.append(ctr.dom, {
36671 id: this.el.id + "-split",
36672 cls: "roo-layout-split roo-layout-split-"+this.position,
36675 /** The SplitBar for this region
36676 * @type Roo.SplitBar */
36677 // does not exist yet...
36678 Roo.log([this.position, this.orientation]);
36680 this.split = new Roo.bootstrap.SplitBar({
36681 dragElement : splitEl,
36682 resizingElement: this.el,
36683 orientation : this.orientation
36686 this.split.on("moved", this.onSplitMove, this);
36687 this.split.useShim = this.config.useShim === true;
36688 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36689 if(this.useSplitTips){
36690 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36692 //if(config.collapsible){
36693 // this.split.el.on("dblclick", this.collapse, this);
36696 if(typeof this.config.minSize != "undefined"){
36697 this.split.minSize = this.config.minSize;
36699 if(typeof this.config.maxSize != "undefined"){
36700 this.split.maxSize = this.config.maxSize;
36702 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36703 this.hideSplitter();
36708 getHMaxSize : function(){
36709 var cmax = this.config.maxSize || 10000;
36710 var center = this.mgr.getRegion("center");
36711 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36714 getVMaxSize : function(){
36715 var cmax = this.config.maxSize || 10000;
36716 var center = this.mgr.getRegion("center");
36717 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36720 onSplitMove : function(split, newSize){
36721 this.fireEvent("resized", this, newSize);
36725 * Returns the {@link Roo.SplitBar} for this region.
36726 * @return {Roo.SplitBar}
36728 getSplitBar : function(){
36733 this.hideSplitter();
36734 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36737 hideSplitter : function(){
36739 this.split.el.setLocation(-2000,-2000);
36740 this.split.el.hide();
36746 this.split.el.show();
36748 Roo.bootstrap.layout.Split.superclass.show.call(this);
36751 beforeSlide: function(){
36752 if(Roo.isGecko){// firefox overflow auto bug workaround
36753 this.bodyEl.clip();
36755 this.tabs.bodyEl.clip();
36757 if(this.activePanel){
36758 this.activePanel.getEl().clip();
36760 if(this.activePanel.beforeSlide){
36761 this.activePanel.beforeSlide();
36767 afterSlide : function(){
36768 if(Roo.isGecko){// firefox overflow auto bug workaround
36769 this.bodyEl.unclip();
36771 this.tabs.bodyEl.unclip();
36773 if(this.activePanel){
36774 this.activePanel.getEl().unclip();
36775 if(this.activePanel.afterSlide){
36776 this.activePanel.afterSlide();
36782 initAutoHide : function(){
36783 if(this.autoHide !== false){
36784 if(!this.autoHideHd){
36785 var st = new Roo.util.DelayedTask(this.slideIn, this);
36786 this.autoHideHd = {
36787 "mouseout": function(e){
36788 if(!e.within(this.el, true)){
36792 "mouseover" : function(e){
36798 this.el.on(this.autoHideHd);
36802 clearAutoHide : function(){
36803 if(this.autoHide !== false){
36804 this.el.un("mouseout", this.autoHideHd.mouseout);
36805 this.el.un("mouseover", this.autoHideHd.mouseover);
36809 clearMonitor : function(){
36810 Roo.get(document).un("click", this.slideInIf, this);
36813 // these names are backwards but not changed for compat
36814 slideOut : function(){
36815 if(this.isSlid || this.el.hasActiveFx()){
36818 this.isSlid = true;
36819 if(this.collapseBtn){
36820 this.collapseBtn.hide();
36822 this.closeBtnState = this.closeBtn.getStyle('display');
36823 this.closeBtn.hide();
36825 this.stickBtn.show();
36828 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36829 this.beforeSlide();
36830 this.el.setStyle("z-index", 10001);
36831 this.el.slideIn(this.getSlideAnchor(), {
36832 callback: function(){
36834 this.initAutoHide();
36835 Roo.get(document).on("click", this.slideInIf, this);
36836 this.fireEvent("slideshow", this);
36843 afterSlideIn : function(){
36844 this.clearAutoHide();
36845 this.isSlid = false;
36846 this.clearMonitor();
36847 this.el.setStyle("z-index", "");
36848 if(this.collapseBtn){
36849 this.collapseBtn.show();
36851 this.closeBtn.setStyle('display', this.closeBtnState);
36853 this.stickBtn.hide();
36855 this.fireEvent("slidehide", this);
36858 slideIn : function(cb){
36859 if(!this.isSlid || this.el.hasActiveFx()){
36863 this.isSlid = false;
36864 this.beforeSlide();
36865 this.el.slideOut(this.getSlideAnchor(), {
36866 callback: function(){
36867 this.el.setLeftTop(-10000, -10000);
36869 this.afterSlideIn();
36877 slideInIf : function(e){
36878 if(!e.within(this.el)){
36883 animateCollapse : function(){
36884 this.beforeSlide();
36885 this.el.setStyle("z-index", 20000);
36886 var anchor = this.getSlideAnchor();
36887 this.el.slideOut(anchor, {
36888 callback : function(){
36889 this.el.setStyle("z-index", "");
36890 this.collapsedEl.slideIn(anchor, {duration:.3});
36892 this.el.setLocation(-10000,-10000);
36894 this.fireEvent("collapsed", this);
36901 animateExpand : function(){
36902 this.beforeSlide();
36903 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36904 this.el.setStyle("z-index", 20000);
36905 this.collapsedEl.hide({
36908 this.el.slideIn(this.getSlideAnchor(), {
36909 callback : function(){
36910 this.el.setStyle("z-index", "");
36913 this.split.el.show();
36915 this.fireEvent("invalidated", this);
36916 this.fireEvent("expanded", this);
36944 getAnchor : function(){
36945 return this.anchors[this.position];
36948 getCollapseAnchor : function(){
36949 return this.canchors[this.position];
36952 getSlideAnchor : function(){
36953 return this.sanchors[this.position];
36956 getAlignAdj : function(){
36957 var cm = this.cmargins;
36958 switch(this.position){
36974 getExpandAdj : function(){
36975 var c = this.collapsedEl, cm = this.cmargins;
36976 switch(this.position){
36978 return [-(cm.right+c.getWidth()+cm.left), 0];
36981 return [cm.right+c.getWidth()+cm.left, 0];
36984 return [0, -(cm.top+cm.bottom+c.getHeight())];
36987 return [0, cm.top+cm.bottom+c.getHeight()];
36993 * Ext JS Library 1.1.1
36994 * Copyright(c) 2006-2007, Ext JS, LLC.
36996 * Originally Released Under LGPL - original licence link has changed is not relivant.
36999 * <script type="text/javascript">
37002 * These classes are private internal classes
37004 Roo.bootstrap.layout.Center = function(config){
37005 config.region = "center";
37006 Roo.bootstrap.layout.Region.call(this, config);
37007 this.visible = true;
37008 this.minWidth = config.minWidth || 20;
37009 this.minHeight = config.minHeight || 20;
37012 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37014 // center panel can't be hidden
37018 // center panel can't be hidden
37021 getMinWidth: function(){
37022 return this.minWidth;
37025 getMinHeight: function(){
37026 return this.minHeight;
37040 Roo.bootstrap.layout.North = function(config)
37042 config.region = 'north';
37043 config.cursor = 'n-resize';
37045 Roo.bootstrap.layout.Split.call(this, config);
37049 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37050 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37051 this.split.el.addClass("roo-layout-split-v");
37053 var size = config.initialSize || config.height;
37054 if(typeof size != "undefined"){
37055 this.el.setHeight(size);
37058 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37060 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37064 getBox : function(){
37065 if(this.collapsed){
37066 return this.collapsedEl.getBox();
37068 var box = this.el.getBox();
37070 box.height += this.split.el.getHeight();
37075 updateBox : function(box){
37076 if(this.split && !this.collapsed){
37077 box.height -= this.split.el.getHeight();
37078 this.split.el.setLeft(box.x);
37079 this.split.el.setTop(box.y+box.height);
37080 this.split.el.setWidth(box.width);
37082 if(this.collapsed){
37083 this.updateBody(box.width, null);
37085 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37093 Roo.bootstrap.layout.South = function(config){
37094 config.region = 'south';
37095 config.cursor = 's-resize';
37096 Roo.bootstrap.layout.Split.call(this, config);
37098 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37099 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37100 this.split.el.addClass("roo-layout-split-v");
37102 var size = config.initialSize || config.height;
37103 if(typeof size != "undefined"){
37104 this.el.setHeight(size);
37108 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37109 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37110 getBox : function(){
37111 if(this.collapsed){
37112 return this.collapsedEl.getBox();
37114 var box = this.el.getBox();
37116 var sh = this.split.el.getHeight();
37123 updateBox : function(box){
37124 if(this.split && !this.collapsed){
37125 var sh = this.split.el.getHeight();
37128 this.split.el.setLeft(box.x);
37129 this.split.el.setTop(box.y-sh);
37130 this.split.el.setWidth(box.width);
37132 if(this.collapsed){
37133 this.updateBody(box.width, null);
37135 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37139 Roo.bootstrap.layout.East = function(config){
37140 config.region = "east";
37141 config.cursor = "e-resize";
37142 Roo.bootstrap.layout.Split.call(this, config);
37144 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37145 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37146 this.split.el.addClass("roo-layout-split-h");
37148 var size = config.initialSize || config.width;
37149 if(typeof size != "undefined"){
37150 this.el.setWidth(size);
37153 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37154 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37155 getBox : function(){
37156 if(this.collapsed){
37157 return this.collapsedEl.getBox();
37159 var box = this.el.getBox();
37161 var sw = this.split.el.getWidth();
37168 updateBox : function(box){
37169 if(this.split && !this.collapsed){
37170 var sw = this.split.el.getWidth();
37172 this.split.el.setLeft(box.x);
37173 this.split.el.setTop(box.y);
37174 this.split.el.setHeight(box.height);
37177 if(this.collapsed){
37178 this.updateBody(null, box.height);
37180 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37184 Roo.bootstrap.layout.West = function(config){
37185 config.region = "west";
37186 config.cursor = "w-resize";
37188 Roo.bootstrap.layout.Split.call(this, config);
37190 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37191 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37192 this.split.el.addClass("roo-layout-split-h");
37196 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37197 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37199 onRender: function(ctr, pos)
37201 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37202 var size = this.config.initialSize || this.config.width;
37203 if(typeof size != "undefined"){
37204 this.el.setWidth(size);
37208 getBox : function(){
37209 if(this.collapsed){
37210 return this.collapsedEl.getBox();
37212 var box = this.el.getBox();
37214 box.width += this.split.el.getWidth();
37219 updateBox : function(box){
37220 if(this.split && !this.collapsed){
37221 var sw = this.split.el.getWidth();
37223 this.split.el.setLeft(box.x+box.width);
37224 this.split.el.setTop(box.y);
37225 this.split.el.setHeight(box.height);
37227 if(this.collapsed){
37228 this.updateBody(null, box.height);
37230 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37232 });Roo.namespace("Roo.bootstrap.panel");/*
37234 * Ext JS Library 1.1.1
37235 * Copyright(c) 2006-2007, Ext JS, LLC.
37237 * Originally Released Under LGPL - original licence link has changed is not relivant.
37240 * <script type="text/javascript">
37243 * @class Roo.ContentPanel
37244 * @extends Roo.util.Observable
37245 * A basic ContentPanel element.
37246 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37247 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37248 * @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
37249 * @cfg {Boolean} closable True if the panel can be closed/removed
37250 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37251 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37252 * @cfg {Toolbar} toolbar A toolbar for this panel
37253 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37254 * @cfg {String} title The title for this panel
37255 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37256 * @cfg {String} url Calls {@link #setUrl} with this value
37257 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37258 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37259 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37260 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37261 * @cfg {Boolean} badges render the badges
37264 * Create a new ContentPanel.
37265 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37266 * @param {String/Object} config A string to set only the title or a config object
37267 * @param {String} content (optional) Set the HTML content for this panel
37268 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37270 Roo.bootstrap.panel.Content = function( config){
37272 this.tpl = config.tpl || false;
37274 var el = config.el;
37275 var content = config.content;
37277 if(config.autoCreate){ // xtype is available if this is called from factory
37280 this.el = Roo.get(el);
37281 if(!this.el && config && config.autoCreate){
37282 if(typeof config.autoCreate == "object"){
37283 if(!config.autoCreate.id){
37284 config.autoCreate.id = config.id||el;
37286 this.el = Roo.DomHelper.append(document.body,
37287 config.autoCreate, true);
37289 var elcfg = { tag: "div",
37290 cls: "roo-layout-inactive-content",
37294 elcfg.html = config.html;
37298 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37301 this.closable = false;
37302 this.loaded = false;
37303 this.active = false;
37306 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37308 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37310 this.wrapEl = this.el; //this.el.wrap();
37312 if (config.toolbar.items) {
37313 ti = config.toolbar.items ;
37314 delete config.toolbar.items ;
37318 this.toolbar.render(this.wrapEl, 'before');
37319 for(var i =0;i < ti.length;i++) {
37320 // Roo.log(['add child', items[i]]);
37321 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37323 this.toolbar.items = nitems;
37324 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37325 delete config.toolbar;
37329 // xtype created footer. - not sure if will work as we normally have to render first..
37330 if (this.footer && !this.footer.el && this.footer.xtype) {
37331 if (!this.wrapEl) {
37332 this.wrapEl = this.el.wrap();
37335 this.footer.container = this.wrapEl.createChild();
37337 this.footer = Roo.factory(this.footer, Roo);
37342 if(typeof config == "string"){
37343 this.title = config;
37345 Roo.apply(this, config);
37349 this.resizeEl = Roo.get(this.resizeEl, true);
37351 this.resizeEl = this.el;
37353 // handle view.xtype
37361 * Fires when this panel is activated.
37362 * @param {Roo.ContentPanel} this
37366 * @event deactivate
37367 * Fires when this panel is activated.
37368 * @param {Roo.ContentPanel} this
37370 "deactivate" : true,
37374 * Fires when this panel is resized if fitToFrame is true.
37375 * @param {Roo.ContentPanel} this
37376 * @param {Number} width The width after any component adjustments
37377 * @param {Number} height The height after any component adjustments
37383 * Fires when this tab is created
37384 * @param {Roo.ContentPanel} this
37395 if(this.autoScroll){
37396 this.resizeEl.setStyle("overflow", "auto");
37398 // fix randome scrolling
37399 //this.el.on('scroll', function() {
37400 // Roo.log('fix random scolling');
37401 // this.scrollTo('top',0);
37404 content = content || this.content;
37406 this.setContent(content);
37408 if(config && config.url){
37409 this.setUrl(this.url, this.params, this.loadOnce);
37414 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37416 if (this.view && typeof(this.view.xtype) != 'undefined') {
37417 this.view.el = this.el.appendChild(document.createElement("div"));
37418 this.view = Roo.factory(this.view);
37419 this.view.render && this.view.render(false, '');
37423 this.fireEvent('render', this);
37426 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37430 setRegion : function(region){
37431 this.region = region;
37432 this.setActiveClass(region && !this.background);
37436 setActiveClass: function(state)
37439 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37440 this.el.setStyle('position','relative');
37442 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37443 this.el.setStyle('position', 'absolute');
37448 * Returns the toolbar for this Panel if one was configured.
37449 * @return {Roo.Toolbar}
37451 getToolbar : function(){
37452 return this.toolbar;
37455 setActiveState : function(active)
37457 this.active = active;
37458 this.setActiveClass(active);
37460 if(this.fireEvent("deactivate", this) === false){
37465 this.fireEvent("activate", this);
37469 * Updates this panel's element
37470 * @param {String} content The new content
37471 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37473 setContent : function(content, loadScripts){
37474 this.el.update(content, loadScripts);
37477 ignoreResize : function(w, h){
37478 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37481 this.lastSize = {width: w, height: h};
37486 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37487 * @return {Roo.UpdateManager} The UpdateManager
37489 getUpdateManager : function(){
37490 return this.el.getUpdateManager();
37493 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37494 * @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:
37497 url: "your-url.php",
37498 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37499 callback: yourFunction,
37500 scope: yourObject, //(optional scope)
37503 text: "Loading...",
37508 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37509 * 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.
37510 * @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}
37511 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37512 * @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.
37513 * @return {Roo.ContentPanel} this
37516 var um = this.el.getUpdateManager();
37517 um.update.apply(um, arguments);
37523 * 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.
37524 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37525 * @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)
37526 * @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)
37527 * @return {Roo.UpdateManager} The UpdateManager
37529 setUrl : function(url, params, loadOnce){
37530 if(this.refreshDelegate){
37531 this.removeListener("activate", this.refreshDelegate);
37533 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37534 this.on("activate", this.refreshDelegate);
37535 return this.el.getUpdateManager();
37538 _handleRefresh : function(url, params, loadOnce){
37539 if(!loadOnce || !this.loaded){
37540 var updater = this.el.getUpdateManager();
37541 updater.update(url, params, this._setLoaded.createDelegate(this));
37545 _setLoaded : function(){
37546 this.loaded = true;
37550 * Returns this panel's id
37553 getId : function(){
37558 * Returns this panel's element - used by regiosn to add.
37559 * @return {Roo.Element}
37561 getEl : function(){
37562 return this.wrapEl || this.el;
37567 adjustForComponents : function(width, height)
37569 //Roo.log('adjustForComponents ');
37570 if(this.resizeEl != this.el){
37571 width -= this.el.getFrameWidth('lr');
37572 height -= this.el.getFrameWidth('tb');
37575 var te = this.toolbar.getEl();
37576 te.setWidth(width);
37577 height -= te.getHeight();
37580 var te = this.footer.getEl();
37581 te.setWidth(width);
37582 height -= te.getHeight();
37586 if(this.adjustments){
37587 width += this.adjustments[0];
37588 height += this.adjustments[1];
37590 return {"width": width, "height": height};
37593 setSize : function(width, height){
37594 if(this.fitToFrame && !this.ignoreResize(width, height)){
37595 if(this.fitContainer && this.resizeEl != this.el){
37596 this.el.setSize(width, height);
37598 var size = this.adjustForComponents(width, height);
37599 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37600 this.fireEvent('resize', this, size.width, size.height);
37605 * Returns this panel's title
37608 getTitle : function(){
37610 if (typeof(this.title) != 'object') {
37615 for (var k in this.title) {
37616 if (!this.title.hasOwnProperty(k)) {
37620 if (k.indexOf('-') >= 0) {
37621 var s = k.split('-');
37622 for (var i = 0; i<s.length; i++) {
37623 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37626 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37633 * Set this panel's title
37634 * @param {String} title
37636 setTitle : function(title){
37637 this.title = title;
37639 this.region.updatePanelTitle(this, title);
37644 * Returns true is this panel was configured to be closable
37645 * @return {Boolean}
37647 isClosable : function(){
37648 return this.closable;
37651 beforeSlide : function(){
37653 this.resizeEl.clip();
37656 afterSlide : function(){
37658 this.resizeEl.unclip();
37662 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37663 * Will fail silently if the {@link #setUrl} method has not been called.
37664 * This does not activate the panel, just updates its content.
37666 refresh : function(){
37667 if(this.refreshDelegate){
37668 this.loaded = false;
37669 this.refreshDelegate();
37674 * Destroys this panel
37676 destroy : function(){
37677 this.el.removeAllListeners();
37678 var tempEl = document.createElement("span");
37679 tempEl.appendChild(this.el.dom);
37680 tempEl.innerHTML = "";
37686 * form - if the content panel contains a form - this is a reference to it.
37687 * @type {Roo.form.Form}
37691 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37692 * This contains a reference to it.
37698 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37708 * @param {Object} cfg Xtype definition of item to add.
37712 getChildContainer: function () {
37713 return this.getEl();
37718 var ret = new Roo.factory(cfg);
37723 if (cfg.xtype.match(/^Form$/)) {
37726 //if (this.footer) {
37727 // el = this.footer.container.insertSibling(false, 'before');
37729 el = this.el.createChild();
37732 this.form = new Roo.form.Form(cfg);
37735 if ( this.form.allItems.length) {
37736 this.form.render(el.dom);
37740 // should only have one of theses..
37741 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37742 // views.. should not be just added - used named prop 'view''
37744 cfg.el = this.el.appendChild(document.createElement("div"));
37747 var ret = new Roo.factory(cfg);
37749 ret.render && ret.render(false, ''); // render blank..
37759 * @class Roo.bootstrap.panel.Grid
37760 * @extends Roo.bootstrap.panel.Content
37762 * Create a new GridPanel.
37763 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37764 * @param {Object} config A the config object
37770 Roo.bootstrap.panel.Grid = function(config)
37774 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37775 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37777 config.el = this.wrapper;
37778 //this.el = this.wrapper;
37780 if (config.container) {
37781 // ctor'ed from a Border/panel.grid
37784 this.wrapper.setStyle("overflow", "hidden");
37785 this.wrapper.addClass('roo-grid-container');
37790 if(config.toolbar){
37791 var tool_el = this.wrapper.createChild();
37792 this.toolbar = Roo.factory(config.toolbar);
37794 if (config.toolbar.items) {
37795 ti = config.toolbar.items ;
37796 delete config.toolbar.items ;
37800 this.toolbar.render(tool_el);
37801 for(var i =0;i < ti.length;i++) {
37802 // Roo.log(['add child', items[i]]);
37803 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37805 this.toolbar.items = nitems;
37807 delete config.toolbar;
37810 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37811 config.grid.scrollBody = true;;
37812 config.grid.monitorWindowResize = false; // turn off autosizing
37813 config.grid.autoHeight = false;
37814 config.grid.autoWidth = false;
37816 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37818 if (config.background) {
37819 // render grid on panel activation (if panel background)
37820 this.on('activate', function(gp) {
37821 if (!gp.grid.rendered) {
37822 gp.grid.render(this.wrapper);
37823 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37828 this.grid.render(this.wrapper);
37829 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37832 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37833 // ??? needed ??? config.el = this.wrapper;
37838 // xtype created footer. - not sure if will work as we normally have to render first..
37839 if (this.footer && !this.footer.el && this.footer.xtype) {
37841 var ctr = this.grid.getView().getFooterPanel(true);
37842 this.footer.dataSource = this.grid.dataSource;
37843 this.footer = Roo.factory(this.footer, Roo);
37844 this.footer.render(ctr);
37854 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37855 getId : function(){
37856 return this.grid.id;
37860 * Returns the grid for this panel
37861 * @return {Roo.bootstrap.Table}
37863 getGrid : function(){
37867 setSize : function(width, height){
37868 if(!this.ignoreResize(width, height)){
37869 var grid = this.grid;
37870 var size = this.adjustForComponents(width, height);
37871 var gridel = grid.getGridEl();
37872 gridel.setSize(size.width, size.height);
37874 var thd = grid.getGridEl().select('thead',true).first();
37875 var tbd = grid.getGridEl().select('tbody', true).first();
37877 tbd.setSize(width, height - thd.getHeight());
37886 beforeSlide : function(){
37887 this.grid.getView().scroller.clip();
37890 afterSlide : function(){
37891 this.grid.getView().scroller.unclip();
37894 destroy : function(){
37895 this.grid.destroy();
37897 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37902 * @class Roo.bootstrap.panel.Nest
37903 * @extends Roo.bootstrap.panel.Content
37905 * Create a new Panel, that can contain a layout.Border.
37908 * @param {Roo.BorderLayout} layout The layout for this panel
37909 * @param {String/Object} config A string to set only the title or a config object
37911 Roo.bootstrap.panel.Nest = function(config)
37913 // construct with only one argument..
37914 /* FIXME - implement nicer consturctors
37915 if (layout.layout) {
37917 layout = config.layout;
37918 delete config.layout;
37920 if (layout.xtype && !layout.getEl) {
37921 // then layout needs constructing..
37922 layout = Roo.factory(layout, Roo);
37926 config.el = config.layout.getEl();
37928 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37930 config.layout.monitorWindowResize = false; // turn off autosizing
37931 this.layout = config.layout;
37932 this.layout.getEl().addClass("roo-layout-nested-layout");
37933 this.layout.parent = this;
37940 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37942 setSize : function(width, height){
37943 if(!this.ignoreResize(width, height)){
37944 var size = this.adjustForComponents(width, height);
37945 var el = this.layout.getEl();
37946 if (size.height < 1) {
37947 el.setWidth(size.width);
37949 el.setSize(size.width, size.height);
37951 var touch = el.dom.offsetWidth;
37952 this.layout.layout();
37953 // ie requires a double layout on the first pass
37954 if(Roo.isIE && !this.initialized){
37955 this.initialized = true;
37956 this.layout.layout();
37961 // activate all subpanels if not currently active..
37963 setActiveState : function(active){
37964 this.active = active;
37965 this.setActiveClass(active);
37968 this.fireEvent("deactivate", this);
37972 this.fireEvent("activate", this);
37973 // not sure if this should happen before or after..
37974 if (!this.layout) {
37975 return; // should not happen..
37978 for (var r in this.layout.regions) {
37979 reg = this.layout.getRegion(r);
37980 if (reg.getActivePanel()) {
37981 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37982 reg.setActivePanel(reg.getActivePanel());
37985 if (!reg.panels.length) {
37988 reg.showPanel(reg.getPanel(0));
37997 * Returns the nested BorderLayout for this panel
37998 * @return {Roo.BorderLayout}
38000 getLayout : function(){
38001 return this.layout;
38005 * Adds a xtype elements to the layout of the nested panel
38009 xtype : 'ContentPanel',
38016 xtype : 'NestedLayoutPanel',
38022 items : [ ... list of content panels or nested layout panels.. ]
38026 * @param {Object} cfg Xtype definition of item to add.
38028 addxtype : function(cfg) {
38029 return this.layout.addxtype(cfg);
38034 * Ext JS Library 1.1.1
38035 * Copyright(c) 2006-2007, Ext JS, LLC.
38037 * Originally Released Under LGPL - original licence link has changed is not relivant.
38040 * <script type="text/javascript">
38043 * @class Roo.TabPanel
38044 * @extends Roo.util.Observable
38045 * A lightweight tab container.
38049 // basic tabs 1, built from existing content
38050 var tabs = new Roo.TabPanel("tabs1");
38051 tabs.addTab("script", "View Script");
38052 tabs.addTab("markup", "View Markup");
38053 tabs.activate("script");
38055 // more advanced tabs, built from javascript
38056 var jtabs = new Roo.TabPanel("jtabs");
38057 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38059 // set up the UpdateManager
38060 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38061 var updater = tab2.getUpdateManager();
38062 updater.setDefaultUrl("ajax1.htm");
38063 tab2.on('activate', updater.refresh, updater, true);
38065 // Use setUrl for Ajax loading
38066 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38067 tab3.setUrl("ajax2.htm", null, true);
38070 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38073 jtabs.activate("jtabs-1");
38076 * Create a new TabPanel.
38077 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38078 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38080 Roo.bootstrap.panel.Tabs = function(config){
38082 * The container element for this TabPanel.
38083 * @type Roo.Element
38085 this.el = Roo.get(config.el);
38088 if(typeof config == "boolean"){
38089 this.tabPosition = config ? "bottom" : "top";
38091 Roo.apply(this, config);
38095 if(this.tabPosition == "bottom"){
38096 // if tabs are at the bottom = create the body first.
38097 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38098 this.el.addClass("roo-tabs-bottom");
38100 // next create the tabs holders
38102 if (this.tabPosition == "west"){
38104 var reg = this.region; // fake it..
38106 if (!reg.mgr.parent) {
38109 reg = reg.mgr.parent.region;
38111 Roo.log("got nest?");
38113 if (reg.mgr.getRegion('west')) {
38114 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38115 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38116 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38117 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38118 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38126 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38127 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38128 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38129 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38134 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38137 // finally - if tabs are at the top, then create the body last..
38138 if(this.tabPosition != "bottom"){
38139 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38140 * @type Roo.Element
38142 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38143 this.el.addClass("roo-tabs-top");
38147 this.bodyEl.setStyle("position", "relative");
38149 this.active = null;
38150 this.activateDelegate = this.activate.createDelegate(this);
38155 * Fires when the active tab changes
38156 * @param {Roo.TabPanel} this
38157 * @param {Roo.TabPanelItem} activePanel The new active tab
38161 * @event beforetabchange
38162 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38163 * @param {Roo.TabPanel} this
38164 * @param {Object} e Set cancel to true on this object to cancel the tab change
38165 * @param {Roo.TabPanelItem} tab The tab being changed to
38167 "beforetabchange" : true
38170 Roo.EventManager.onWindowResize(this.onResize, this);
38171 this.cpad = this.el.getPadding("lr");
38172 this.hiddenCount = 0;
38175 // toolbar on the tabbar support...
38176 if (this.toolbar) {
38177 alert("no toolbar support yet");
38178 this.toolbar = false;
38180 var tcfg = this.toolbar;
38181 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38182 this.toolbar = new Roo.Toolbar(tcfg);
38183 if (Roo.isSafari) {
38184 var tbl = tcfg.container.child('table', true);
38185 tbl.setAttribute('width', '100%');
38193 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38196 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38198 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38200 tabPosition : "top",
38202 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38204 currentTabWidth : 0,
38206 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38210 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38214 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38216 preferredTabWidth : 175,
38218 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38220 resizeTabs : false,
38222 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38224 monitorResize : true,
38226 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38228 toolbar : false, // set by caller..
38230 region : false, /// set by caller
38232 disableTooltips : true, // not used yet...
38235 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38236 * @param {String} id The id of the div to use <b>or create</b>
38237 * @param {String} text The text for the tab
38238 * @param {String} content (optional) Content to put in the TabPanelItem body
38239 * @param {Boolean} closable (optional) True to create a close icon on the tab
38240 * @return {Roo.TabPanelItem} The created TabPanelItem
38242 addTab : function(id, text, content, closable, tpl)
38244 var item = new Roo.bootstrap.panel.TabItem({
38248 closable : closable,
38251 this.addTabItem(item);
38253 item.setContent(content);
38259 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38260 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38261 * @return {Roo.TabPanelItem}
38263 getTab : function(id){
38264 return this.items[id];
38268 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38269 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38271 hideTab : function(id){
38272 var t = this.items[id];
38275 this.hiddenCount++;
38276 this.autoSizeTabs();
38281 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38282 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38284 unhideTab : function(id){
38285 var t = this.items[id];
38287 t.setHidden(false);
38288 this.hiddenCount--;
38289 this.autoSizeTabs();
38294 * Adds an existing {@link Roo.TabPanelItem}.
38295 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38297 addTabItem : function(item)
38299 this.items[item.id] = item;
38300 this.items.push(item);
38301 this.autoSizeTabs();
38302 // if(this.resizeTabs){
38303 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38304 // this.autoSizeTabs();
38306 // item.autoSize();
38311 * Removes a {@link Roo.TabPanelItem}.
38312 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38314 removeTab : function(id){
38315 var items = this.items;
38316 var tab = items[id];
38317 if(!tab) { return; }
38318 var index = items.indexOf(tab);
38319 if(this.active == tab && items.length > 1){
38320 var newTab = this.getNextAvailable(index);
38325 this.stripEl.dom.removeChild(tab.pnode.dom);
38326 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38327 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38329 items.splice(index, 1);
38330 delete this.items[tab.id];
38331 tab.fireEvent("close", tab);
38332 tab.purgeListeners();
38333 this.autoSizeTabs();
38336 getNextAvailable : function(start){
38337 var items = this.items;
38339 // look for a next tab that will slide over to
38340 // replace the one being removed
38341 while(index < items.length){
38342 var item = items[++index];
38343 if(item && !item.isHidden()){
38347 // if one isn't found select the previous tab (on the left)
38350 var item = items[--index];
38351 if(item && !item.isHidden()){
38359 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38360 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38362 disableTab : function(id){
38363 var tab = this.items[id];
38364 if(tab && this.active != tab){
38370 * Enables a {@link Roo.TabPanelItem} that is disabled.
38371 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38373 enableTab : function(id){
38374 var tab = this.items[id];
38379 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38380 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38381 * @return {Roo.TabPanelItem} The TabPanelItem.
38383 activate : function(id)
38385 //Roo.log('activite:' + id);
38387 var tab = this.items[id];
38391 if(tab == this.active || tab.disabled){
38395 this.fireEvent("beforetabchange", this, e, tab);
38396 if(e.cancel !== true && !tab.disabled){
38398 this.active.hide();
38400 this.active = this.items[id];
38401 this.active.show();
38402 this.fireEvent("tabchange", this, this.active);
38408 * Gets the active {@link Roo.TabPanelItem}.
38409 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38411 getActiveTab : function(){
38412 return this.active;
38416 * Updates the tab body element to fit the height of the container element
38417 * for overflow scrolling
38418 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38420 syncHeight : function(targetHeight){
38421 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38422 var bm = this.bodyEl.getMargins();
38423 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38424 this.bodyEl.setHeight(newHeight);
38428 onResize : function(){
38429 if(this.monitorResize){
38430 this.autoSizeTabs();
38435 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38437 beginUpdate : function(){
38438 this.updating = true;
38442 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38444 endUpdate : function(){
38445 this.updating = false;
38446 this.autoSizeTabs();
38450 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38452 autoSizeTabs : function()
38454 var count = this.items.length;
38455 var vcount = count - this.hiddenCount;
38458 this.stripEl.hide();
38460 this.stripEl.show();
38463 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38468 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38469 var availWidth = Math.floor(w / vcount);
38470 var b = this.stripBody;
38471 if(b.getWidth() > w){
38472 var tabs = this.items;
38473 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38474 if(availWidth < this.minTabWidth){
38475 /*if(!this.sleft){ // incomplete scrolling code
38476 this.createScrollButtons();
38479 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38482 if(this.currentTabWidth < this.preferredTabWidth){
38483 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38489 * Returns the number of tabs in this TabPanel.
38492 getCount : function(){
38493 return this.items.length;
38497 * Resizes all the tabs to the passed width
38498 * @param {Number} The new width
38500 setTabWidth : function(width){
38501 this.currentTabWidth = width;
38502 for(var i = 0, len = this.items.length; i < len; i++) {
38503 if(!this.items[i].isHidden()) {
38504 this.items[i].setWidth(width);
38510 * Destroys this TabPanel
38511 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38513 destroy : function(removeEl){
38514 Roo.EventManager.removeResizeListener(this.onResize, this);
38515 for(var i = 0, len = this.items.length; i < len; i++){
38516 this.items[i].purgeListeners();
38518 if(removeEl === true){
38519 this.el.update("");
38524 createStrip : function(container)
38526 var strip = document.createElement("nav");
38527 strip.className = Roo.bootstrap.version == 4 ?
38528 "navbar-light bg-light" :
38529 "navbar navbar-default"; //"x-tabs-wrap";
38530 container.appendChild(strip);
38534 createStripList : function(strip)
38536 // div wrapper for retard IE
38537 // returns the "tr" element.
38538 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38539 //'<div class="x-tabs-strip-wrap">'+
38540 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38541 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38542 return strip.firstChild; //.firstChild.firstChild.firstChild;
38544 createBody : function(container)
38546 var body = document.createElement("div");
38547 Roo.id(body, "tab-body");
38548 //Roo.fly(body).addClass("x-tabs-body");
38549 Roo.fly(body).addClass("tab-content");
38550 container.appendChild(body);
38553 createItemBody :function(bodyEl, id){
38554 var body = Roo.getDom(id);
38556 body = document.createElement("div");
38559 //Roo.fly(body).addClass("x-tabs-item-body");
38560 Roo.fly(body).addClass("tab-pane");
38561 bodyEl.insertBefore(body, bodyEl.firstChild);
38565 createStripElements : function(stripEl, text, closable, tpl)
38567 var td = document.createElement("li"); // was td..
38568 td.className = 'nav-item';
38570 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38573 stripEl.appendChild(td);
38575 td.className = "x-tabs-closable";
38576 if(!this.closeTpl){
38577 this.closeTpl = new Roo.Template(
38578 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38579 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38580 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38583 var el = this.closeTpl.overwrite(td, {"text": text});
38584 var close = el.getElementsByTagName("div")[0];
38585 var inner = el.getElementsByTagName("em")[0];
38586 return {"el": el, "close": close, "inner": inner};
38589 // not sure what this is..
38590 // if(!this.tabTpl){
38591 //this.tabTpl = new Roo.Template(
38592 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38593 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38595 // this.tabTpl = new Roo.Template(
38596 // '<a href="#">' +
38597 // '<span unselectable="on"' +
38598 // (this.disableTooltips ? '' : ' title="{text}"') +
38599 // ' >{text}</span></a>'
38605 var template = tpl || this.tabTpl || false;
38608 template = new Roo.Template(
38609 Roo.bootstrap.version == 4 ?
38611 '<a class="nav-link" href="#" unselectable="on"' +
38612 (this.disableTooltips ? '' : ' title="{text}"') +
38615 '<a class="nav-link" href="#">' +
38616 '<span unselectable="on"' +
38617 (this.disableTooltips ? '' : ' title="{text}"') +
38618 ' >{text}</span></a>'
38623 switch (typeof(template)) {
38627 template = new Roo.Template(template);
38633 var el = template.overwrite(td, {"text": text});
38635 var inner = el.getElementsByTagName("span")[0];
38637 return {"el": el, "inner": inner};
38645 * @class Roo.TabPanelItem
38646 * @extends Roo.util.Observable
38647 * Represents an individual item (tab plus body) in a TabPanel.
38648 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38649 * @param {String} id The id of this TabPanelItem
38650 * @param {String} text The text for the tab of this TabPanelItem
38651 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38653 Roo.bootstrap.panel.TabItem = function(config){
38655 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38656 * @type Roo.TabPanel
38658 this.tabPanel = config.panel;
38660 * The id for this TabPanelItem
38663 this.id = config.id;
38665 this.disabled = false;
38667 this.text = config.text;
38669 this.loaded = false;
38670 this.closable = config.closable;
38673 * The body element for this TabPanelItem.
38674 * @type Roo.Element
38676 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38677 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38678 this.bodyEl.setStyle("display", "block");
38679 this.bodyEl.setStyle("zoom", "1");
38680 //this.hideAction();
38682 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38684 this.el = Roo.get(els.el);
38685 this.inner = Roo.get(els.inner, true);
38686 this.textEl = Roo.bootstrap.version == 4 ?
38687 this.el : Roo.get(this.el.dom.firstChild, true);
38689 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38690 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38693 // this.el.on("mousedown", this.onTabMouseDown, this);
38694 this.el.on("click", this.onTabClick, this);
38696 if(config.closable){
38697 var c = Roo.get(els.close, true);
38698 c.dom.title = this.closeText;
38699 c.addClassOnOver("close-over");
38700 c.on("click", this.closeClick, this);
38706 * Fires when this tab becomes the active tab.
38707 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38708 * @param {Roo.TabPanelItem} this
38712 * @event beforeclose
38713 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38714 * @param {Roo.TabPanelItem} this
38715 * @param {Object} e Set cancel to true on this object to cancel the close.
38717 "beforeclose": true,
38720 * Fires when this tab is closed.
38721 * @param {Roo.TabPanelItem} this
38725 * @event deactivate
38726 * Fires when this tab is no longer the active tab.
38727 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38728 * @param {Roo.TabPanelItem} this
38730 "deactivate" : true
38732 this.hidden = false;
38734 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38737 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38739 purgeListeners : function(){
38740 Roo.util.Observable.prototype.purgeListeners.call(this);
38741 this.el.removeAllListeners();
38744 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38747 this.status_node.addClass("active");
38750 this.tabPanel.stripWrap.repaint();
38752 this.fireEvent("activate", this.tabPanel, this);
38756 * Returns true if this tab is the active tab.
38757 * @return {Boolean}
38759 isActive : function(){
38760 return this.tabPanel.getActiveTab() == this;
38764 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38767 this.status_node.removeClass("active");
38769 this.fireEvent("deactivate", this.tabPanel, this);
38772 hideAction : function(){
38773 this.bodyEl.hide();
38774 this.bodyEl.setStyle("position", "absolute");
38775 this.bodyEl.setLeft("-20000px");
38776 this.bodyEl.setTop("-20000px");
38779 showAction : function(){
38780 this.bodyEl.setStyle("position", "relative");
38781 this.bodyEl.setTop("");
38782 this.bodyEl.setLeft("");
38783 this.bodyEl.show();
38787 * Set the tooltip for the tab.
38788 * @param {String} tooltip The tab's tooltip
38790 setTooltip : function(text){
38791 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38792 this.textEl.dom.qtip = text;
38793 this.textEl.dom.removeAttribute('title');
38795 this.textEl.dom.title = text;
38799 onTabClick : function(e){
38800 e.preventDefault();
38801 this.tabPanel.activate(this.id);
38804 onTabMouseDown : function(e){
38805 e.preventDefault();
38806 this.tabPanel.activate(this.id);
38809 getWidth : function(){
38810 return this.inner.getWidth();
38813 setWidth : function(width){
38814 var iwidth = width - this.linode.getPadding("lr");
38815 this.inner.setWidth(iwidth);
38816 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38817 this.linode.setWidth(width);
38821 * Show or hide the tab
38822 * @param {Boolean} hidden True to hide or false to show.
38824 setHidden : function(hidden){
38825 this.hidden = hidden;
38826 this.linode.setStyle("display", hidden ? "none" : "");
38830 * Returns true if this tab is "hidden"
38831 * @return {Boolean}
38833 isHidden : function(){
38834 return this.hidden;
38838 * Returns the text for this tab
38841 getText : function(){
38845 autoSize : function(){
38846 //this.el.beginMeasure();
38847 this.textEl.setWidth(1);
38849 * #2804 [new] Tabs in Roojs
38850 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38852 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38853 //this.el.endMeasure();
38857 * Sets the text for the tab (Note: this also sets the tooltip text)
38858 * @param {String} text The tab's text and tooltip
38860 setText : function(text){
38862 this.textEl.update(text);
38863 this.setTooltip(text);
38864 //if(!this.tabPanel.resizeTabs){
38865 // this.autoSize();
38869 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38871 activate : function(){
38872 this.tabPanel.activate(this.id);
38876 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38878 disable : function(){
38879 if(this.tabPanel.active != this){
38880 this.disabled = true;
38881 this.status_node.addClass("disabled");
38886 * Enables this TabPanelItem if it was previously disabled.
38888 enable : function(){
38889 this.disabled = false;
38890 this.status_node.removeClass("disabled");
38894 * Sets the content for this TabPanelItem.
38895 * @param {String} content The content
38896 * @param {Boolean} loadScripts true to look for and load scripts
38898 setContent : function(content, loadScripts){
38899 this.bodyEl.update(content, loadScripts);
38903 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38904 * @return {Roo.UpdateManager} The UpdateManager
38906 getUpdateManager : function(){
38907 return this.bodyEl.getUpdateManager();
38911 * Set a URL to be used to load the content for this TabPanelItem.
38912 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38913 * @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)
38914 * @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)
38915 * @return {Roo.UpdateManager} The UpdateManager
38917 setUrl : function(url, params, loadOnce){
38918 if(this.refreshDelegate){
38919 this.un('activate', this.refreshDelegate);
38921 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38922 this.on("activate", this.refreshDelegate);
38923 return this.bodyEl.getUpdateManager();
38927 _handleRefresh : function(url, params, loadOnce){
38928 if(!loadOnce || !this.loaded){
38929 var updater = this.bodyEl.getUpdateManager();
38930 updater.update(url, params, this._setLoaded.createDelegate(this));
38935 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38936 * Will fail silently if the setUrl method has not been called.
38937 * This does not activate the panel, just updates its content.
38939 refresh : function(){
38940 if(this.refreshDelegate){
38941 this.loaded = false;
38942 this.refreshDelegate();
38947 _setLoaded : function(){
38948 this.loaded = true;
38952 closeClick : function(e){
38955 this.fireEvent("beforeclose", this, o);
38956 if(o.cancel !== true){
38957 this.tabPanel.removeTab(this.id);
38961 * The text displayed in the tooltip for the close icon.
38964 closeText : "Close this tab"
38967 * This script refer to:
38968 * Title: International Telephone Input
38969 * Author: Jack O'Connor
38970 * Code version: v12.1.12
38971 * Availability: https://github.com/jackocnr/intl-tel-input.git
38974 Roo.bootstrap.PhoneInputData = function() {
38977 "Afghanistan (افغانستان)",
38982 "Albania (Shqipëri)",
38987 "Algeria (الجزائر)",
39012 "Antigua and Barbuda",
39022 "Armenia (Հայաստան)",
39038 "Austria (Österreich)",
39043 "Azerbaijan (Azərbaycan)",
39053 "Bahrain (البحرين)",
39058 "Bangladesh (বাংলাদেশ)",
39068 "Belarus (Беларусь)",
39073 "Belgium (België)",
39103 "Bosnia and Herzegovina (Босна и Херцеговина)",
39118 "British Indian Ocean Territory",
39123 "British Virgin Islands",
39133 "Bulgaria (България)",
39143 "Burundi (Uburundi)",
39148 "Cambodia (កម្ពុជា)",
39153 "Cameroon (Cameroun)",
39162 ["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"]
39165 "Cape Verde (Kabu Verdi)",
39170 "Caribbean Netherlands",
39181 "Central African Republic (République centrafricaine)",
39201 "Christmas Island",
39207 "Cocos (Keeling) Islands",
39218 "Comoros (جزر القمر)",
39223 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39228 "Congo (Republic) (Congo-Brazzaville)",
39248 "Croatia (Hrvatska)",
39269 "Czech Republic (Česká republika)",
39274 "Denmark (Danmark)",
39289 "Dominican Republic (República Dominicana)",
39293 ["809", "829", "849"]
39311 "Equatorial Guinea (Guinea Ecuatorial)",
39331 "Falkland Islands (Islas Malvinas)",
39336 "Faroe Islands (Føroyar)",
39357 "French Guiana (Guyane française)",
39362 "French Polynesia (Polynésie française)",
39377 "Georgia (საქართველო)",
39382 "Germany (Deutschland)",
39402 "Greenland (Kalaallit Nunaat)",
39439 "Guinea-Bissau (Guiné Bissau)",
39464 "Hungary (Magyarország)",
39469 "Iceland (Ísland)",
39489 "Iraq (العراق)",
39505 "Israel (ישראל)",
39532 "Jordan (الأردن)",
39537 "Kazakhstan (Казахстан)",
39558 "Kuwait (الكويت)",
39563 "Kyrgyzstan (Кыргызстан)",
39573 "Latvia (Latvija)",
39578 "Lebanon (لبنان)",
39593 "Libya (ليبيا)",
39603 "Lithuania (Lietuva)",
39618 "Macedonia (FYROM) (Македонија)",
39623 "Madagascar (Madagasikara)",
39653 "Marshall Islands",
39663 "Mauritania (موريتانيا)",
39668 "Mauritius (Moris)",
39689 "Moldova (Republica Moldova)",
39699 "Mongolia (Монгол)",
39704 "Montenegro (Crna Gora)",
39714 "Morocco (المغرب)",
39720 "Mozambique (Moçambique)",
39725 "Myanmar (Burma) (မြန်မာ)",
39730 "Namibia (Namibië)",
39745 "Netherlands (Nederland)",
39750 "New Caledonia (Nouvelle-Calédonie)",
39785 "North Korea (조선 민주주의 인민 공화국)",
39790 "Northern Mariana Islands",
39806 "Pakistan (پاکستان)",
39816 "Palestine (فلسطين)",
39826 "Papua New Guinea",
39868 "Réunion (La Réunion)",
39874 "Romania (România)",
39890 "Saint Barthélemy",
39901 "Saint Kitts and Nevis",
39911 "Saint Martin (Saint-Martin (partie française))",
39917 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39922 "Saint Vincent and the Grenadines",
39937 "São Tomé and Príncipe (São Tomé e Príncipe)",
39942 "Saudi Arabia (المملكة العربية السعودية)",
39947 "Senegal (Sénégal)",
39977 "Slovakia (Slovensko)",
39982 "Slovenia (Slovenija)",
39992 "Somalia (Soomaaliya)",
40002 "South Korea (대한민국)",
40007 "South Sudan (جنوب السودان)",
40017 "Sri Lanka (ශ්රී ලංකාව)",
40022 "Sudan (السودان)",
40032 "Svalbard and Jan Mayen",
40043 "Sweden (Sverige)",
40048 "Switzerland (Schweiz)",
40053 "Syria (سوريا)",
40098 "Trinidad and Tobago",
40103 "Tunisia (تونس)",
40108 "Turkey (Türkiye)",
40118 "Turks and Caicos Islands",
40128 "U.S. Virgin Islands",
40138 "Ukraine (Україна)",
40143 "United Arab Emirates (الإمارات العربية المتحدة)",
40165 "Uzbekistan (Oʻzbekiston)",
40175 "Vatican City (Città del Vaticano)",
40186 "Vietnam (Việt Nam)",
40191 "Wallis and Futuna (Wallis-et-Futuna)",
40196 "Western Sahara (الصحراء الغربية)",
40202 "Yemen (اليمن)",
40226 * This script refer to:
40227 * Title: International Telephone Input
40228 * Author: Jack O'Connor
40229 * Code version: v12.1.12
40230 * Availability: https://github.com/jackocnr/intl-tel-input.git
40234 * @class Roo.bootstrap.PhoneInput
40235 * @extends Roo.bootstrap.TriggerField
40236 * An input with International dial-code selection
40238 * @cfg {String} defaultDialCode default '+852'
40239 * @cfg {Array} preferedCountries default []
40242 * Create a new PhoneInput.
40243 * @param {Object} config Configuration options
40246 Roo.bootstrap.PhoneInput = function(config) {
40247 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40250 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40252 listWidth: undefined,
40254 selectedClass: 'active',
40256 invalidClass : "has-warning",
40258 validClass: 'has-success',
40260 allowed: '0123456789',
40265 * @cfg {String} defaultDialCode The default dial code when initializing the input
40267 defaultDialCode: '+852',
40270 * @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
40272 preferedCountries: false,
40274 getAutoCreate : function()
40276 var data = Roo.bootstrap.PhoneInputData();
40277 var align = this.labelAlign || this.parentLabelAlign();
40280 this.allCountries = [];
40281 this.dialCodeMapping = [];
40283 for (var i = 0; i < data.length; i++) {
40285 this.allCountries[i] = {
40289 priority: c[3] || 0,
40290 areaCodes: c[4] || null
40292 this.dialCodeMapping[c[2]] = {
40295 priority: c[3] || 0,
40296 areaCodes: c[4] || null
40308 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40309 maxlength: this.max_length,
40310 cls : 'form-control tel-input',
40311 autocomplete: 'new-password'
40314 var hiddenInput = {
40317 cls: 'hidden-tel-input'
40321 hiddenInput.name = this.name;
40324 if (this.disabled) {
40325 input.disabled = true;
40328 var flag_container = {
40345 cls: this.hasFeedback ? 'has-feedback' : '',
40351 cls: 'dial-code-holder',
40358 cls: 'roo-select2-container input-group',
40365 if (this.fieldLabel.length) {
40368 tooltip: 'This field is required'
40374 cls: 'control-label',
40380 html: this.fieldLabel
40383 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40389 if(this.indicatorpos == 'right') {
40390 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40397 if(align == 'left') {
40405 if(this.labelWidth > 12){
40406 label.style = "width: " + this.labelWidth + 'px';
40408 if(this.labelWidth < 13 && this.labelmd == 0){
40409 this.labelmd = this.labelWidth;
40411 if(this.labellg > 0){
40412 label.cls += ' col-lg-' + this.labellg;
40413 input.cls += ' col-lg-' + (12 - this.labellg);
40415 if(this.labelmd > 0){
40416 label.cls += ' col-md-' + this.labelmd;
40417 container.cls += ' col-md-' + (12 - this.labelmd);
40419 if(this.labelsm > 0){
40420 label.cls += ' col-sm-' + this.labelsm;
40421 container.cls += ' col-sm-' + (12 - this.labelsm);
40423 if(this.labelxs > 0){
40424 label.cls += ' col-xs-' + this.labelxs;
40425 container.cls += ' col-xs-' + (12 - this.labelxs);
40435 var settings = this;
40437 ['xs','sm','md','lg'].map(function(size){
40438 if (settings[size]) {
40439 cfg.cls += ' col-' + size + '-' + settings[size];
40443 this.store = new Roo.data.Store({
40444 proxy : new Roo.data.MemoryProxy({}),
40445 reader : new Roo.data.JsonReader({
40456 'name' : 'dialCode',
40460 'name' : 'priority',
40464 'name' : 'areaCodes',
40471 if(!this.preferedCountries) {
40472 this.preferedCountries = [
40479 var p = this.preferedCountries.reverse();
40482 for (var i = 0; i < p.length; i++) {
40483 for (var j = 0; j < this.allCountries.length; j++) {
40484 if(this.allCountries[j].iso2 == p[i]) {
40485 var t = this.allCountries[j];
40486 this.allCountries.splice(j,1);
40487 this.allCountries.unshift(t);
40493 this.store.proxy.data = {
40495 data: this.allCountries
40501 initEvents : function()
40504 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40506 this.indicator = this.indicatorEl();
40507 this.flag = this.flagEl();
40508 this.dialCodeHolder = this.dialCodeHolderEl();
40510 this.trigger = this.el.select('div.flag-box',true).first();
40511 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40516 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40517 _this.list.setWidth(lw);
40520 this.list.on('mouseover', this.onViewOver, this);
40521 this.list.on('mousemove', this.onViewMove, this);
40522 this.inputEl().on("keyup", this.onKeyUp, this);
40523 this.inputEl().on("keypress", this.onKeyPress, this);
40525 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40527 this.view = new Roo.View(this.list, this.tpl, {
40528 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40531 this.view.on('click', this.onViewClick, this);
40532 this.setValue(this.defaultDialCode);
40535 onTriggerClick : function(e)
40537 Roo.log('trigger click');
40542 if(this.isExpanded()){
40544 this.hasFocus = false;
40546 this.store.load({});
40547 this.hasFocus = true;
40552 isExpanded : function()
40554 return this.list.isVisible();
40557 collapse : function()
40559 if(!this.isExpanded()){
40563 Roo.get(document).un('mousedown', this.collapseIf, this);
40564 Roo.get(document).un('mousewheel', this.collapseIf, this);
40565 this.fireEvent('collapse', this);
40569 expand : function()
40573 if(this.isExpanded() || !this.hasFocus){
40577 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40578 this.list.setWidth(lw);
40581 this.restrictHeight();
40583 Roo.get(document).on('mousedown', this.collapseIf, this);
40584 Roo.get(document).on('mousewheel', this.collapseIf, this);
40586 this.fireEvent('expand', this);
40589 restrictHeight : function()
40591 this.list.alignTo(this.inputEl(), this.listAlign);
40592 this.list.alignTo(this.inputEl(), this.listAlign);
40595 onViewOver : function(e, t)
40597 if(this.inKeyMode){
40600 var item = this.view.findItemFromChild(t);
40603 var index = this.view.indexOf(item);
40604 this.select(index, false);
40609 onViewClick : function(view, doFocus, el, e)
40611 var index = this.view.getSelectedIndexes()[0];
40613 var r = this.store.getAt(index);
40616 this.onSelect(r, index);
40618 if(doFocus !== false && !this.blockFocus){
40619 this.inputEl().focus();
40623 onViewMove : function(e, t)
40625 this.inKeyMode = false;
40628 select : function(index, scrollIntoView)
40630 this.selectedIndex = index;
40631 this.view.select(index);
40632 if(scrollIntoView !== false){
40633 var el = this.view.getNode(index);
40635 this.list.scrollChildIntoView(el, false);
40640 createList : function()
40642 this.list = Roo.get(document.body).createChild({
40644 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40645 style: 'display:none'
40648 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40651 collapseIf : function(e)
40653 var in_combo = e.within(this.el);
40654 var in_list = e.within(this.list);
40655 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40657 if (in_combo || in_list || is_list) {
40663 onSelect : function(record, index)
40665 if(this.fireEvent('beforeselect', this, record, index) !== false){
40667 this.setFlagClass(record.data.iso2);
40668 this.setDialCode(record.data.dialCode);
40669 this.hasFocus = false;
40671 this.fireEvent('select', this, record, index);
40675 flagEl : function()
40677 var flag = this.el.select('div.flag',true).first();
40684 dialCodeHolderEl : function()
40686 var d = this.el.select('input.dial-code-holder',true).first();
40693 setDialCode : function(v)
40695 this.dialCodeHolder.dom.value = '+'+v;
40698 setFlagClass : function(n)
40700 this.flag.dom.className = 'flag '+n;
40703 getValue : function()
40705 var v = this.inputEl().getValue();
40706 if(this.dialCodeHolder) {
40707 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40712 setValue : function(v)
40714 var d = this.getDialCode(v);
40716 //invalid dial code
40717 if(v.length == 0 || !d || d.length == 0) {
40719 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40720 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40726 this.setFlagClass(this.dialCodeMapping[d].iso2);
40727 this.setDialCode(d);
40728 this.inputEl().dom.value = v.replace('+'+d,'');
40729 this.hiddenEl().dom.value = this.getValue();
40734 getDialCode : function(v)
40738 if (v.length == 0) {
40739 return this.dialCodeHolder.dom.value;
40743 if (v.charAt(0) != "+") {
40746 var numericChars = "";
40747 for (var i = 1; i < v.length; i++) {
40748 var c = v.charAt(i);
40751 if (this.dialCodeMapping[numericChars]) {
40752 dialCode = v.substr(1, i);
40754 if (numericChars.length == 4) {
40764 this.setValue(this.defaultDialCode);
40768 hiddenEl : function()
40770 return this.el.select('input.hidden-tel-input',true).first();
40773 // after setting val
40774 onKeyUp : function(e){
40775 this.setValue(this.getValue());
40778 onKeyPress : function(e){
40779 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40786 * @class Roo.bootstrap.MoneyField
40787 * @extends Roo.bootstrap.ComboBox
40788 * Bootstrap MoneyField class
40791 * Create a new MoneyField.
40792 * @param {Object} config Configuration options
40795 Roo.bootstrap.MoneyField = function(config) {
40797 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40801 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40804 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40806 allowDecimals : true,
40808 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40810 decimalSeparator : ".",
40812 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40814 decimalPrecision : 0,
40816 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40818 allowNegative : true,
40820 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40824 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40826 minValue : Number.NEGATIVE_INFINITY,
40828 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40830 maxValue : Number.MAX_VALUE,
40832 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40834 minText : "The minimum value for this field is {0}",
40836 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40838 maxText : "The maximum value for this field is {0}",
40840 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40841 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40843 nanText : "{0} is not a valid number",
40845 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40849 * @cfg {String} defaults currency of the MoneyField
40850 * value should be in lkey
40852 defaultCurrency : false,
40854 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40856 thousandsDelimiter : false,
40858 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40869 getAutoCreate : function()
40871 var align = this.labelAlign || this.parentLabelAlign();
40883 cls : 'form-control roo-money-amount-input',
40884 autocomplete: 'new-password'
40887 var hiddenInput = {
40891 cls: 'hidden-number-input'
40894 if(this.max_length) {
40895 input.maxlength = this.max_length;
40899 hiddenInput.name = this.name;
40902 if (this.disabled) {
40903 input.disabled = true;
40906 var clg = 12 - this.inputlg;
40907 var cmd = 12 - this.inputmd;
40908 var csm = 12 - this.inputsm;
40909 var cxs = 12 - this.inputxs;
40913 cls : 'row roo-money-field',
40917 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40921 cls: 'roo-select2-container input-group',
40925 cls : 'form-control roo-money-currency-input',
40926 autocomplete: 'new-password',
40928 name : this.currencyName
40932 cls : 'input-group-addon',
40946 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40950 cls: this.hasFeedback ? 'has-feedback' : '',
40961 if (this.fieldLabel.length) {
40964 tooltip: 'This field is required'
40970 cls: 'control-label',
40976 html: this.fieldLabel
40979 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40985 if(this.indicatorpos == 'right') {
40986 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40993 if(align == 'left') {
41001 if(this.labelWidth > 12){
41002 label.style = "width: " + this.labelWidth + 'px';
41004 if(this.labelWidth < 13 && this.labelmd == 0){
41005 this.labelmd = this.labelWidth;
41007 if(this.labellg > 0){
41008 label.cls += ' col-lg-' + this.labellg;
41009 input.cls += ' col-lg-' + (12 - this.labellg);
41011 if(this.labelmd > 0){
41012 label.cls += ' col-md-' + this.labelmd;
41013 container.cls += ' col-md-' + (12 - this.labelmd);
41015 if(this.labelsm > 0){
41016 label.cls += ' col-sm-' + this.labelsm;
41017 container.cls += ' col-sm-' + (12 - this.labelsm);
41019 if(this.labelxs > 0){
41020 label.cls += ' col-xs-' + this.labelxs;
41021 container.cls += ' col-xs-' + (12 - this.labelxs);
41032 var settings = this;
41034 ['xs','sm','md','lg'].map(function(size){
41035 if (settings[size]) {
41036 cfg.cls += ' col-' + size + '-' + settings[size];
41043 initEvents : function()
41045 this.indicator = this.indicatorEl();
41047 this.initCurrencyEvent();
41049 this.initNumberEvent();
41052 initCurrencyEvent : function()
41055 throw "can not find store for combo";
41058 this.store = Roo.factory(this.store, Roo.data);
41059 this.store.parent = this;
41063 this.triggerEl = this.el.select('.input-group-addon', true).first();
41065 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41070 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41071 _this.list.setWidth(lw);
41074 this.list.on('mouseover', this.onViewOver, this);
41075 this.list.on('mousemove', this.onViewMove, this);
41076 this.list.on('scroll', this.onViewScroll, this);
41079 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41082 this.view = new Roo.View(this.list, this.tpl, {
41083 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41086 this.view.on('click', this.onViewClick, this);
41088 this.store.on('beforeload', this.onBeforeLoad, this);
41089 this.store.on('load', this.onLoad, this);
41090 this.store.on('loadexception', this.onLoadException, this);
41092 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41093 "up" : function(e){
41094 this.inKeyMode = true;
41098 "down" : function(e){
41099 if(!this.isExpanded()){
41100 this.onTriggerClick();
41102 this.inKeyMode = true;
41107 "enter" : function(e){
41110 if(this.fireEvent("specialkey", this, e)){
41111 this.onViewClick(false);
41117 "esc" : function(e){
41121 "tab" : function(e){
41124 if(this.fireEvent("specialkey", this, e)){
41125 this.onViewClick(false);
41133 doRelay : function(foo, bar, hname){
41134 if(hname == 'down' || this.scope.isExpanded()){
41135 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41143 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41147 initNumberEvent : function(e)
41149 this.inputEl().on("keydown" , this.fireKey, this);
41150 this.inputEl().on("focus", this.onFocus, this);
41151 this.inputEl().on("blur", this.onBlur, this);
41153 this.inputEl().relayEvent('keyup', this);
41155 if(this.indicator){
41156 this.indicator.addClass('invisible');
41159 this.originalValue = this.getValue();
41161 if(this.validationEvent == 'keyup'){
41162 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41163 this.inputEl().on('keyup', this.filterValidation, this);
41165 else if(this.validationEvent !== false){
41166 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41169 if(this.selectOnFocus){
41170 this.on("focus", this.preFocus, this);
41173 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41174 this.inputEl().on("keypress", this.filterKeys, this);
41176 this.inputEl().relayEvent('keypress', this);
41179 var allowed = "0123456789";
41181 if(this.allowDecimals){
41182 allowed += this.decimalSeparator;
41185 if(this.allowNegative){
41189 if(this.thousandsDelimiter) {
41193 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41195 var keyPress = function(e){
41197 var k = e.getKey();
41199 var c = e.getCharCode();
41202 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41203 allowed.indexOf(String.fromCharCode(c)) === -1
41209 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41213 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41218 this.inputEl().on("keypress", keyPress, this);
41222 onTriggerClick : function(e)
41229 this.loadNext = false;
41231 if(this.isExpanded()){
41236 this.hasFocus = true;
41238 if(this.triggerAction == 'all') {
41239 this.doQuery(this.allQuery, true);
41243 this.doQuery(this.getRawValue());
41246 getCurrency : function()
41248 var v = this.currencyEl().getValue();
41253 restrictHeight : function()
41255 this.list.alignTo(this.currencyEl(), this.listAlign);
41256 this.list.alignTo(this.currencyEl(), this.listAlign);
41259 onViewClick : function(view, doFocus, el, e)
41261 var index = this.view.getSelectedIndexes()[0];
41263 var r = this.store.getAt(index);
41266 this.onSelect(r, index);
41270 onSelect : function(record, index){
41272 if(this.fireEvent('beforeselect', this, record, index) !== false){
41274 this.setFromCurrencyData(index > -1 ? record.data : false);
41278 this.fireEvent('select', this, record, index);
41282 setFromCurrencyData : function(o)
41286 this.lastCurrency = o;
41288 if (this.currencyField) {
41289 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41291 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41294 this.lastSelectionText = currency;
41296 //setting default currency
41297 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41298 this.setCurrency(this.defaultCurrency);
41302 this.setCurrency(currency);
41305 setFromData : function(o)
41309 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41311 this.setFromCurrencyData(c);
41316 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41318 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41321 this.setValue(value);
41325 setCurrency : function(v)
41327 this.currencyValue = v;
41330 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41335 setValue : function(v)
41337 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41343 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41345 this.inputEl().dom.value = (v == '') ? '' :
41346 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41348 if(!this.allowZero && v === '0') {
41349 this.hiddenEl().dom.value = '';
41350 this.inputEl().dom.value = '';
41357 getRawValue : function()
41359 var v = this.inputEl().getValue();
41364 getValue : function()
41366 return this.fixPrecision(this.parseValue(this.getRawValue()));
41369 parseValue : function(value)
41371 if(this.thousandsDelimiter) {
41373 r = new RegExp(",", "g");
41374 value = value.replace(r, "");
41377 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41378 return isNaN(value) ? '' : value;
41382 fixPrecision : function(value)
41384 if(this.thousandsDelimiter) {
41386 r = new RegExp(",", "g");
41387 value = value.replace(r, "");
41390 var nan = isNaN(value);
41392 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41393 return nan ? '' : value;
41395 return parseFloat(value).toFixed(this.decimalPrecision);
41398 decimalPrecisionFcn : function(v)
41400 return Math.floor(v);
41403 validateValue : function(value)
41405 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41409 var num = this.parseValue(value);
41412 this.markInvalid(String.format(this.nanText, value));
41416 if(num < this.minValue){
41417 this.markInvalid(String.format(this.minText, this.minValue));
41421 if(num > this.maxValue){
41422 this.markInvalid(String.format(this.maxText, this.maxValue));
41429 validate : function()
41431 if(this.disabled || this.allowBlank){
41436 var currency = this.getCurrency();
41438 if(this.validateValue(this.getRawValue()) && currency.length){
41443 this.markInvalid();
41447 getName: function()
41452 beforeBlur : function()
41458 var v = this.parseValue(this.getRawValue());
41465 onBlur : function()
41469 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41470 //this.el.removeClass(this.focusClass);
41473 this.hasFocus = false;
41475 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41479 var v = this.getValue();
41481 if(String(v) !== String(this.startValue)){
41482 this.fireEvent('change', this, v, this.startValue);
41485 this.fireEvent("blur", this);
41488 inputEl : function()
41490 return this.el.select('.roo-money-amount-input', true).first();
41493 currencyEl : function()
41495 return this.el.select('.roo-money-currency-input', true).first();
41498 hiddenEl : function()
41500 return this.el.select('input.hidden-number-input',true).first();
41504 * This script refer to:
41505 * Title: Signature Pad
41507 * Availability: https://github.com/szimek/signature_pad
41511 * @class Roo.bootstrap.BezierSignature
41512 * @extends Roo.bootstrap.Component
41513 * Bootstrap BezierSignature class
41516 * Create a new BezierSignature
41517 * @param {Object} config The config object
41520 Roo.bootstrap.BezierSignature = function(config){
41521 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41527 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component, {
41533 mouse_btn_down: true,
41536 * @cfg(int) canvas height
41538 canvas_height: '200px',
41541 * @cfg(float or function) Radius of a single dot.
41546 * @cfg(float) Minimum width of a line. Defaults to 0.5.
41551 * @cfg(float) Maximum width of a line. Defaults to 2.5.
41556 * @cfg(integer) Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41561 * @cfg(integer) Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41566 * @cfg(string) Color used to clear the background. Can be any color format accepted by context.fillStyle. Defaults to "rgba(0,0,0,0)" (transparent black). Use a non-transparent color e.g. "rgb(255,255,255)" (opaque white) if you'd like to save signatures as JPEG images.
41568 bg_color: 'rgba(0, 0, 0, 0)',
41571 * @cfg(string) Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41573 dot_color: 'black',
41576 * @cfg(float) Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41578 velocity_filter_weight: 0.7,
41581 * @cfg(function) Callback when stroke begin.
41586 * @cfg(function) Callback when stroke end.
41590 getAutoCreate : function()
41592 var cls = 'roo-signature column';
41595 cls += ' ' + this.cls;
41605 for(var i = 0; i < col_sizes.length; i++) {
41606 if(this[col_sizes[i]]) {
41607 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41617 cls: 'roo-signature-body',
41621 cls: 'roo-signature-body-canvas',
41622 height: this.canvas_height,
41623 width: this.canvas_width
41630 style: 'display: none'
41638 initEvents: function()
41640 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41642 var canvas = this.canvasEl();
41644 // mouse && touch event swapping...
41645 canvas.dom.style.touchAction = 'none';
41646 canvas.dom.style.msTouchAction = 'none';
41648 this.mouse_btn_down = false;
41649 canvas.on('mousedown', this._handleMouseDown, this);
41650 canvas.on('mousemove', this._handleMouseMove, this);
41651 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41653 if (window.PointerEvent) {
41654 canvas.on('pointerdown', this._handleMouseDown, this);
41655 canvas.on('pointermove', this._handleMouseMove, this);
41656 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41659 if ('ontouchstart' in window) {
41660 canvas.on('touchstart', this._handleTouchStart, this);
41661 canvas.on('touchmove', this._handleTouchMove, this);
41662 canvas.on('touchend', this._handleTouchEnd, this);
41665 Roo.EventManager.onWindowResize(this.resize, this, true);
41667 // file input event
41668 this.fileEl().on('change', this.uploadImage, this);
41675 resize: function(){
41677 var canvas = this.canvasEl().dom;
41678 var ctx = this.canvasElCtx();
41679 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41681 // setting canvas width will clean img data
41684 var style = window.getComputedStyle ?
41685 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41687 var padding_left = parseInt(style.paddingLeft) || 0;
41688 var padding_right = parseInt(style.paddingRight) || 0;
41690 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41692 ctx.putImageData(img_data, 0, 0);
41695 _handleMouseDown: function(e)
41697 if (e.browserEvent.which === 1) {
41698 this.mouse_btn_down = true;
41699 this.strokeBegin(e);
41703 _handleMouseMove: function (e)
41705 if (this.mouse_btn_down) {
41706 this.strokeMoveUpdate(e);
41710 _handleMouseUp: function (e)
41712 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41713 this.mouse_btn_down = false;
41718 _handleTouchStart: function (e) {
41720 e.preventDefault();
41721 if (e.browserEvent.targetTouches.length === 1) {
41722 // var touch = e.browserEvent.changedTouches[0];
41723 // this.strokeBegin(touch);
41725 this.strokeBegin(e); // assume e catching the correct xy...
41729 _handleTouchMove: function (e) {
41730 e.preventDefault();
41731 // var touch = event.targetTouches[0];
41732 // _this._strokeMoveUpdate(touch);
41733 this.strokeMoveUpdate(e);
41736 _handleTouchEnd: function (e) {
41737 var wasCanvasTouched = e.target === this.canvasEl().dom;
41738 if (wasCanvasTouched) {
41739 e.preventDefault();
41740 // var touch = event.changedTouches[0];
41741 // _this._strokeEnd(touch);
41746 reset: function () {
41747 this._lastPoints = [];
41748 this._lastVelocity = 0;
41749 this._lastWidth = (this.min_width + this.max_width) / 2;
41750 this.canvasElCtx().fillStyle = this.dot_color;
41753 strokeMoveUpdate: function(e)
41755 this.strokeUpdate(e);
41757 if (this.throttle) {
41758 this.throttle(this.strokeUpdate, this.throttle);
41761 this.strokeUpdate(e);
41765 strokeBegin: function(e)
41767 var newPointGroup = {
41768 color: this.dot_color,
41772 if (typeof this.onBegin === 'function') {
41776 this.curve_data.push(newPointGroup);
41778 this.strokeUpdate(e);
41781 strokeUpdate: function(e)
41783 var rect = this.canvasEl().dom.getBoundingClientRect();
41784 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41785 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41786 var lastPoints = lastPointGroup.points;
41787 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41788 var isLastPointTooClose = lastPoint
41789 ? point.distanceTo(lastPoint) <= this.min_distance
41791 var color = lastPointGroup.color;
41792 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41793 var curve = this.addPoint(point);
41795 this.drawDot({color: color, point: point});
41798 this.drawCurve({color: color, curve: curve});
41808 strokeEnd: function(e)
41810 this.strokeUpdate(e);
41811 if (typeof this.onEnd === 'function') {
41816 addPoint: function (point) {
41817 var _lastPoints = this._lastPoints;
41818 _lastPoints.push(point);
41819 if (_lastPoints.length > 2) {
41820 if (_lastPoints.length === 3) {
41821 _lastPoints.unshift(_lastPoints[0]);
41823 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41824 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41825 _lastPoints.shift();
41831 calculateCurveWidths: function (startPoint, endPoint) {
41832 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41833 (1 - this.velocity_filter_weight) * this._lastVelocity;
41835 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41838 start: this._lastWidth
41841 this._lastVelocity = velocity;
41842 this._lastWidth = newWidth;
41846 drawDot: function (_a) {
41847 var color = _a.color, point = _a.point;
41848 var ctx = this.canvasElCtx();
41849 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41851 this.drawCurveSegment(point.x, point.y, width);
41853 ctx.fillStyle = color;
41857 drawCurve: function (_a) {
41858 var color = _a.color, curve = _a.curve;
41859 var ctx = this.canvasElCtx();
41860 var widthDelta = curve.endWidth - curve.startWidth;
41861 var drawSteps = Math.floor(curve.length()) * 2;
41863 ctx.fillStyle = color;
41864 for (var i = 0; i < drawSteps; i += 1) {
41865 var t = i / drawSteps;
41871 var x = uuu * curve.startPoint.x;
41872 x += 3 * uu * t * curve.control1.x;
41873 x += 3 * u * tt * curve.control2.x;
41874 x += ttt * curve.endPoint.x;
41875 var y = uuu * curve.startPoint.y;
41876 y += 3 * uu * t * curve.control1.y;
41877 y += 3 * u * tt * curve.control2.y;
41878 y += ttt * curve.endPoint.y;
41879 var width = curve.startWidth + ttt * widthDelta;
41880 this.drawCurveSegment(x, y, width);
41886 drawCurveSegment: function (x, y, width) {
41887 var ctx = this.canvasElCtx();
41889 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
41890 this.is_empty = false;
41895 var ctx = this.canvasElCtx();
41896 var canvas = this.canvasEl().dom;
41897 ctx.fillStyle = this.bg_color;
41898 ctx.clearRect(0, 0, canvas.width, canvas.height);
41899 ctx.fillRect(0, 0, canvas.width, canvas.height);
41900 this.curve_data = [];
41902 this.is_empty = true;
41907 return this.el.select('input',true).first();
41910 canvasEl: function()
41912 return this.el.select('canvas',true).first();
41915 canvasElCtx: function()
41917 return this.el.select('canvas',true).first().dom.getContext('2d');
41920 getImage: function(type)
41922 if(this.is_empty) {
41927 return this.canvasEl().dom.toDataURL('image/'+type, 1);
41930 drawFromImage: function(img_src)
41932 var img = new Image();
41934 img.onload = function(){
41935 this.canvasElCtx().drawImage(img, 0, 0);
41940 this.is_empty = false;
41943 selectImage: function()
41945 this.fileEl().dom.click();
41948 uploadImage: function(e)
41950 var reader = new FileReader();
41952 reader.onload = function(e){
41953 var img = new Image();
41954 img.onload = function(){
41956 this.canvasElCtx().drawImage(img, 0, 0);
41958 img.src = e.target.result;
41961 reader.readAsDataURL(e.target.files[0]);
41964 // Bezier Point Constructor
41965 Point: (function () {
41966 function Point(x, y, time) {
41969 this.time = time || Date.now();
41971 Point.prototype.distanceTo = function (start) {
41972 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
41974 Point.prototype.equals = function (other) {
41975 return this.x === other.x && this.y === other.y && this.time === other.time;
41977 Point.prototype.velocityFrom = function (start) {
41978 return this.time !== start.time
41979 ? this.distanceTo(start) / (this.time - start.time)
41986 // Bezier Constructor
41987 Bezier: (function () {
41988 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
41989 this.startPoint = startPoint;
41990 this.control2 = control2;
41991 this.control1 = control1;
41992 this.endPoint = endPoint;
41993 this.startWidth = startWidth;
41994 this.endWidth = endWidth;
41996 Bezier.fromPoints = function (points, widths, scope) {
41997 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
41998 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
41999 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42001 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42002 var dx1 = s1.x - s2.x;
42003 var dy1 = s1.y - s2.y;
42004 var dx2 = s2.x - s3.x;
42005 var dy2 = s2.y - s3.y;
42006 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42007 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42008 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42009 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42010 var dxm = m1.x - m2.x;
42011 var dym = m1.y - m2.y;
42012 var k = l2 / (l1 + l2);
42013 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42014 var tx = s2.x - cm.x;
42015 var ty = s2.y - cm.y;
42017 c1: new scope.Point(m1.x + tx, m1.y + ty),
42018 c2: new scope.Point(m2.x + tx, m2.y + ty)
42021 Bezier.prototype.length = function () {
42026 for (var i = 0; i <= steps; i += 1) {
42028 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42029 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42031 var xdiff = cx - px;
42032 var ydiff = cy - py;
42033 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42040 Bezier.prototype.point = function (t, start, c1, c2, end) {
42041 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42042 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42043 + (3.0 * c2 * (1.0 - t) * t * t)
42044 + (end * t * t * t);
42049 throttle: function(fn, wait) {
42050 if (wait === void 0) { wait = 250; }
42052 var timeout = null;
42056 var later = function () {
42057 previous = Date.now();
42059 result = fn.apply(storedContext, storedArgs);
42061 storedContext = null;
42065 return function wrapper() {
42067 for (var _i = 0; _i < arguments.length; _i++) {
42068 args[_i] = arguments[_i];
42070 var now = Date.now();
42071 var remaining = wait - (now - previous);
42072 storedContext = this;
42074 if (remaining <= 0 || remaining > wait) {
42076 clearTimeout(timeout);
42080 result = fn.apply(storedContext, storedArgs);
42082 storedContext = null;
42086 else if (!timeout) {
42087 timeout = window.setTimeout(later, remaining);