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.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
7909 this.uploadProgress();
7911 }else if (o.clientValidation !== false){ // client validation failed
7912 this.failureType = Roo.form.Action.CLIENT_INVALID;
7913 this.form.afterAction(this, false);
7917 success : function(response)
7919 this.uploadComplete= true;
7920 if (this.haveProgress) {
7921 Roo.MessageBox.hide();
7925 var result = this.processResponse(response);
7926 if(result === true || result.success){
7927 this.form.afterAction(this, true);
7931 this.form.markInvalid(result.errors);
7932 this.failureType = Roo.form.Action.SERVER_INVALID;
7934 this.form.afterAction(this, false);
7936 failure : function(response)
7938 this.uploadComplete= true;
7939 if (this.haveProgress) {
7940 Roo.MessageBox.hide();
7943 this.response = response;
7944 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7945 this.form.afterAction(this, false);
7948 handleResponse : function(response){
7949 if(this.form.errorReader){
7950 var rs = this.form.errorReader.read(response);
7953 for(var i = 0, len = rs.records.length; i < len; i++) {
7954 var r = rs.records[i];
7958 if(errors.length < 1){
7962 success : rs.success,
7968 ret = Roo.decode(response.responseText);
7972 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
7982 Roo.form.Action.Load = function(form, options){
7983 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
7984 this.reader = this.form.reader;
7987 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
7992 Roo.Ajax.request(Roo.apply(
7993 this.createCallback(), {
7994 method:this.getMethod(),
7995 url:this.getUrl(false),
7996 params:this.getParams()
8000 success : function(response){
8002 var result = this.processResponse(response);
8003 if(result === true || !result.success || !result.data){
8004 this.failureType = Roo.form.Action.LOAD_FAILURE;
8005 this.form.afterAction(this, false);
8008 this.form.clearInvalid();
8009 this.form.setValues(result.data);
8010 this.form.afterAction(this, true);
8013 handleResponse : function(response){
8014 if(this.form.reader){
8015 var rs = this.form.reader.read(response);
8016 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8018 success : rs.success,
8022 return Roo.decode(response.responseText);
8026 Roo.form.Action.ACTION_TYPES = {
8027 'load' : Roo.form.Action.Load,
8028 'submit' : Roo.form.Action.Submit
8037 * @class Roo.bootstrap.Form
8038 * @extends Roo.bootstrap.Component
8039 * Bootstrap Form class
8040 * @cfg {String} method GET | POST (default POST)
8041 * @cfg {String} labelAlign top | left (default top)
8042 * @cfg {String} align left | right - for navbars
8043 * @cfg {Boolean} loadMask load mask when submit (default true)
8048 * @param {Object} config The config object
8052 Roo.bootstrap.Form = function(config){
8054 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8056 Roo.bootstrap.Form.popover.apply();
8060 * @event clientvalidation
8061 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8062 * @param {Form} this
8063 * @param {Boolean} valid true if the form has passed client-side validation
8065 clientvalidation: true,
8067 * @event beforeaction
8068 * Fires before any action is performed. Return false to cancel the action.
8069 * @param {Form} this
8070 * @param {Action} action The action to be performed
8074 * @event actionfailed
8075 * Fires when an action fails.
8076 * @param {Form} this
8077 * @param {Action} action The action that failed
8079 actionfailed : true,
8081 * @event actioncomplete
8082 * Fires when an action is completed.
8083 * @param {Form} this
8084 * @param {Action} action The action that completed
8086 actioncomplete : true
8090 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8093 * @cfg {String} method
8094 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8099 * The URL to use for form actions if one isn't supplied in the action options.
8102 * @cfg {Boolean} fileUpload
8103 * Set to true if this form is a file upload.
8107 * @cfg {Object} baseParams
8108 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8112 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8116 * @cfg {Sting} align (left|right) for navbar forms
8121 activeAction : null,
8124 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8125 * element by passing it or its id or mask the form itself by passing in true.
8128 waitMsgTarget : false,
8133 * @cfg {Boolean} errorMask (true|false) default false
8138 * @cfg {Number} maskOffset Default 100
8143 * @cfg {Boolean} maskBody
8147 getAutoCreate : function(){
8151 method : this.method || 'POST',
8152 id : this.id || Roo.id(),
8155 if (this.parent().xtype.match(/^Nav/)) {
8156 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8160 if (this.labelAlign == 'left' ) {
8161 cfg.cls += ' form-horizontal';
8167 initEvents : function()
8169 this.el.on('submit', this.onSubmit, this);
8170 // this was added as random key presses on the form where triggering form submit.
8171 this.el.on('keypress', function(e) {
8172 if (e.getCharCode() != 13) {
8175 // we might need to allow it for textareas.. and some other items.
8176 // check e.getTarget().
8178 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8182 Roo.log("keypress blocked");
8190 onSubmit : function(e){
8195 * Returns true if client-side validation on the form is successful.
8198 isValid : function(){
8199 var items = this.getItems();
8203 items.each(function(f){
8209 Roo.log('invalid field: ' + f.name);
8213 if(!target && f.el.isVisible(true)){
8219 if(this.errorMask && !valid){
8220 Roo.bootstrap.Form.popover.mask(this, target);
8227 * Returns true if any fields in this form have changed since their original load.
8230 isDirty : function(){
8232 var items = this.getItems();
8233 items.each(function(f){
8243 * Performs a predefined action (submit or load) or custom actions you define on this form.
8244 * @param {String} actionName The name of the action type
8245 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8246 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8247 * accept other config options):
8249 Property Type Description
8250 ---------------- --------------- ----------------------------------------------------------------------------------
8251 url String The url for the action (defaults to the form's url)
8252 method String The form method to use (defaults to the form's method, or POST if not defined)
8253 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8254 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8255 validate the form on the client (defaults to false)
8257 * @return {BasicForm} this
8259 doAction : function(action, options){
8260 if(typeof action == 'string'){
8261 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8263 if(this.fireEvent('beforeaction', this, action) !== false){
8264 this.beforeAction(action);
8265 action.run.defer(100, action);
8271 beforeAction : function(action){
8272 var o = action.options;
8277 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8279 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8282 // not really supported yet.. ??
8284 //if(this.waitMsgTarget === true){
8285 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8286 //}else if(this.waitMsgTarget){
8287 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8288 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8290 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8296 afterAction : function(action, success){
8297 this.activeAction = null;
8298 var o = action.options;
8303 Roo.get(document.body).unmask();
8309 //if(this.waitMsgTarget === true){
8310 // this.el.unmask();
8311 //}else if(this.waitMsgTarget){
8312 // this.waitMsgTarget.unmask();
8314 // Roo.MessageBox.updateProgress(1);
8315 // Roo.MessageBox.hide();
8322 Roo.callback(o.success, o.scope, [this, action]);
8323 this.fireEvent('actioncomplete', this, action);
8327 // failure condition..
8328 // we have a scenario where updates need confirming.
8329 // eg. if a locking scenario exists..
8330 // we look for { errors : { needs_confirm : true }} in the response.
8332 (typeof(action.result) != 'undefined') &&
8333 (typeof(action.result.errors) != 'undefined') &&
8334 (typeof(action.result.errors.needs_confirm) != 'undefined')
8337 Roo.log("not supported yet");
8340 Roo.MessageBox.confirm(
8341 "Change requires confirmation",
8342 action.result.errorMsg,
8347 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8357 Roo.callback(o.failure, o.scope, [this, action]);
8358 // show an error message if no failed handler is set..
8359 if (!this.hasListener('actionfailed')) {
8360 Roo.log("need to add dialog support");
8362 Roo.MessageBox.alert("Error",
8363 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8364 action.result.errorMsg :
8365 "Saving Failed, please check your entries or try again"
8370 this.fireEvent('actionfailed', this, action);
8375 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8376 * @param {String} id The value to search for
8379 findField : function(id){
8380 var items = this.getItems();
8381 var field = items.get(id);
8383 items.each(function(f){
8384 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8391 return field || null;
8394 * Mark fields in this form invalid in bulk.
8395 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8396 * @return {BasicForm} this
8398 markInvalid : function(errors){
8399 if(errors instanceof Array){
8400 for(var i = 0, len = errors.length; i < len; i++){
8401 var fieldError = errors[i];
8402 var f = this.findField(fieldError.id);
8404 f.markInvalid(fieldError.msg);
8410 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8411 field.markInvalid(errors[id]);
8415 //Roo.each(this.childForms || [], function (f) {
8416 // f.markInvalid(errors);
8423 * Set values for fields in this form in bulk.
8424 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8425 * @return {BasicForm} this
8427 setValues : function(values){
8428 if(values instanceof Array){ // array of objects
8429 for(var i = 0, len = values.length; i < len; i++){
8431 var f = this.findField(v.id);
8433 f.setValue(v.value);
8434 if(this.trackResetOnLoad){
8435 f.originalValue = f.getValue();
8439 }else{ // object hash
8442 if(typeof values[id] != 'function' && (field = this.findField(id))){
8444 if (field.setFromData &&
8446 field.displayField &&
8447 // combos' with local stores can
8448 // be queried via setValue()
8449 // to set their value..
8450 (field.store && !field.store.isLocal)
8454 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8455 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8456 field.setFromData(sd);
8458 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8460 field.setFromData(values);
8463 field.setValue(values[id]);
8467 if(this.trackResetOnLoad){
8468 field.originalValue = field.getValue();
8474 //Roo.each(this.childForms || [], function (f) {
8475 // f.setValues(values);
8482 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8483 * they are returned as an array.
8484 * @param {Boolean} asString
8487 getValues : function(asString){
8488 //if (this.childForms) {
8489 // copy values from the child forms
8490 // Roo.each(this.childForms, function (f) {
8491 // this.setValues(f.getValues());
8497 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8498 if(asString === true){
8501 return Roo.urlDecode(fs);
8505 * Returns the fields in this form as an object with key/value pairs.
8506 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8509 getFieldValues : function(with_hidden)
8511 var items = this.getItems();
8513 items.each(function(f){
8519 var v = f.getValue();
8521 if (f.inputType =='radio') {
8522 if (typeof(ret[f.getName()]) == 'undefined') {
8523 ret[f.getName()] = ''; // empty..
8526 if (!f.el.dom.checked) {
8534 if(f.xtype == 'MoneyField'){
8535 ret[f.currencyName] = f.getCurrency();
8538 // not sure if this supported any more..
8539 if ((typeof(v) == 'object') && f.getRawValue) {
8540 v = f.getRawValue() ; // dates..
8542 // combo boxes where name != hiddenName...
8543 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8544 ret[f.name] = f.getRawValue();
8546 ret[f.getName()] = v;
8553 * Clears all invalid messages in this form.
8554 * @return {BasicForm} this
8556 clearInvalid : function(){
8557 var items = this.getItems();
8559 items.each(function(f){
8568 * @return {BasicForm} this
8571 var items = this.getItems();
8572 items.each(function(f){
8576 Roo.each(this.childForms || [], function (f) {
8584 getItems : function()
8586 var r=new Roo.util.MixedCollection(false, function(o){
8587 return o.id || (o.id = Roo.id());
8589 var iter = function(el) {
8596 Roo.each(el.items,function(e) {
8605 hideFields : function(items)
8607 Roo.each(items, function(i){
8609 var f = this.findField(i);
8620 showFields : function(items)
8622 Roo.each(items, function(i){
8624 var f = this.findField(i);
8637 Roo.apply(Roo.bootstrap.Form, {
8664 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8665 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8666 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8667 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8670 this.maskEl.top.enableDisplayMode("block");
8671 this.maskEl.left.enableDisplayMode("block");
8672 this.maskEl.bottom.enableDisplayMode("block");
8673 this.maskEl.right.enableDisplayMode("block");
8675 this.toolTip = new Roo.bootstrap.Tooltip({
8676 cls : 'roo-form-error-popover',
8678 'left' : ['r-l', [-2,0], 'right'],
8679 'right' : ['l-r', [2,0], 'left'],
8680 'bottom' : ['tl-bl', [0,2], 'top'],
8681 'top' : [ 'bl-tl', [0,-2], 'bottom']
8685 this.toolTip.render(Roo.get(document.body));
8687 this.toolTip.el.enableDisplayMode("block");
8689 Roo.get(document.body).on('click', function(){
8693 Roo.get(document.body).on('touchstart', function(){
8697 this.isApplied = true
8700 mask : function(form, target)
8704 this.target = target;
8706 if(!this.form.errorMask || !target.el){
8710 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8712 Roo.log(scrollable);
8714 var ot = this.target.el.calcOffsetsTo(scrollable);
8716 var scrollTo = ot[1] - this.form.maskOffset;
8718 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8720 scrollable.scrollTo('top', scrollTo);
8722 var box = this.target.el.getBox();
8724 var zIndex = Roo.bootstrap.Modal.zIndex++;
8727 this.maskEl.top.setStyle('position', 'absolute');
8728 this.maskEl.top.setStyle('z-index', zIndex);
8729 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8730 this.maskEl.top.setLeft(0);
8731 this.maskEl.top.setTop(0);
8732 this.maskEl.top.show();
8734 this.maskEl.left.setStyle('position', 'absolute');
8735 this.maskEl.left.setStyle('z-index', zIndex);
8736 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8737 this.maskEl.left.setLeft(0);
8738 this.maskEl.left.setTop(box.y - this.padding);
8739 this.maskEl.left.show();
8741 this.maskEl.bottom.setStyle('position', 'absolute');
8742 this.maskEl.bottom.setStyle('z-index', zIndex);
8743 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8744 this.maskEl.bottom.setLeft(0);
8745 this.maskEl.bottom.setTop(box.bottom + this.padding);
8746 this.maskEl.bottom.show();
8748 this.maskEl.right.setStyle('position', 'absolute');
8749 this.maskEl.right.setStyle('z-index', zIndex);
8750 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8751 this.maskEl.right.setLeft(box.right + this.padding);
8752 this.maskEl.right.setTop(box.y - this.padding);
8753 this.maskEl.right.show();
8755 this.toolTip.bindEl = this.target.el;
8757 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8759 var tip = this.target.blankText;
8761 if(this.target.getValue() !== '' ) {
8763 if (this.target.invalidText.length) {
8764 tip = this.target.invalidText;
8765 } else if (this.target.regexText.length){
8766 tip = this.target.regexText;
8770 this.toolTip.show(tip);
8772 this.intervalID = window.setInterval(function() {
8773 Roo.bootstrap.Form.popover.unmask();
8776 window.onwheel = function(){ return false;};
8778 (function(){ this.isMasked = true; }).defer(500, this);
8784 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8788 this.maskEl.top.setStyle('position', 'absolute');
8789 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8790 this.maskEl.top.hide();
8792 this.maskEl.left.setStyle('position', 'absolute');
8793 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8794 this.maskEl.left.hide();
8796 this.maskEl.bottom.setStyle('position', 'absolute');
8797 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8798 this.maskEl.bottom.hide();
8800 this.maskEl.right.setStyle('position', 'absolute');
8801 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8802 this.maskEl.right.hide();
8804 this.toolTip.hide();
8806 this.toolTip.el.hide();
8808 window.onwheel = function(){ return true;};
8810 if(this.intervalID){
8811 window.clearInterval(this.intervalID);
8812 this.intervalID = false;
8815 this.isMasked = false;
8825 * Ext JS Library 1.1.1
8826 * Copyright(c) 2006-2007, Ext JS, LLC.
8828 * Originally Released Under LGPL - original licence link has changed is not relivant.
8831 * <script type="text/javascript">
8834 * @class Roo.form.VTypes
8835 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8838 Roo.form.VTypes = function(){
8839 // closure these in so they are only created once.
8840 var alpha = /^[a-zA-Z_]+$/;
8841 var alphanum = /^[a-zA-Z0-9_]+$/;
8842 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8843 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8845 // All these messages and functions are configurable
8848 * The function used to validate email addresses
8849 * @param {String} value The email address
8851 'email' : function(v){
8852 return email.test(v);
8855 * The error text to display when the email validation function returns false
8858 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8860 * The keystroke filter mask to be applied on email input
8863 'emailMask' : /[a-z0-9_\.\-@]/i,
8866 * The function used to validate URLs
8867 * @param {String} value The URL
8869 'url' : function(v){
8873 * The error text to display when the url validation function returns false
8876 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8879 * The function used to validate alpha values
8880 * @param {String} value The value
8882 'alpha' : function(v){
8883 return alpha.test(v);
8886 * The error text to display when the alpha validation function returns false
8889 'alphaText' : 'This field should only contain letters and _',
8891 * The keystroke filter mask to be applied on alpha input
8894 'alphaMask' : /[a-z_]/i,
8897 * The function used to validate alphanumeric values
8898 * @param {String} value The value
8900 'alphanum' : function(v){
8901 return alphanum.test(v);
8904 * The error text to display when the alphanumeric validation function returns false
8907 'alphanumText' : 'This field should only contain letters, numbers and _',
8909 * The keystroke filter mask to be applied on alphanumeric input
8912 'alphanumMask' : /[a-z0-9_]/i
8922 * @class Roo.bootstrap.Input
8923 * @extends Roo.bootstrap.Component
8924 * Bootstrap Input class
8925 * @cfg {Boolean} disabled is it disabled
8926 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8927 * @cfg {String} name name of the input
8928 * @cfg {string} fieldLabel - the label associated
8929 * @cfg {string} placeholder - placeholder to put in text.
8930 * @cfg {string} before - input group add on before
8931 * @cfg {string} after - input group add on after
8932 * @cfg {string} size - (lg|sm) or leave empty..
8933 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8934 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8935 * @cfg {Number} md colspan out of 12 for computer-sized screens
8936 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8937 * @cfg {string} value default value of the input
8938 * @cfg {Number} labelWidth set the width of label
8939 * @cfg {Number} labellg set the width of label (1-12)
8940 * @cfg {Number} labelmd set the width of label (1-12)
8941 * @cfg {Number} labelsm set the width of label (1-12)
8942 * @cfg {Number} labelxs set the width of label (1-12)
8943 * @cfg {String} labelAlign (top|left)
8944 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8945 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8946 * @cfg {String} indicatorpos (left|right) default left
8947 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8948 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8950 * @cfg {String} align (left|center|right) Default left
8951 * @cfg {Boolean} forceFeedback (true|false) Default false
8954 * Create a new Input
8955 * @param {Object} config The config object
8958 Roo.bootstrap.Input = function(config){
8960 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8965 * Fires when this field receives input focus.
8966 * @param {Roo.form.Field} this
8971 * Fires when this field loses input focus.
8972 * @param {Roo.form.Field} this
8977 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
8978 * {@link Roo.EventObject#getKey} to determine which key was pressed.
8979 * @param {Roo.form.Field} this
8980 * @param {Roo.EventObject} e The event object
8985 * Fires just before the field blurs if the field value has changed.
8986 * @param {Roo.form.Field} this
8987 * @param {Mixed} newValue The new value
8988 * @param {Mixed} oldValue The original value
8993 * Fires after the field has been marked as invalid.
8994 * @param {Roo.form.Field} this
8995 * @param {String} msg The validation message
9000 * Fires after the field has been validated with no errors.
9001 * @param {Roo.form.Field} this
9006 * Fires after the key up
9007 * @param {Roo.form.Field} this
9008 * @param {Roo.EventObject} e The event Object
9014 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9016 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9017 automatic validation (defaults to "keyup").
9019 validationEvent : "keyup",
9021 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9023 validateOnBlur : true,
9025 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9027 validationDelay : 250,
9029 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9031 focusClass : "x-form-focus", // not needed???
9035 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9037 invalidClass : "has-warning",
9040 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9042 validClass : "has-success",
9045 * @cfg {Boolean} hasFeedback (true|false) default true
9050 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9052 invalidFeedbackClass : "glyphicon-warning-sign",
9055 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9057 validFeedbackClass : "glyphicon-ok",
9060 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9062 selectOnFocus : false,
9065 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9069 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9074 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9076 disableKeyFilter : false,
9079 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9083 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9087 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9089 blankText : "Please complete this mandatory field",
9092 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9096 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9098 maxLength : Number.MAX_VALUE,
9100 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9102 minLengthText : "The minimum length for this field is {0}",
9104 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9106 maxLengthText : "The maximum length for this field is {0}",
9110 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9111 * If available, this function will be called only after the basic validators all return true, and will be passed the
9112 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9116 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9117 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9118 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9122 * @cfg {String} regexText -- Depricated - use Invalid Text
9127 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9133 autocomplete: false,
9152 formatedValue : false,
9153 forceFeedback : false,
9155 indicatorpos : 'left',
9165 parentLabelAlign : function()
9168 while (parent.parent()) {
9169 parent = parent.parent();
9170 if (typeof(parent.labelAlign) !='undefined') {
9171 return parent.labelAlign;
9178 getAutoCreate : function()
9180 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9186 if(this.inputType != 'hidden'){
9187 cfg.cls = 'form-group' //input-group
9193 type : this.inputType,
9195 cls : 'form-control',
9196 placeholder : this.placeholder || '',
9197 autocomplete : this.autocomplete || 'new-password'
9200 if(this.capture.length){
9201 input.capture = this.capture;
9204 if(this.accept.length){
9205 input.accept = this.accept + "/*";
9209 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9212 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9213 input.maxLength = this.maxLength;
9216 if (this.disabled) {
9217 input.disabled=true;
9220 if (this.readOnly) {
9221 input.readonly=true;
9225 input.name = this.name;
9229 input.cls += ' input-' + this.size;
9233 ['xs','sm','md','lg'].map(function(size){
9234 if (settings[size]) {
9235 cfg.cls += ' col-' + size + '-' + settings[size];
9239 var inputblock = input;
9243 cls: 'glyphicon form-control-feedback'
9246 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9249 cls : 'has-feedback',
9257 if (this.before || this.after) {
9260 cls : 'input-group',
9264 if (this.before && typeof(this.before) == 'string') {
9266 inputblock.cn.push({
9268 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9272 if (this.before && typeof(this.before) == 'object') {
9273 this.before = Roo.factory(this.before);
9275 inputblock.cn.push({
9277 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9278 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9282 inputblock.cn.push(input);
9284 if (this.after && typeof(this.after) == 'string') {
9285 inputblock.cn.push({
9287 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9291 if (this.after && typeof(this.after) == 'object') {
9292 this.after = Roo.factory(this.after);
9294 inputblock.cn.push({
9296 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9297 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9301 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9302 inputblock.cls += ' has-feedback';
9303 inputblock.cn.push(feedback);
9308 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9309 tooltip : 'This field is required'
9311 if (Roo.bootstrap.version == 4) {
9314 style : 'display-none'
9317 if (align ==='left' && this.fieldLabel.length) {
9319 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9326 cls : 'control-label col-form-label',
9327 html : this.fieldLabel
9338 var labelCfg = cfg.cn[1];
9339 var contentCfg = cfg.cn[2];
9341 if(this.indicatorpos == 'right'){
9346 cls : 'control-label col-form-label',
9350 html : this.fieldLabel
9364 labelCfg = cfg.cn[0];
9365 contentCfg = cfg.cn[1];
9369 if(this.labelWidth > 12){
9370 labelCfg.style = "width: " + this.labelWidth + 'px';
9373 if(this.labelWidth < 13 && this.labelmd == 0){
9374 this.labelmd = this.labelWidth;
9377 if(this.labellg > 0){
9378 labelCfg.cls += ' col-lg-' + this.labellg;
9379 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9382 if(this.labelmd > 0){
9383 labelCfg.cls += ' col-md-' + this.labelmd;
9384 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9387 if(this.labelsm > 0){
9388 labelCfg.cls += ' col-sm-' + this.labelsm;
9389 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9392 if(this.labelxs > 0){
9393 labelCfg.cls += ' col-xs-' + this.labelxs;
9394 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9398 } else if ( this.fieldLabel.length) {
9403 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9404 tooltip : 'This field is required'
9408 //cls : 'input-group-addon',
9409 html : this.fieldLabel
9417 if(this.indicatorpos == 'right'){
9422 //cls : 'input-group-addon',
9423 html : this.fieldLabel
9428 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9429 tooltip : 'This field is required'
9449 if (this.parentType === 'Navbar' && this.parent().bar) {
9450 cfg.cls += ' navbar-form';
9453 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9454 // on BS4 we do this only if not form
9455 cfg.cls += ' navbar-form';
9463 * return the real input element.
9465 inputEl: function ()
9467 return this.el.select('input.form-control',true).first();
9470 tooltipEl : function()
9472 return this.inputEl();
9475 indicatorEl : function()
9477 if (Roo.bootstrap.version == 4) {
9478 return false; // not enabled in v4 yet.
9481 var indicator = this.el.select('i.roo-required-indicator',true).first();
9491 setDisabled : function(v)
9493 var i = this.inputEl().dom;
9495 i.removeAttribute('disabled');
9499 i.setAttribute('disabled','true');
9501 initEvents : function()
9504 this.inputEl().on("keydown" , this.fireKey, this);
9505 this.inputEl().on("focus", this.onFocus, this);
9506 this.inputEl().on("blur", this.onBlur, this);
9508 this.inputEl().relayEvent('keyup', this);
9510 this.indicator = this.indicatorEl();
9513 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9516 // reference to original value for reset
9517 this.originalValue = this.getValue();
9518 //Roo.form.TextField.superclass.initEvents.call(this);
9519 if(this.validationEvent == 'keyup'){
9520 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9521 this.inputEl().on('keyup', this.filterValidation, this);
9523 else if(this.validationEvent !== false){
9524 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9527 if(this.selectOnFocus){
9528 this.on("focus", this.preFocus, this);
9531 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9532 this.inputEl().on("keypress", this.filterKeys, this);
9534 this.inputEl().relayEvent('keypress', this);
9537 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9538 this.el.on("click", this.autoSize, this);
9541 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9542 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9545 if (typeof(this.before) == 'object') {
9546 this.before.render(this.el.select('.roo-input-before',true).first());
9548 if (typeof(this.after) == 'object') {
9549 this.after.render(this.el.select('.roo-input-after',true).first());
9552 this.inputEl().on('change', this.onChange, this);
9555 filterValidation : function(e){
9556 if(!e.isNavKeyPress()){
9557 this.validationTask.delay(this.validationDelay);
9561 * Validates the field value
9562 * @return {Boolean} True if the value is valid, else false
9564 validate : function(){
9565 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9566 if(this.disabled || this.validateValue(this.getRawValue())){
9577 * Validates a value according to the field's validation rules and marks the field as invalid
9578 * if the validation fails
9579 * @param {Mixed} value The value to validate
9580 * @return {Boolean} True if the value is valid, else false
9582 validateValue : function(value)
9584 if(this.getVisibilityEl().hasClass('hidden')){
9588 if(value.length < 1) { // if it's blank
9589 if(this.allowBlank){
9595 if(value.length < this.minLength){
9598 if(value.length > this.maxLength){
9602 var vt = Roo.form.VTypes;
9603 if(!vt[this.vtype](value, this)){
9607 if(typeof this.validator == "function"){
9608 var msg = this.validator(value);
9612 if (typeof(msg) == 'string') {
9613 this.invalidText = msg;
9617 if(this.regex && !this.regex.test(value)){
9625 fireKey : function(e){
9626 //Roo.log('field ' + e.getKey());
9627 if(e.isNavKeyPress()){
9628 this.fireEvent("specialkey", this, e);
9631 focus : function (selectText){
9633 this.inputEl().focus();
9634 if(selectText === true){
9635 this.inputEl().dom.select();
9641 onFocus : function(){
9642 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9643 // this.el.addClass(this.focusClass);
9646 this.hasFocus = true;
9647 this.startValue = this.getValue();
9648 this.fireEvent("focus", this);
9652 beforeBlur : Roo.emptyFn,
9656 onBlur : function(){
9658 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9659 //this.el.removeClass(this.focusClass);
9661 this.hasFocus = false;
9662 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9665 var v = this.getValue();
9666 if(String(v) !== String(this.startValue)){
9667 this.fireEvent('change', this, v, this.startValue);
9669 this.fireEvent("blur", this);
9672 onChange : function(e)
9674 var v = this.getValue();
9675 if(String(v) !== String(this.startValue)){
9676 this.fireEvent('change', this, v, this.startValue);
9682 * Resets the current field value to the originally loaded value and clears any validation messages
9685 this.setValue(this.originalValue);
9689 * Returns the name of the field
9690 * @return {Mixed} name The name field
9692 getName: function(){
9696 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9697 * @return {Mixed} value The field value
9699 getValue : function(){
9701 var v = this.inputEl().getValue();
9706 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9707 * @return {Mixed} value The field value
9709 getRawValue : function(){
9710 var v = this.inputEl().getValue();
9716 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9717 * @param {Mixed} value The value to set
9719 setRawValue : function(v){
9720 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9723 selectText : function(start, end){
9724 var v = this.getRawValue();
9726 start = start === undefined ? 0 : start;
9727 end = end === undefined ? v.length : end;
9728 var d = this.inputEl().dom;
9729 if(d.setSelectionRange){
9730 d.setSelectionRange(start, end);
9731 }else if(d.createTextRange){
9732 var range = d.createTextRange();
9733 range.moveStart("character", start);
9734 range.moveEnd("character", v.length-end);
9741 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9742 * @param {Mixed} value The value to set
9744 setValue : function(v){
9747 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9753 processValue : function(value){
9754 if(this.stripCharsRe){
9755 var newValue = value.replace(this.stripCharsRe, '');
9756 if(newValue !== value){
9757 this.setRawValue(newValue);
9764 preFocus : function(){
9766 if(this.selectOnFocus){
9767 this.inputEl().dom.select();
9770 filterKeys : function(e){
9772 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9775 var c = e.getCharCode(), cc = String.fromCharCode(c);
9776 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9779 if(!this.maskRe.test(cc)){
9784 * Clear any invalid styles/messages for this field
9786 clearInvalid : function(){
9788 if(!this.el || this.preventMark){ // not rendered
9793 this.el.removeClass([this.invalidClass, 'is-invalid']);
9795 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9797 var feedback = this.el.select('.form-control-feedback', true).first();
9800 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9806 this.indicator.removeClass('visible');
9807 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9810 this.fireEvent('valid', this);
9814 * Mark this field as valid
9816 markValid : function()
9818 if(!this.el || this.preventMark){ // not rendered...
9822 this.el.removeClass([this.invalidClass, this.validClass]);
9823 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9825 var feedback = this.el.select('.form-control-feedback', true).first();
9828 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9832 this.indicator.removeClass('visible');
9833 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9840 if(this.allowBlank && !this.getRawValue().length){
9843 if (Roo.bootstrap.version == 3) {
9844 this.el.addClass(this.validClass);
9846 this.inputEl().addClass('is-valid');
9849 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9851 var feedback = this.el.select('.form-control-feedback', true).first();
9854 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9855 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9860 this.fireEvent('valid', this);
9864 * Mark this field as invalid
9865 * @param {String} msg The validation message
9867 markInvalid : function(msg)
9869 if(!this.el || this.preventMark){ // not rendered
9873 this.el.removeClass([this.invalidClass, this.validClass]);
9874 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9876 var feedback = this.el.select('.form-control-feedback', true).first();
9879 this.el.select('.form-control-feedback', true).first().removeClass(
9880 [this.invalidFeedbackClass, this.validFeedbackClass]);
9887 if(this.allowBlank && !this.getRawValue().length){
9892 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9893 this.indicator.addClass('visible');
9895 if (Roo.bootstrap.version == 3) {
9896 this.el.addClass(this.invalidClass);
9898 this.inputEl().addClass('is-invalid');
9903 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9905 var feedback = this.el.select('.form-control-feedback', true).first();
9908 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9910 if(this.getValue().length || this.forceFeedback){
9911 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9918 this.fireEvent('invalid', this, msg);
9921 SafariOnKeyDown : function(event)
9923 // this is a workaround for a password hang bug on chrome/ webkit.
9924 if (this.inputEl().dom.type != 'password') {
9928 var isSelectAll = false;
9930 if(this.inputEl().dom.selectionEnd > 0){
9931 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9933 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9934 event.preventDefault();
9939 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9941 event.preventDefault();
9942 // this is very hacky as keydown always get's upper case.
9944 var cc = String.fromCharCode(event.getCharCode());
9945 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9949 adjustWidth : function(tag, w){
9950 tag = tag.toLowerCase();
9951 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9952 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9956 if(tag == 'textarea'){
9959 }else if(Roo.isOpera){
9963 if(tag == 'textarea'){
9971 setFieldLabel : function(v)
9977 if(this.indicatorEl()){
9978 var ar = this.el.select('label > span',true);
9980 if (ar.elements.length) {
9981 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9982 this.fieldLabel = v;
9986 var br = this.el.select('label',true);
9988 if(br.elements.length) {
9989 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9990 this.fieldLabel = v;
9994 Roo.log('Cannot Found any of label > span || label in input');
9998 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
9999 this.fieldLabel = v;
10014 * @class Roo.bootstrap.TextArea
10015 * @extends Roo.bootstrap.Input
10016 * Bootstrap TextArea class
10017 * @cfg {Number} cols Specifies the visible width of a text area
10018 * @cfg {Number} rows Specifies the visible number of lines in a text area
10019 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10020 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10021 * @cfg {string} html text
10024 * Create a new TextArea
10025 * @param {Object} config The config object
10028 Roo.bootstrap.TextArea = function(config){
10029 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10033 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10043 getAutoCreate : function(){
10045 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10051 if(this.inputType != 'hidden'){
10052 cfg.cls = 'form-group' //input-group
10060 value : this.value || '',
10061 html: this.html || '',
10062 cls : 'form-control',
10063 placeholder : this.placeholder || ''
10067 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10068 input.maxLength = this.maxLength;
10072 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10076 input.cols = this.cols;
10079 if (this.readOnly) {
10080 input.readonly = true;
10084 input.name = this.name;
10088 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10092 ['xs','sm','md','lg'].map(function(size){
10093 if (settings[size]) {
10094 cfg.cls += ' col-' + size + '-' + settings[size];
10098 var inputblock = input;
10100 if(this.hasFeedback && !this.allowBlank){
10104 cls: 'glyphicon form-control-feedback'
10108 cls : 'has-feedback',
10117 if (this.before || this.after) {
10120 cls : 'input-group',
10124 inputblock.cn.push({
10126 cls : 'input-group-addon',
10131 inputblock.cn.push(input);
10133 if(this.hasFeedback && !this.allowBlank){
10134 inputblock.cls += ' has-feedback';
10135 inputblock.cn.push(feedback);
10139 inputblock.cn.push({
10141 cls : 'input-group-addon',
10148 if (align ==='left' && this.fieldLabel.length) {
10153 cls : 'control-label',
10154 html : this.fieldLabel
10165 if(this.labelWidth > 12){
10166 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10169 if(this.labelWidth < 13 && this.labelmd == 0){
10170 this.labelmd = this.labelWidth;
10173 if(this.labellg > 0){
10174 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10175 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10178 if(this.labelmd > 0){
10179 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10180 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10183 if(this.labelsm > 0){
10184 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10185 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10188 if(this.labelxs > 0){
10189 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10190 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10193 } else if ( this.fieldLabel.length) {
10198 //cls : 'input-group-addon',
10199 html : this.fieldLabel
10217 if (this.disabled) {
10218 input.disabled=true;
10225 * return the real textarea element.
10227 inputEl: function ()
10229 return this.el.select('textarea.form-control',true).first();
10233 * Clear any invalid styles/messages for this field
10235 clearInvalid : function()
10238 if(!this.el || this.preventMark){ // not rendered
10242 var label = this.el.select('label', true).first();
10243 var icon = this.el.select('i.fa-star', true).first();
10248 this.el.removeClass( this.validClass);
10249 this.inputEl().removeClass('is-invalid');
10251 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10253 var feedback = this.el.select('.form-control-feedback', true).first();
10256 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10261 this.fireEvent('valid', this);
10265 * Mark this field as valid
10267 markValid : function()
10269 if(!this.el || this.preventMark){ // not rendered
10273 this.el.removeClass([this.invalidClass, this.validClass]);
10274 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10276 var feedback = this.el.select('.form-control-feedback', true).first();
10279 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10282 if(this.disabled || this.allowBlank){
10286 var label = this.el.select('label', true).first();
10287 var icon = this.el.select('i.fa-star', true).first();
10292 if (Roo.bootstrap.version == 3) {
10293 this.el.addClass(this.validClass);
10295 this.inputEl().addClass('is-valid');
10299 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10301 var feedback = this.el.select('.form-control-feedback', true).first();
10304 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10305 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10310 this.fireEvent('valid', this);
10314 * Mark this field as invalid
10315 * @param {String} msg The validation message
10317 markInvalid : function(msg)
10319 if(!this.el || this.preventMark){ // not rendered
10323 this.el.removeClass([this.invalidClass, this.validClass]);
10324 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10326 var feedback = this.el.select('.form-control-feedback', true).first();
10329 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10332 if(this.disabled || this.allowBlank){
10336 var label = this.el.select('label', true).first();
10337 var icon = this.el.select('i.fa-star', true).first();
10339 if(!this.getValue().length && label && !icon){
10340 this.el.createChild({
10342 cls : 'text-danger fa fa-lg fa-star',
10343 tooltip : 'This field is required',
10344 style : 'margin-right:5px;'
10348 if (Roo.bootstrap.version == 3) {
10349 this.el.addClass(this.invalidClass);
10351 this.inputEl().addClass('is-invalid');
10354 // fixme ... this may be depricated need to test..
10355 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10357 var feedback = this.el.select('.form-control-feedback', true).first();
10360 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10362 if(this.getValue().length || this.forceFeedback){
10363 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10370 this.fireEvent('invalid', this, msg);
10378 * trigger field - base class for combo..
10383 * @class Roo.bootstrap.TriggerField
10384 * @extends Roo.bootstrap.Input
10385 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10386 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10387 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10388 * for which you can provide a custom implementation. For example:
10390 var trigger = new Roo.bootstrap.TriggerField();
10391 trigger.onTriggerClick = myTriggerFn;
10392 trigger.applyTo('my-field');
10395 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10396 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10397 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10398 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10399 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10402 * Create a new TriggerField.
10403 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10404 * to the base TextField)
10406 Roo.bootstrap.TriggerField = function(config){
10407 this.mimicing = false;
10408 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10411 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10413 * @cfg {String} triggerClass A CSS class to apply to the trigger
10416 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10421 * @cfg {Boolean} removable (true|false) special filter default false
10425 /** @cfg {Boolean} grow @hide */
10426 /** @cfg {Number} growMin @hide */
10427 /** @cfg {Number} growMax @hide */
10433 autoSize: Roo.emptyFn,
10437 deferHeight : true,
10440 actionMode : 'wrap',
10445 getAutoCreate : function(){
10447 var align = this.labelAlign || this.parentLabelAlign();
10452 cls: 'form-group' //input-group
10459 type : this.inputType,
10460 cls : 'form-control',
10461 autocomplete: 'new-password',
10462 placeholder : this.placeholder || ''
10466 input.name = this.name;
10469 input.cls += ' input-' + this.size;
10472 if (this.disabled) {
10473 input.disabled=true;
10476 var inputblock = input;
10478 if(this.hasFeedback && !this.allowBlank){
10482 cls: 'glyphicon form-control-feedback'
10485 if(this.removable && !this.editable && !this.tickable){
10487 cls : 'has-feedback',
10493 cls : 'roo-combo-removable-btn close'
10500 cls : 'has-feedback',
10509 if(this.removable && !this.editable && !this.tickable){
10511 cls : 'roo-removable',
10517 cls : 'roo-combo-removable-btn close'
10524 if (this.before || this.after) {
10527 cls : 'input-group',
10531 inputblock.cn.push({
10533 cls : 'input-group-addon input-group-prepend input-group-text',
10538 inputblock.cn.push(input);
10540 if(this.hasFeedback && !this.allowBlank){
10541 inputblock.cls += ' has-feedback';
10542 inputblock.cn.push(feedback);
10546 inputblock.cn.push({
10548 cls : 'input-group-addon input-group-append input-group-text',
10557 var ibwrap = inputblock;
10562 cls: 'roo-select2-choices',
10566 cls: 'roo-select2-search-field',
10578 cls: 'roo-select2-container input-group',
10583 cls: 'form-hidden-field'
10589 if(!this.multiple && this.showToggleBtn){
10595 if (this.caret != false) {
10598 cls: 'fa fa-' + this.caret
10605 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10610 cls: 'combobox-clear',
10624 combobox.cls += ' roo-select2-container-multi';
10628 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10629 tooltip : 'This field is required'
10631 if (Roo.bootstrap.version == 4) {
10634 style : 'display:none'
10639 if (align ==='left' && this.fieldLabel.length) {
10641 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10648 cls : 'control-label',
10649 html : this.fieldLabel
10661 var labelCfg = cfg.cn[1];
10662 var contentCfg = cfg.cn[2];
10664 if(this.indicatorpos == 'right'){
10669 cls : 'control-label',
10673 html : this.fieldLabel
10687 labelCfg = cfg.cn[0];
10688 contentCfg = cfg.cn[1];
10691 if(this.labelWidth > 12){
10692 labelCfg.style = "width: " + this.labelWidth + 'px';
10695 if(this.labelWidth < 13 && this.labelmd == 0){
10696 this.labelmd = this.labelWidth;
10699 if(this.labellg > 0){
10700 labelCfg.cls += ' col-lg-' + this.labellg;
10701 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10704 if(this.labelmd > 0){
10705 labelCfg.cls += ' col-md-' + this.labelmd;
10706 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10709 if(this.labelsm > 0){
10710 labelCfg.cls += ' col-sm-' + this.labelsm;
10711 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10714 if(this.labelxs > 0){
10715 labelCfg.cls += ' col-xs-' + this.labelxs;
10716 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10719 } else if ( this.fieldLabel.length) {
10720 // Roo.log(" label");
10725 //cls : 'input-group-addon',
10726 html : this.fieldLabel
10734 if(this.indicatorpos == 'right'){
10742 html : this.fieldLabel
10756 // Roo.log(" no label && no align");
10763 ['xs','sm','md','lg'].map(function(size){
10764 if (settings[size]) {
10765 cfg.cls += ' col-' + size + '-' + settings[size];
10776 onResize : function(w, h){
10777 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10778 // if(typeof w == 'number'){
10779 // var x = w - this.trigger.getWidth();
10780 // this.inputEl().setWidth(this.adjustWidth('input', x));
10781 // this.trigger.setStyle('left', x+'px');
10786 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10789 getResizeEl : function(){
10790 return this.inputEl();
10794 getPositionEl : function(){
10795 return this.inputEl();
10799 alignErrorIcon : function(){
10800 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10804 initEvents : function(){
10808 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10809 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10810 if(!this.multiple && this.showToggleBtn){
10811 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10812 if(this.hideTrigger){
10813 this.trigger.setDisplayed(false);
10815 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10819 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10822 if(this.removable && !this.editable && !this.tickable){
10823 var close = this.closeTriggerEl();
10826 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10827 close.on('click', this.removeBtnClick, this, close);
10831 //this.trigger.addClassOnOver('x-form-trigger-over');
10832 //this.trigger.addClassOnClick('x-form-trigger-click');
10835 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10839 closeTriggerEl : function()
10841 var close = this.el.select('.roo-combo-removable-btn', true).first();
10842 return close ? close : false;
10845 removeBtnClick : function(e, h, el)
10847 e.preventDefault();
10849 if(this.fireEvent("remove", this) !== false){
10851 this.fireEvent("afterremove", this)
10855 createList : function()
10857 this.list = Roo.get(document.body).createChild({
10858 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10859 cls: 'typeahead typeahead-long dropdown-menu',
10860 style: 'display:none'
10863 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10868 initTrigger : function(){
10873 onDestroy : function(){
10875 this.trigger.removeAllListeners();
10876 // this.trigger.remove();
10879 // this.wrap.remove();
10881 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10885 onFocus : function(){
10886 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10888 if(!this.mimicing){
10889 this.wrap.addClass('x-trigger-wrap-focus');
10890 this.mimicing = true;
10891 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10892 if(this.monitorTab){
10893 this.el.on("keydown", this.checkTab, this);
10900 checkTab : function(e){
10901 if(e.getKey() == e.TAB){
10902 this.triggerBlur();
10907 onBlur : function(){
10912 mimicBlur : function(e, t){
10914 if(!this.wrap.contains(t) && this.validateBlur()){
10915 this.triggerBlur();
10921 triggerBlur : function(){
10922 this.mimicing = false;
10923 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10924 if(this.monitorTab){
10925 this.el.un("keydown", this.checkTab, this);
10927 //this.wrap.removeClass('x-trigger-wrap-focus');
10928 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10932 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10933 validateBlur : function(e, t){
10938 onDisable : function(){
10939 this.inputEl().dom.disabled = true;
10940 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10942 // this.wrap.addClass('x-item-disabled');
10947 onEnable : function(){
10948 this.inputEl().dom.disabled = false;
10949 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10951 // this.el.removeClass('x-item-disabled');
10956 onShow : function(){
10957 var ae = this.getActionEl();
10960 ae.dom.style.display = '';
10961 ae.dom.style.visibility = 'visible';
10967 onHide : function(){
10968 var ae = this.getActionEl();
10969 ae.dom.style.display = 'none';
10973 * The function that should handle the trigger's click event. This method does nothing by default until overridden
10974 * by an implementing function.
10976 * @param {EventObject} e
10978 onTriggerClick : Roo.emptyFn
10982 * Ext JS Library 1.1.1
10983 * Copyright(c) 2006-2007, Ext JS, LLC.
10985 * Originally Released Under LGPL - original licence link has changed is not relivant.
10988 * <script type="text/javascript">
10993 * @class Roo.data.SortTypes
10995 * Defines the default sorting (casting?) comparison functions used when sorting data.
10997 Roo.data.SortTypes = {
10999 * Default sort that does nothing
11000 * @param {Mixed} s The value being converted
11001 * @return {Mixed} The comparison value
11003 none : function(s){
11008 * The regular expression used to strip tags
11012 stripTagsRE : /<\/?[^>]+>/gi,
11015 * Strips all HTML tags to sort on text only
11016 * @param {Mixed} s The value being converted
11017 * @return {String} The comparison value
11019 asText : function(s){
11020 return String(s).replace(this.stripTagsRE, "");
11024 * Strips all HTML tags to sort on text only - Case insensitive
11025 * @param {Mixed} s The value being converted
11026 * @return {String} The comparison value
11028 asUCText : function(s){
11029 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11033 * Case insensitive string
11034 * @param {Mixed} s The value being converted
11035 * @return {String} The comparison value
11037 asUCString : function(s) {
11038 return String(s).toUpperCase();
11043 * @param {Mixed} s The value being converted
11044 * @return {Number} The comparison value
11046 asDate : function(s) {
11050 if(s instanceof Date){
11051 return s.getTime();
11053 return Date.parse(String(s));
11058 * @param {Mixed} s The value being converted
11059 * @return {Float} The comparison value
11061 asFloat : function(s) {
11062 var val = parseFloat(String(s).replace(/,/g, ""));
11071 * @param {Mixed} s The value being converted
11072 * @return {Number} The comparison value
11074 asInt : function(s) {
11075 var val = parseInt(String(s).replace(/,/g, ""));
11083 * Ext JS Library 1.1.1
11084 * Copyright(c) 2006-2007, Ext JS, LLC.
11086 * Originally Released Under LGPL - original licence link has changed is not relivant.
11089 * <script type="text/javascript">
11093 * @class Roo.data.Record
11094 * Instances of this class encapsulate both record <em>definition</em> information, and record
11095 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11096 * to access Records cached in an {@link Roo.data.Store} object.<br>
11098 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11099 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11102 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11104 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11105 * {@link #create}. The parameters are the same.
11106 * @param {Array} data An associative Array of data values keyed by the field name.
11107 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11108 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11109 * not specified an integer id is generated.
11111 Roo.data.Record = function(data, id){
11112 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11117 * Generate a constructor for a specific record layout.
11118 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11119 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11120 * Each field definition object may contain the following properties: <ul>
11121 * <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,
11122 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11123 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11124 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11125 * is being used, then this is a string containing the javascript expression to reference the data relative to
11126 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11127 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11128 * this may be omitted.</p></li>
11129 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11130 * <ul><li>auto (Default, implies no conversion)</li>
11135 * <li>date</li></ul></p></li>
11136 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11137 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11138 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11139 * by the Reader into an object that will be stored in the Record. It is passed the
11140 * following parameters:<ul>
11141 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11143 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11145 * <br>usage:<br><pre><code>
11146 var TopicRecord = Roo.data.Record.create(
11147 {name: 'title', mapping: 'topic_title'},
11148 {name: 'author', mapping: 'username'},
11149 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11150 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11151 {name: 'lastPoster', mapping: 'user2'},
11152 {name: 'excerpt', mapping: 'post_text'}
11155 var myNewRecord = new TopicRecord({
11156 title: 'Do my job please',
11159 lastPost: new Date(),
11160 lastPoster: 'Animal',
11161 excerpt: 'No way dude!'
11163 myStore.add(myNewRecord);
11168 Roo.data.Record.create = function(o){
11169 var f = function(){
11170 f.superclass.constructor.apply(this, arguments);
11172 Roo.extend(f, Roo.data.Record);
11173 var p = f.prototype;
11174 p.fields = new Roo.util.MixedCollection(false, function(field){
11177 for(var i = 0, len = o.length; i < len; i++){
11178 p.fields.add(new Roo.data.Field(o[i]));
11180 f.getField = function(name){
11181 return p.fields.get(name);
11186 Roo.data.Record.AUTO_ID = 1000;
11187 Roo.data.Record.EDIT = 'edit';
11188 Roo.data.Record.REJECT = 'reject';
11189 Roo.data.Record.COMMIT = 'commit';
11191 Roo.data.Record.prototype = {
11193 * Readonly flag - true if this record has been modified.
11202 join : function(store){
11203 this.store = store;
11207 * Set the named field to the specified value.
11208 * @param {String} name The name of the field to set.
11209 * @param {Object} value The value to set the field to.
11211 set : function(name, value){
11212 if(this.data[name] == value){
11216 if(!this.modified){
11217 this.modified = {};
11219 if(typeof this.modified[name] == 'undefined'){
11220 this.modified[name] = this.data[name];
11222 this.data[name] = value;
11223 if(!this.editing && this.store){
11224 this.store.afterEdit(this);
11229 * Get the value of the named field.
11230 * @param {String} name The name of the field to get the value of.
11231 * @return {Object} The value of the field.
11233 get : function(name){
11234 return this.data[name];
11238 beginEdit : function(){
11239 this.editing = true;
11240 this.modified = {};
11244 cancelEdit : function(){
11245 this.editing = false;
11246 delete this.modified;
11250 endEdit : function(){
11251 this.editing = false;
11252 if(this.dirty && this.store){
11253 this.store.afterEdit(this);
11258 * Usually called by the {@link Roo.data.Store} which owns the Record.
11259 * Rejects all changes made to the Record since either creation, or the last commit operation.
11260 * Modified fields are reverted to their original values.
11262 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11263 * of reject operations.
11265 reject : function(){
11266 var m = this.modified;
11268 if(typeof m[n] != "function"){
11269 this.data[n] = m[n];
11272 this.dirty = false;
11273 delete this.modified;
11274 this.editing = false;
11276 this.store.afterReject(this);
11281 * Usually called by the {@link Roo.data.Store} which owns the Record.
11282 * Commits all changes made to the Record since either creation, or the last commit operation.
11284 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11285 * of commit operations.
11287 commit : function(){
11288 this.dirty = false;
11289 delete this.modified;
11290 this.editing = false;
11292 this.store.afterCommit(this);
11297 hasError : function(){
11298 return this.error != null;
11302 clearError : function(){
11307 * Creates a copy of this record.
11308 * @param {String} id (optional) A new record id if you don't want to use this record's id
11311 copy : function(newId) {
11312 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11316 * Ext JS Library 1.1.1
11317 * Copyright(c) 2006-2007, Ext JS, LLC.
11319 * Originally Released Under LGPL - original licence link has changed is not relivant.
11322 * <script type="text/javascript">
11328 * @class Roo.data.Store
11329 * @extends Roo.util.Observable
11330 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11331 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11333 * 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
11334 * has no knowledge of the format of the data returned by the Proxy.<br>
11336 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11337 * instances from the data object. These records are cached and made available through accessor functions.
11339 * Creates a new Store.
11340 * @param {Object} config A config object containing the objects needed for the Store to access data,
11341 * and read the data into Records.
11343 Roo.data.Store = function(config){
11344 this.data = new Roo.util.MixedCollection(false);
11345 this.data.getKey = function(o){
11348 this.baseParams = {};
11350 this.paramNames = {
11355 "multisort" : "_multisort"
11358 if(config && config.data){
11359 this.inlineData = config.data;
11360 delete config.data;
11363 Roo.apply(this, config);
11365 if(this.reader){ // reader passed
11366 this.reader = Roo.factory(this.reader, Roo.data);
11367 this.reader.xmodule = this.xmodule || false;
11368 if(!this.recordType){
11369 this.recordType = this.reader.recordType;
11371 if(this.reader.onMetaChange){
11372 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11376 if(this.recordType){
11377 this.fields = this.recordType.prototype.fields;
11379 this.modified = [];
11383 * @event datachanged
11384 * Fires when the data cache has changed, and a widget which is using this Store
11385 * as a Record cache should refresh its view.
11386 * @param {Store} this
11388 datachanged : true,
11390 * @event metachange
11391 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11392 * @param {Store} this
11393 * @param {Object} meta The JSON metadata
11398 * Fires when Records have been added to the Store
11399 * @param {Store} this
11400 * @param {Roo.data.Record[]} records The array of Records added
11401 * @param {Number} index The index at which the record(s) were added
11406 * Fires when a Record has been removed from the Store
11407 * @param {Store} this
11408 * @param {Roo.data.Record} record The Record that was removed
11409 * @param {Number} index The index at which the record was removed
11414 * Fires when a Record has been updated
11415 * @param {Store} this
11416 * @param {Roo.data.Record} record The Record that was updated
11417 * @param {String} operation The update operation being performed. Value may be one of:
11419 Roo.data.Record.EDIT
11420 Roo.data.Record.REJECT
11421 Roo.data.Record.COMMIT
11427 * Fires when the data cache has been cleared.
11428 * @param {Store} this
11432 * @event beforeload
11433 * Fires before a request is made for a new data object. If the beforeload handler returns false
11434 * the load action will be canceled.
11435 * @param {Store} this
11436 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11440 * @event beforeloadadd
11441 * Fires after a new set of Records has been loaded.
11442 * @param {Store} this
11443 * @param {Roo.data.Record[]} records The Records that were loaded
11444 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11446 beforeloadadd : true,
11449 * Fires after a new set of Records has been loaded, before they are added to the store.
11450 * @param {Store} this
11451 * @param {Roo.data.Record[]} records The Records that were loaded
11452 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11453 * @params {Object} return from reader
11457 * @event loadexception
11458 * Fires if an exception occurs in the Proxy during loading.
11459 * Called with the signature of the Proxy's "loadexception" event.
11460 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11463 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11464 * @param {Object} load options
11465 * @param {Object} jsonData from your request (normally this contains the Exception)
11467 loadexception : true
11471 this.proxy = Roo.factory(this.proxy, Roo.data);
11472 this.proxy.xmodule = this.xmodule || false;
11473 this.relayEvents(this.proxy, ["loadexception"]);
11475 this.sortToggle = {};
11476 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11478 Roo.data.Store.superclass.constructor.call(this);
11480 if(this.inlineData){
11481 this.loadData(this.inlineData);
11482 delete this.inlineData;
11486 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11488 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11489 * without a remote query - used by combo/forms at present.
11493 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11496 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11499 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11500 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11503 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11504 * on any HTTP request
11507 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11510 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11514 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11515 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11517 remoteSort : false,
11520 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11521 * loaded or when a record is removed. (defaults to false).
11523 pruneModifiedRecords : false,
11526 lastOptions : null,
11529 * Add Records to the Store and fires the add event.
11530 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11532 add : function(records){
11533 records = [].concat(records);
11534 for(var i = 0, len = records.length; i < len; i++){
11535 records[i].join(this);
11537 var index = this.data.length;
11538 this.data.addAll(records);
11539 this.fireEvent("add", this, records, index);
11543 * Remove a Record from the Store and fires the remove event.
11544 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11546 remove : function(record){
11547 var index = this.data.indexOf(record);
11548 this.data.removeAt(index);
11550 if(this.pruneModifiedRecords){
11551 this.modified.remove(record);
11553 this.fireEvent("remove", this, record, index);
11557 * Remove all Records from the Store and fires the clear event.
11559 removeAll : function(){
11561 if(this.pruneModifiedRecords){
11562 this.modified = [];
11564 this.fireEvent("clear", this);
11568 * Inserts Records to the Store at the given index and fires the add event.
11569 * @param {Number} index The start index at which to insert the passed Records.
11570 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11572 insert : function(index, records){
11573 records = [].concat(records);
11574 for(var i = 0, len = records.length; i < len; i++){
11575 this.data.insert(index, records[i]);
11576 records[i].join(this);
11578 this.fireEvent("add", this, records, index);
11582 * Get the index within the cache of the passed Record.
11583 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11584 * @return {Number} The index of the passed Record. Returns -1 if not found.
11586 indexOf : function(record){
11587 return this.data.indexOf(record);
11591 * Get the index within the cache of the Record with the passed id.
11592 * @param {String} id The id of the Record to find.
11593 * @return {Number} The index of the Record. Returns -1 if not found.
11595 indexOfId : function(id){
11596 return this.data.indexOfKey(id);
11600 * Get the Record with the specified id.
11601 * @param {String} id The id of the Record to find.
11602 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11604 getById : function(id){
11605 return this.data.key(id);
11609 * Get the Record at the specified index.
11610 * @param {Number} index The index of the Record to find.
11611 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11613 getAt : function(index){
11614 return this.data.itemAt(index);
11618 * Returns a range of Records between specified indices.
11619 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11620 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11621 * @return {Roo.data.Record[]} An array of Records
11623 getRange : function(start, end){
11624 return this.data.getRange(start, end);
11628 storeOptions : function(o){
11629 o = Roo.apply({}, o);
11632 this.lastOptions = o;
11636 * Loads the Record cache from the configured Proxy using the configured Reader.
11638 * If using remote paging, then the first load call must specify the <em>start</em>
11639 * and <em>limit</em> properties in the options.params property to establish the initial
11640 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11642 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11643 * and this call will return before the new data has been loaded. Perform any post-processing
11644 * in a callback function, or in a "load" event handler.</strong>
11646 * @param {Object} options An object containing properties which control loading options:<ul>
11647 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11648 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11649 * passed the following arguments:<ul>
11650 * <li>r : Roo.data.Record[]</li>
11651 * <li>options: Options object from the load call</li>
11652 * <li>success: Boolean success indicator</li></ul></li>
11653 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11654 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11657 load : function(options){
11658 options = options || {};
11659 if(this.fireEvent("beforeload", this, options) !== false){
11660 this.storeOptions(options);
11661 var p = Roo.apply(options.params || {}, this.baseParams);
11662 // if meta was not loaded from remote source.. try requesting it.
11663 if (!this.reader.metaFromRemote) {
11664 p._requestMeta = 1;
11666 if(this.sortInfo && this.remoteSort){
11667 var pn = this.paramNames;
11668 p[pn["sort"]] = this.sortInfo.field;
11669 p[pn["dir"]] = this.sortInfo.direction;
11671 if (this.multiSort) {
11672 var pn = this.paramNames;
11673 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11676 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11681 * Reloads the Record cache from the configured Proxy using the configured Reader and
11682 * the options from the last load operation performed.
11683 * @param {Object} options (optional) An object containing properties which may override the options
11684 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11685 * the most recently used options are reused).
11687 reload : function(options){
11688 this.load(Roo.applyIf(options||{}, this.lastOptions));
11692 // Called as a callback by the Reader during a load operation.
11693 loadRecords : function(o, options, success){
11694 if(!o || success === false){
11695 if(success !== false){
11696 this.fireEvent("load", this, [], options, o);
11698 if(options.callback){
11699 options.callback.call(options.scope || this, [], options, false);
11703 // if data returned failure - throw an exception.
11704 if (o.success === false) {
11705 // show a message if no listener is registered.
11706 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11707 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11709 // loadmask wil be hooked into this..
11710 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11713 var r = o.records, t = o.totalRecords || r.length;
11715 this.fireEvent("beforeloadadd", this, r, options, o);
11717 if(!options || options.add !== true){
11718 if(this.pruneModifiedRecords){
11719 this.modified = [];
11721 for(var i = 0, len = r.length; i < len; i++){
11725 this.data = this.snapshot;
11726 delete this.snapshot;
11729 this.data.addAll(r);
11730 this.totalLength = t;
11732 this.fireEvent("datachanged", this);
11734 this.totalLength = Math.max(t, this.data.length+r.length);
11738 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11740 var e = new Roo.data.Record({});
11742 e.set(this.parent.displayField, this.parent.emptyTitle);
11743 e.set(this.parent.valueField, '');
11748 this.fireEvent("load", this, r, options, o);
11749 if(options.callback){
11750 options.callback.call(options.scope || this, r, options, true);
11756 * Loads data from a passed data block. A Reader which understands the format of the data
11757 * must have been configured in the constructor.
11758 * @param {Object} data The data block from which to read the Records. The format of the data expected
11759 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11760 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11762 loadData : function(o, append){
11763 var r = this.reader.readRecords(o);
11764 this.loadRecords(r, {add: append}, true);
11768 * Gets the number of cached records.
11770 * <em>If using paging, this may not be the total size of the dataset. If the data object
11771 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11772 * the data set size</em>
11774 getCount : function(){
11775 return this.data.length || 0;
11779 * Gets the total number of records in the dataset as returned by the server.
11781 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11782 * the dataset size</em>
11784 getTotalCount : function(){
11785 return this.totalLength || 0;
11789 * Returns the sort state of the Store as an object with two properties:
11791 field {String} The name of the field by which the Records are sorted
11792 direction {String} The sort order, "ASC" or "DESC"
11795 getSortState : function(){
11796 return this.sortInfo;
11800 applySort : function(){
11801 if(this.sortInfo && !this.remoteSort){
11802 var s = this.sortInfo, f = s.field;
11803 var st = this.fields.get(f).sortType;
11804 var fn = function(r1, r2){
11805 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11806 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11808 this.data.sort(s.direction, fn);
11809 if(this.snapshot && this.snapshot != this.data){
11810 this.snapshot.sort(s.direction, fn);
11816 * Sets the default sort column and order to be used by the next load operation.
11817 * @param {String} fieldName The name of the field to sort by.
11818 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11820 setDefaultSort : function(field, dir){
11821 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11825 * Sort the Records.
11826 * If remote sorting is used, the sort is performed on the server, and the cache is
11827 * reloaded. If local sorting is used, the cache is sorted internally.
11828 * @param {String} fieldName The name of the field to sort by.
11829 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11831 sort : function(fieldName, dir){
11832 var f = this.fields.get(fieldName);
11834 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11836 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11837 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11842 this.sortToggle[f.name] = dir;
11843 this.sortInfo = {field: f.name, direction: dir};
11844 if(!this.remoteSort){
11846 this.fireEvent("datachanged", this);
11848 this.load(this.lastOptions);
11853 * Calls the specified function for each of the Records in the cache.
11854 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11855 * Returning <em>false</em> aborts and exits the iteration.
11856 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11858 each : function(fn, scope){
11859 this.data.each(fn, scope);
11863 * Gets all records modified since the last commit. Modified records are persisted across load operations
11864 * (e.g., during paging).
11865 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11867 getModifiedRecords : function(){
11868 return this.modified;
11872 createFilterFn : function(property, value, anyMatch){
11873 if(!value.exec){ // not a regex
11874 value = String(value);
11875 if(value.length == 0){
11878 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11880 return function(r){
11881 return value.test(r.data[property]);
11886 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11887 * @param {String} property A field on your records
11888 * @param {Number} start The record index to start at (defaults to 0)
11889 * @param {Number} end The last record index to include (defaults to length - 1)
11890 * @return {Number} The sum
11892 sum : function(property, start, end){
11893 var rs = this.data.items, v = 0;
11894 start = start || 0;
11895 end = (end || end === 0) ? end : rs.length-1;
11897 for(var i = start; i <= end; i++){
11898 v += (rs[i].data[property] || 0);
11904 * Filter the records by a specified property.
11905 * @param {String} field A field on your records
11906 * @param {String/RegExp} value Either a string that the field
11907 * should start with or a RegExp to test against the field
11908 * @param {Boolean} anyMatch True to match any part not just the beginning
11910 filter : function(property, value, anyMatch){
11911 var fn = this.createFilterFn(property, value, anyMatch);
11912 return fn ? this.filterBy(fn) : this.clearFilter();
11916 * Filter by a function. The specified function will be called with each
11917 * record in this data source. If the function returns true the record is included,
11918 * otherwise it is filtered.
11919 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11920 * @param {Object} scope (optional) The scope of the function (defaults to this)
11922 filterBy : function(fn, scope){
11923 this.snapshot = this.snapshot || this.data;
11924 this.data = this.queryBy(fn, scope||this);
11925 this.fireEvent("datachanged", this);
11929 * Query the records by a specified property.
11930 * @param {String} field A field on your records
11931 * @param {String/RegExp} value Either a string that the field
11932 * should start with or a RegExp to test against the field
11933 * @param {Boolean} anyMatch True to match any part not just the beginning
11934 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11936 query : function(property, value, anyMatch){
11937 var fn = this.createFilterFn(property, value, anyMatch);
11938 return fn ? this.queryBy(fn) : this.data.clone();
11942 * Query by a function. The specified function will be called with each
11943 * record in this data source. If the function returns true the record is included
11945 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11946 * @param {Object} scope (optional) The scope of the function (defaults to this)
11947 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11949 queryBy : function(fn, scope){
11950 var data = this.snapshot || this.data;
11951 return data.filterBy(fn, scope||this);
11955 * Collects unique values for a particular dataIndex from this store.
11956 * @param {String} dataIndex The property to collect
11957 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11958 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11959 * @return {Array} An array of the unique values
11961 collect : function(dataIndex, allowNull, bypassFilter){
11962 var d = (bypassFilter === true && this.snapshot) ?
11963 this.snapshot.items : this.data.items;
11964 var v, sv, r = [], l = {};
11965 for(var i = 0, len = d.length; i < len; i++){
11966 v = d[i].data[dataIndex];
11968 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
11977 * Revert to a view of the Record cache with no filtering applied.
11978 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
11980 clearFilter : function(suppressEvent){
11981 if(this.snapshot && this.snapshot != this.data){
11982 this.data = this.snapshot;
11983 delete this.snapshot;
11984 if(suppressEvent !== true){
11985 this.fireEvent("datachanged", this);
11991 afterEdit : function(record){
11992 if(this.modified.indexOf(record) == -1){
11993 this.modified.push(record);
11995 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
11999 afterReject : function(record){
12000 this.modified.remove(record);
12001 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12005 afterCommit : function(record){
12006 this.modified.remove(record);
12007 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12011 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12012 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12014 commitChanges : function(){
12015 var m = this.modified.slice(0);
12016 this.modified = [];
12017 for(var i = 0, len = m.length; i < len; i++){
12023 * Cancel outstanding changes on all changed records.
12025 rejectChanges : function(){
12026 var m = this.modified.slice(0);
12027 this.modified = [];
12028 for(var i = 0, len = m.length; i < len; i++){
12033 onMetaChange : function(meta, rtype, o){
12034 this.recordType = rtype;
12035 this.fields = rtype.prototype.fields;
12036 delete this.snapshot;
12037 this.sortInfo = meta.sortInfo || this.sortInfo;
12038 this.modified = [];
12039 this.fireEvent('metachange', this, this.reader.meta);
12042 moveIndex : function(data, type)
12044 var index = this.indexOf(data);
12046 var newIndex = index + type;
12050 this.insert(newIndex, data);
12055 * Ext JS Library 1.1.1
12056 * Copyright(c) 2006-2007, Ext JS, LLC.
12058 * Originally Released Under LGPL - original licence link has changed is not relivant.
12061 * <script type="text/javascript">
12065 * @class Roo.data.SimpleStore
12066 * @extends Roo.data.Store
12067 * Small helper class to make creating Stores from Array data easier.
12068 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12069 * @cfg {Array} fields An array of field definition objects, or field name strings.
12070 * @cfg {Array} data The multi-dimensional array of data
12072 * @param {Object} config
12074 Roo.data.SimpleStore = function(config){
12075 Roo.data.SimpleStore.superclass.constructor.call(this, {
12077 reader: new Roo.data.ArrayReader({
12080 Roo.data.Record.create(config.fields)
12082 proxy : new Roo.data.MemoryProxy(config.data)
12086 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12088 * Ext JS Library 1.1.1
12089 * Copyright(c) 2006-2007, Ext JS, LLC.
12091 * Originally Released Under LGPL - original licence link has changed is not relivant.
12094 * <script type="text/javascript">
12099 * @extends Roo.data.Store
12100 * @class Roo.data.JsonStore
12101 * Small helper class to make creating Stores for JSON data easier. <br/>
12103 var store = new Roo.data.JsonStore({
12104 url: 'get-images.php',
12106 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12109 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12110 * JsonReader and HttpProxy (unless inline data is provided).</b>
12111 * @cfg {Array} fields An array of field definition objects, or field name strings.
12113 * @param {Object} config
12115 Roo.data.JsonStore = function(c){
12116 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12117 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12118 reader: new Roo.data.JsonReader(c, c.fields)
12121 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12123 * Ext JS Library 1.1.1
12124 * Copyright(c) 2006-2007, Ext JS, LLC.
12126 * Originally Released Under LGPL - original licence link has changed is not relivant.
12129 * <script type="text/javascript">
12133 Roo.data.Field = function(config){
12134 if(typeof config == "string"){
12135 config = {name: config};
12137 Roo.apply(this, config);
12140 this.type = "auto";
12143 var st = Roo.data.SortTypes;
12144 // named sortTypes are supported, here we look them up
12145 if(typeof this.sortType == "string"){
12146 this.sortType = st[this.sortType];
12149 // set default sortType for strings and dates
12150 if(!this.sortType){
12153 this.sortType = st.asUCString;
12156 this.sortType = st.asDate;
12159 this.sortType = st.none;
12164 var stripRe = /[\$,%]/g;
12166 // prebuilt conversion function for this field, instead of
12167 // switching every time we're reading a value
12169 var cv, dateFormat = this.dateFormat;
12174 cv = function(v){ return v; };
12177 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12181 return v !== undefined && v !== null && v !== '' ?
12182 parseInt(String(v).replace(stripRe, ""), 10) : '';
12187 return v !== undefined && v !== null && v !== '' ?
12188 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12193 cv = function(v){ return v === true || v === "true" || v == 1; };
12200 if(v instanceof Date){
12204 if(dateFormat == "timestamp"){
12205 return new Date(v*1000);
12207 return Date.parseDate(v, dateFormat);
12209 var parsed = Date.parse(v);
12210 return parsed ? new Date(parsed) : null;
12219 Roo.data.Field.prototype = {
12227 * Ext JS Library 1.1.1
12228 * Copyright(c) 2006-2007, Ext JS, LLC.
12230 * Originally Released Under LGPL - original licence link has changed is not relivant.
12233 * <script type="text/javascript">
12236 // Base class for reading structured data from a data source. This class is intended to be
12237 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12240 * @class Roo.data.DataReader
12241 * Base class for reading structured data from a data source. This class is intended to be
12242 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12245 Roo.data.DataReader = function(meta, recordType){
12249 this.recordType = recordType instanceof Array ?
12250 Roo.data.Record.create(recordType) : recordType;
12253 Roo.data.DataReader.prototype = {
12255 * Create an empty record
12256 * @param {Object} data (optional) - overlay some values
12257 * @return {Roo.data.Record} record created.
12259 newRow : function(d) {
12261 this.recordType.prototype.fields.each(function(c) {
12263 case 'int' : da[c.name] = 0; break;
12264 case 'date' : da[c.name] = new Date(); break;
12265 case 'float' : da[c.name] = 0.0; break;
12266 case 'boolean' : da[c.name] = false; break;
12267 default : da[c.name] = ""; break;
12271 return new this.recordType(Roo.apply(da, d));
12276 * Ext JS Library 1.1.1
12277 * Copyright(c) 2006-2007, Ext JS, LLC.
12279 * Originally Released Under LGPL - original licence link has changed is not relivant.
12282 * <script type="text/javascript">
12286 * @class Roo.data.DataProxy
12287 * @extends Roo.data.Observable
12288 * This class is an abstract base class for implementations which provide retrieval of
12289 * unformatted data objects.<br>
12291 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12292 * (of the appropriate type which knows how to parse the data object) to provide a block of
12293 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12295 * Custom implementations must implement the load method as described in
12296 * {@link Roo.data.HttpProxy#load}.
12298 Roo.data.DataProxy = function(){
12301 * @event beforeload
12302 * Fires before a network request is made to retrieve a data object.
12303 * @param {Object} This DataProxy object.
12304 * @param {Object} params The params parameter to the load function.
12309 * Fires before the load method's callback is called.
12310 * @param {Object} This DataProxy object.
12311 * @param {Object} o The data object.
12312 * @param {Object} arg The callback argument object passed to the load function.
12316 * @event loadexception
12317 * Fires if an Exception occurs during data retrieval.
12318 * @param {Object} This DataProxy object.
12319 * @param {Object} o The data object.
12320 * @param {Object} arg The callback argument object passed to the load function.
12321 * @param {Object} e The Exception.
12323 loadexception : true
12325 Roo.data.DataProxy.superclass.constructor.call(this);
12328 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12331 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12335 * Ext JS Library 1.1.1
12336 * Copyright(c) 2006-2007, Ext JS, LLC.
12338 * Originally Released Under LGPL - original licence link has changed is not relivant.
12341 * <script type="text/javascript">
12344 * @class Roo.data.MemoryProxy
12345 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12346 * to the Reader when its load method is called.
12348 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12350 Roo.data.MemoryProxy = function(data){
12354 Roo.data.MemoryProxy.superclass.constructor.call(this);
12358 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12361 * Load data from the requested source (in this case an in-memory
12362 * data object passed to the constructor), read the data object into
12363 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12364 * process that block using the passed callback.
12365 * @param {Object} params This parameter is not used by the MemoryProxy class.
12366 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12367 * object into a block of Roo.data.Records.
12368 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12369 * The function must be passed <ul>
12370 * <li>The Record block object</li>
12371 * <li>The "arg" argument from the load function</li>
12372 * <li>A boolean success indicator</li>
12374 * @param {Object} scope The scope in which to call the callback
12375 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12377 load : function(params, reader, callback, scope, arg){
12378 params = params || {};
12381 result = reader.readRecords(this.data);
12383 this.fireEvent("loadexception", this, arg, null, e);
12384 callback.call(scope, null, arg, false);
12387 callback.call(scope, result, arg, true);
12391 update : function(params, records){
12396 * Ext JS Library 1.1.1
12397 * Copyright(c) 2006-2007, Ext JS, LLC.
12399 * Originally Released Under LGPL - original licence link has changed is not relivant.
12402 * <script type="text/javascript">
12405 * @class Roo.data.HttpProxy
12406 * @extends Roo.data.DataProxy
12407 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12408 * configured to reference a certain URL.<br><br>
12410 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12411 * from which the running page was served.<br><br>
12413 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12415 * Be aware that to enable the browser to parse an XML document, the server must set
12416 * the Content-Type header in the HTTP response to "text/xml".
12418 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12419 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12420 * will be used to make the request.
12422 Roo.data.HttpProxy = function(conn){
12423 Roo.data.HttpProxy.superclass.constructor.call(this);
12424 // is conn a conn config or a real conn?
12426 this.useAjax = !conn || !conn.events;
12430 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12431 // thse are take from connection...
12434 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12437 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12438 * extra parameters to each request made by this object. (defaults to undefined)
12441 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12442 * to each request made by this object. (defaults to undefined)
12445 * @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)
12448 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12451 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12457 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12461 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12462 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12463 * a finer-grained basis than the DataProxy events.
12465 getConnection : function(){
12466 return this.useAjax ? Roo.Ajax : this.conn;
12470 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12471 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12472 * process that block using the passed callback.
12473 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12474 * for the request to the remote server.
12475 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12476 * object into a block of Roo.data.Records.
12477 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12478 * The function must be passed <ul>
12479 * <li>The Record block object</li>
12480 * <li>The "arg" argument from the load function</li>
12481 * <li>A boolean success indicator</li>
12483 * @param {Object} scope The scope in which to call the callback
12484 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12486 load : function(params, reader, callback, scope, arg){
12487 if(this.fireEvent("beforeload", this, params) !== false){
12489 params : params || {},
12491 callback : callback,
12496 callback : this.loadResponse,
12500 Roo.applyIf(o, this.conn);
12501 if(this.activeRequest){
12502 Roo.Ajax.abort(this.activeRequest);
12504 this.activeRequest = Roo.Ajax.request(o);
12506 this.conn.request(o);
12509 callback.call(scope||this, null, arg, false);
12514 loadResponse : function(o, success, response){
12515 delete this.activeRequest;
12517 this.fireEvent("loadexception", this, o, response);
12518 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12523 result = o.reader.read(response);
12525 this.fireEvent("loadexception", this, o, response, e);
12526 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12530 this.fireEvent("load", this, o, o.request.arg);
12531 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12535 update : function(dataSet){
12540 updateResponse : function(dataSet){
12545 * Ext JS Library 1.1.1
12546 * Copyright(c) 2006-2007, Ext JS, LLC.
12548 * Originally Released Under LGPL - original licence link has changed is not relivant.
12551 * <script type="text/javascript">
12555 * @class Roo.data.ScriptTagProxy
12556 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12557 * other than the originating domain of the running page.<br><br>
12559 * <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
12560 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12562 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12563 * source code that is used as the source inside a <script> tag.<br><br>
12565 * In order for the browser to process the returned data, the server must wrap the data object
12566 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12567 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12568 * depending on whether the callback name was passed:
12571 boolean scriptTag = false;
12572 String cb = request.getParameter("callback");
12575 response.setContentType("text/javascript");
12577 response.setContentType("application/x-json");
12579 Writer out = response.getWriter();
12581 out.write(cb + "(");
12583 out.print(dataBlock.toJsonString());
12590 * @param {Object} config A configuration object.
12592 Roo.data.ScriptTagProxy = function(config){
12593 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12594 Roo.apply(this, config);
12595 this.head = document.getElementsByTagName("head")[0];
12598 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12600 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12602 * @cfg {String} url The URL from which to request the data object.
12605 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12609 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12610 * the server the name of the callback function set up by the load call to process the returned data object.
12611 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12612 * javascript output which calls this named function passing the data object as its only parameter.
12614 callbackParam : "callback",
12616 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12617 * name to the request.
12622 * Load data from the configured URL, read the data object into
12623 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12624 * process that block using the passed callback.
12625 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12626 * for the request to the remote server.
12627 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12628 * object into a block of Roo.data.Records.
12629 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12630 * The function must be passed <ul>
12631 * <li>The Record block object</li>
12632 * <li>The "arg" argument from the load function</li>
12633 * <li>A boolean success indicator</li>
12635 * @param {Object} scope The scope in which to call the callback
12636 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12638 load : function(params, reader, callback, scope, arg){
12639 if(this.fireEvent("beforeload", this, params) !== false){
12641 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12643 var url = this.url;
12644 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12646 url += "&_dc=" + (new Date().getTime());
12648 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12651 cb : "stcCallback"+transId,
12652 scriptId : "stcScript"+transId,
12656 callback : callback,
12662 window[trans.cb] = function(o){
12663 conn.handleResponse(o, trans);
12666 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12668 if(this.autoAbort !== false){
12672 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12674 var script = document.createElement("script");
12675 script.setAttribute("src", url);
12676 script.setAttribute("type", "text/javascript");
12677 script.setAttribute("id", trans.scriptId);
12678 this.head.appendChild(script);
12680 this.trans = trans;
12682 callback.call(scope||this, null, arg, false);
12687 isLoading : function(){
12688 return this.trans ? true : false;
12692 * Abort the current server request.
12694 abort : function(){
12695 if(this.isLoading()){
12696 this.destroyTrans(this.trans);
12701 destroyTrans : function(trans, isLoaded){
12702 this.head.removeChild(document.getElementById(trans.scriptId));
12703 clearTimeout(trans.timeoutId);
12705 window[trans.cb] = undefined;
12707 delete window[trans.cb];
12710 // if hasn't been loaded, wait for load to remove it to prevent script error
12711 window[trans.cb] = function(){
12712 window[trans.cb] = undefined;
12714 delete window[trans.cb];
12721 handleResponse : function(o, trans){
12722 this.trans = false;
12723 this.destroyTrans(trans, true);
12726 result = trans.reader.readRecords(o);
12728 this.fireEvent("loadexception", this, o, trans.arg, e);
12729 trans.callback.call(trans.scope||window, null, trans.arg, false);
12732 this.fireEvent("load", this, o, trans.arg);
12733 trans.callback.call(trans.scope||window, result, trans.arg, true);
12737 handleFailure : function(trans){
12738 this.trans = false;
12739 this.destroyTrans(trans, false);
12740 this.fireEvent("loadexception", this, null, trans.arg);
12741 trans.callback.call(trans.scope||window, null, trans.arg, false);
12745 * Ext JS Library 1.1.1
12746 * Copyright(c) 2006-2007, Ext JS, LLC.
12748 * Originally Released Under LGPL - original licence link has changed is not relivant.
12751 * <script type="text/javascript">
12755 * @class Roo.data.JsonReader
12756 * @extends Roo.data.DataReader
12757 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12758 * based on mappings in a provided Roo.data.Record constructor.
12760 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12761 * in the reply previously.
12766 var RecordDef = Roo.data.Record.create([
12767 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12768 {name: 'occupation'} // This field will use "occupation" as the mapping.
12770 var myReader = new Roo.data.JsonReader({
12771 totalProperty: "results", // The property which contains the total dataset size (optional)
12772 root: "rows", // The property which contains an Array of row objects
12773 id: "id" // The property within each row object that provides an ID for the record (optional)
12777 * This would consume a JSON file like this:
12779 { 'results': 2, 'rows': [
12780 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12781 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12784 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12785 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12786 * paged from the remote server.
12787 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12788 * @cfg {String} root name of the property which contains the Array of row objects.
12789 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12790 * @cfg {Array} fields Array of field definition objects
12792 * Create a new JsonReader
12793 * @param {Object} meta Metadata configuration options
12794 * @param {Object} recordType Either an Array of field definition objects,
12795 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12797 Roo.data.JsonReader = function(meta, recordType){
12800 // set some defaults:
12801 Roo.applyIf(meta, {
12802 totalProperty: 'total',
12803 successProperty : 'success',
12808 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12810 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12813 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12814 * Used by Store query builder to append _requestMeta to params.
12817 metaFromRemote : false,
12819 * This method is only used by a DataProxy which has retrieved data from a remote server.
12820 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12821 * @return {Object} data A data block which is used by an Roo.data.Store object as
12822 * a cache of Roo.data.Records.
12824 read : function(response){
12825 var json = response.responseText;
12827 var o = /* eval:var:o */ eval("("+json+")");
12829 throw {message: "JsonReader.read: Json object not found"};
12835 this.metaFromRemote = true;
12836 this.meta = o.metaData;
12837 this.recordType = Roo.data.Record.create(o.metaData.fields);
12838 this.onMetaChange(this.meta, this.recordType, o);
12840 return this.readRecords(o);
12843 // private function a store will implement
12844 onMetaChange : function(meta, recordType, o){
12851 simpleAccess: function(obj, subsc) {
12858 getJsonAccessor: function(){
12860 return function(expr) {
12862 return(re.test(expr))
12863 ? new Function("obj", "return obj." + expr)
12868 return Roo.emptyFn;
12873 * Create a data block containing Roo.data.Records from an XML document.
12874 * @param {Object} o An object which contains an Array of row objects in the property specified
12875 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12876 * which contains the total size of the dataset.
12877 * @return {Object} data A data block which is used by an Roo.data.Store object as
12878 * a cache of Roo.data.Records.
12880 readRecords : function(o){
12882 * After any data loads, the raw JSON data is available for further custom processing.
12886 var s = this.meta, Record = this.recordType,
12887 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12889 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12891 if(s.totalProperty) {
12892 this.getTotal = this.getJsonAccessor(s.totalProperty);
12894 if(s.successProperty) {
12895 this.getSuccess = this.getJsonAccessor(s.successProperty);
12897 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12899 var g = this.getJsonAccessor(s.id);
12900 this.getId = function(rec) {
12902 return (r === undefined || r === "") ? null : r;
12905 this.getId = function(){return null;};
12908 for(var jj = 0; jj < fl; jj++){
12910 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12911 this.ef[jj] = this.getJsonAccessor(map);
12915 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12916 if(s.totalProperty){
12917 var vt = parseInt(this.getTotal(o), 10);
12922 if(s.successProperty){
12923 var vs = this.getSuccess(o);
12924 if(vs === false || vs === 'false'){
12929 for(var i = 0; i < c; i++){
12932 var id = this.getId(n);
12933 for(var j = 0; j < fl; j++){
12935 var v = this.ef[j](n);
12937 Roo.log('missing convert for ' + f.name);
12941 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12943 var record = new Record(values, id);
12945 records[i] = record;
12951 totalRecords : totalRecords
12956 * Ext JS Library 1.1.1
12957 * Copyright(c) 2006-2007, Ext JS, LLC.
12959 * Originally Released Under LGPL - original licence link has changed is not relivant.
12962 * <script type="text/javascript">
12966 * @class Roo.data.ArrayReader
12967 * @extends Roo.data.DataReader
12968 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12969 * Each element of that Array represents a row of data fields. The
12970 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12971 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
12975 var RecordDef = Roo.data.Record.create([
12976 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
12977 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
12979 var myReader = new Roo.data.ArrayReader({
12980 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
12984 * This would consume an Array like this:
12986 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
12988 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
12990 * Create a new JsonReader
12991 * @param {Object} meta Metadata configuration options.
12992 * @param {Object} recordType Either an Array of field definition objects
12993 * as specified to {@link Roo.data.Record#create},
12994 * or an {@link Roo.data.Record} object
12995 * created using {@link Roo.data.Record#create}.
12997 Roo.data.ArrayReader = function(meta, recordType){
12998 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
13001 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13003 * Create a data block containing Roo.data.Records from an XML document.
13004 * @param {Object} o An Array of row objects which represents the dataset.
13005 * @return {Object} data A data block which is used by an Roo.data.Store object as
13006 * a cache of Roo.data.Records.
13008 readRecords : function(o){
13009 var sid = this.meta ? this.meta.id : null;
13010 var recordType = this.recordType, fields = recordType.prototype.fields;
13013 for(var i = 0; i < root.length; i++){
13016 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13017 for(var j = 0, jlen = fields.length; j < jlen; j++){
13018 var f = fields.items[j];
13019 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13020 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13022 values[f.name] = v;
13024 var record = new recordType(values, id);
13026 records[records.length] = record;
13030 totalRecords : records.length
13039 * @class Roo.bootstrap.ComboBox
13040 * @extends Roo.bootstrap.TriggerField
13041 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13042 * @cfg {Boolean} append (true|false) default false
13043 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13044 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13045 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13046 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13047 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13048 * @cfg {Boolean} animate default true
13049 * @cfg {Boolean} emptyResultText only for touch device
13050 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13051 * @cfg {String} emptyTitle default ''
13053 * Create a new ComboBox.
13054 * @param {Object} config Configuration options
13056 Roo.bootstrap.ComboBox = function(config){
13057 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13061 * Fires when the dropdown list is expanded
13062 * @param {Roo.bootstrap.ComboBox} combo This combo box
13067 * Fires when the dropdown list is collapsed
13068 * @param {Roo.bootstrap.ComboBox} combo This combo box
13072 * @event beforeselect
13073 * Fires before a list item is selected. Return false to cancel the selection.
13074 * @param {Roo.bootstrap.ComboBox} combo This combo box
13075 * @param {Roo.data.Record} record The data record returned from the underlying store
13076 * @param {Number} index The index of the selected item in the dropdown list
13078 'beforeselect' : true,
13081 * Fires when a list item is selected
13082 * @param {Roo.bootstrap.ComboBox} combo This combo box
13083 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13084 * @param {Number} index The index of the selected item in the dropdown list
13088 * @event beforequery
13089 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13090 * The event object passed has these properties:
13091 * @param {Roo.bootstrap.ComboBox} combo This combo box
13092 * @param {String} query The query
13093 * @param {Boolean} forceAll true to force "all" query
13094 * @param {Boolean} cancel true to cancel the query
13095 * @param {Object} e The query event object
13097 'beforequery': true,
13100 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13101 * @param {Roo.bootstrap.ComboBox} combo This combo box
13106 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13107 * @param {Roo.bootstrap.ComboBox} combo This combo box
13108 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13113 * Fires when the remove value from the combobox array
13114 * @param {Roo.bootstrap.ComboBox} combo This combo box
13118 * @event afterremove
13119 * Fires when the remove value from the combobox array
13120 * @param {Roo.bootstrap.ComboBox} combo This combo box
13122 'afterremove' : true,
13124 * @event specialfilter
13125 * Fires when specialfilter
13126 * @param {Roo.bootstrap.ComboBox} combo This combo box
13128 'specialfilter' : true,
13131 * Fires when tick the element
13132 * @param {Roo.bootstrap.ComboBox} combo This combo box
13136 * @event touchviewdisplay
13137 * Fires when touch view require special display (default is using displayField)
13138 * @param {Roo.bootstrap.ComboBox} combo This combo box
13139 * @param {Object} cfg set html .
13141 'touchviewdisplay' : true
13146 this.tickItems = [];
13148 this.selectedIndex = -1;
13149 if(this.mode == 'local'){
13150 if(config.queryDelay === undefined){
13151 this.queryDelay = 10;
13153 if(config.minChars === undefined){
13159 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13162 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13163 * rendering into an Roo.Editor, defaults to false)
13166 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13167 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13170 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13173 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13174 * the dropdown list (defaults to undefined, with no header element)
13178 * @cfg {String/Roo.Template} tpl The template to use to render the output
13182 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13184 listWidth: undefined,
13186 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13187 * mode = 'remote' or 'text' if mode = 'local')
13189 displayField: undefined,
13192 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13193 * mode = 'remote' or 'value' if mode = 'local').
13194 * Note: use of a valueField requires the user make a selection
13195 * in order for a value to be mapped.
13197 valueField: undefined,
13199 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13204 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13205 * field's data value (defaults to the underlying DOM element's name)
13207 hiddenName: undefined,
13209 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13213 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13215 selectedClass: 'active',
13218 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13222 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13223 * anchor positions (defaults to 'tl-bl')
13225 listAlign: 'tl-bl?',
13227 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13231 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13232 * query specified by the allQuery config option (defaults to 'query')
13234 triggerAction: 'query',
13236 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13237 * (defaults to 4, does not apply if editable = false)
13241 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13242 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13246 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13247 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13251 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13252 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13256 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13257 * when editable = true (defaults to false)
13259 selectOnFocus:false,
13261 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13263 queryParam: 'query',
13265 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13266 * when mode = 'remote' (defaults to 'Loading...')
13268 loadingText: 'Loading...',
13270 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13274 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13278 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13279 * traditional select (defaults to true)
13283 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13287 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13291 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13292 * listWidth has a higher value)
13296 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13297 * allow the user to set arbitrary text into the field (defaults to false)
13299 forceSelection:false,
13301 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13302 * if typeAhead = true (defaults to 250)
13304 typeAheadDelay : 250,
13306 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13307 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13309 valueNotFoundText : undefined,
13311 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13313 blockFocus : false,
13316 * @cfg {Boolean} disableClear Disable showing of clear button.
13318 disableClear : false,
13320 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13322 alwaysQuery : false,
13325 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13330 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13332 invalidClass : "has-warning",
13335 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13337 validClass : "has-success",
13340 * @cfg {Boolean} specialFilter (true|false) special filter default false
13342 specialFilter : false,
13345 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13347 mobileTouchView : true,
13350 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13352 useNativeIOS : false,
13355 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13357 mobile_restrict_height : false,
13359 ios_options : false,
13371 btnPosition : 'right',
13372 triggerList : true,
13373 showToggleBtn : true,
13375 emptyResultText: 'Empty',
13376 triggerText : 'Select',
13379 // element that contains real text value.. (when hidden is used..)
13381 getAutoCreate : function()
13386 * Render classic select for iso
13389 if(Roo.isIOS && this.useNativeIOS){
13390 cfg = this.getAutoCreateNativeIOS();
13398 if(Roo.isTouch && this.mobileTouchView){
13399 cfg = this.getAutoCreateTouchView();
13406 if(!this.tickable){
13407 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13412 * ComboBox with tickable selections
13415 var align = this.labelAlign || this.parentLabelAlign();
13418 cls : 'form-group roo-combobox-tickable' //input-group
13421 var btn_text_select = '';
13422 var btn_text_done = '';
13423 var btn_text_cancel = '';
13425 if (this.btn_text_show) {
13426 btn_text_select = 'Select';
13427 btn_text_done = 'Done';
13428 btn_text_cancel = 'Cancel';
13433 cls : 'tickable-buttons',
13438 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13439 //html : this.triggerText
13440 html: btn_text_select
13446 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13448 html: btn_text_done
13454 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13456 html: btn_text_cancel
13462 buttons.cn.unshift({
13464 cls: 'roo-select2-search-field-input'
13470 Roo.each(buttons.cn, function(c){
13472 c.cls += ' btn-' + _this.size;
13475 if (_this.disabled) {
13482 style : 'display: contents',
13487 cls: 'form-hidden-field'
13491 cls: 'roo-select2-choices',
13495 cls: 'roo-select2-search-field',
13506 cls: 'roo-select2-container input-group roo-select2-container-multi',
13512 // cls: 'typeahead typeahead-long dropdown-menu',
13513 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13518 if(this.hasFeedback && !this.allowBlank){
13522 cls: 'glyphicon form-control-feedback'
13525 combobox.cn.push(feedback);
13530 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13531 tooltip : 'This field is required'
13533 if (Roo.bootstrap.version == 4) {
13536 style : 'display:none'
13539 if (align ==='left' && this.fieldLabel.length) {
13541 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13548 cls : 'control-label col-form-label',
13549 html : this.fieldLabel
13561 var labelCfg = cfg.cn[1];
13562 var contentCfg = cfg.cn[2];
13565 if(this.indicatorpos == 'right'){
13571 cls : 'control-label col-form-label',
13575 html : this.fieldLabel
13591 labelCfg = cfg.cn[0];
13592 contentCfg = cfg.cn[1];
13596 if(this.labelWidth > 12){
13597 labelCfg.style = "width: " + this.labelWidth + 'px';
13600 if(this.labelWidth < 13 && this.labelmd == 0){
13601 this.labelmd = this.labelWidth;
13604 if(this.labellg > 0){
13605 labelCfg.cls += ' col-lg-' + this.labellg;
13606 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13609 if(this.labelmd > 0){
13610 labelCfg.cls += ' col-md-' + this.labelmd;
13611 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13614 if(this.labelsm > 0){
13615 labelCfg.cls += ' col-sm-' + this.labelsm;
13616 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13619 if(this.labelxs > 0){
13620 labelCfg.cls += ' col-xs-' + this.labelxs;
13621 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13625 } else if ( this.fieldLabel.length) {
13626 // Roo.log(" label");
13631 //cls : 'input-group-addon',
13632 html : this.fieldLabel
13637 if(this.indicatorpos == 'right'){
13641 //cls : 'input-group-addon',
13642 html : this.fieldLabel
13652 // Roo.log(" no label && no align");
13659 ['xs','sm','md','lg'].map(function(size){
13660 if (settings[size]) {
13661 cfg.cls += ' col-' + size + '-' + settings[size];
13669 _initEventsCalled : false,
13672 initEvents: function()
13674 if (this._initEventsCalled) { // as we call render... prevent looping...
13677 this._initEventsCalled = true;
13680 throw "can not find store for combo";
13683 this.indicator = this.indicatorEl();
13685 this.store = Roo.factory(this.store, Roo.data);
13686 this.store.parent = this;
13688 // if we are building from html. then this element is so complex, that we can not really
13689 // use the rendered HTML.
13690 // so we have to trash and replace the previous code.
13691 if (Roo.XComponent.build_from_html) {
13692 // remove this element....
13693 var e = this.el.dom, k=0;
13694 while (e ) { e = e.previousSibling; ++k;}
13699 this.rendered = false;
13701 this.render(this.parent().getChildContainer(true), k);
13704 if(Roo.isIOS && this.useNativeIOS){
13705 this.initIOSView();
13713 if(Roo.isTouch && this.mobileTouchView){
13714 this.initTouchView();
13719 this.initTickableEvents();
13723 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13725 if(this.hiddenName){
13727 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13729 this.hiddenField.dom.value =
13730 this.hiddenValue !== undefined ? this.hiddenValue :
13731 this.value !== undefined ? this.value : '';
13733 // prevent input submission
13734 this.el.dom.removeAttribute('name');
13735 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13740 // this.el.dom.setAttribute('autocomplete', 'off');
13743 var cls = 'x-combo-list';
13745 //this.list = new Roo.Layer({
13746 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13752 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13753 _this.list.setWidth(lw);
13756 this.list.on('mouseover', this.onViewOver, this);
13757 this.list.on('mousemove', this.onViewMove, this);
13758 this.list.on('scroll', this.onViewScroll, this);
13761 this.list.swallowEvent('mousewheel');
13762 this.assetHeight = 0;
13765 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13766 this.assetHeight += this.header.getHeight();
13769 this.innerList = this.list.createChild({cls:cls+'-inner'});
13770 this.innerList.on('mouseover', this.onViewOver, this);
13771 this.innerList.on('mousemove', this.onViewMove, this);
13772 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13774 if(this.allowBlank && !this.pageSize && !this.disableClear){
13775 this.footer = this.list.createChild({cls:cls+'-ft'});
13776 this.pageTb = new Roo.Toolbar(this.footer);
13780 this.footer = this.list.createChild({cls:cls+'-ft'});
13781 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13782 {pageSize: this.pageSize});
13786 if (this.pageTb && this.allowBlank && !this.disableClear) {
13788 this.pageTb.add(new Roo.Toolbar.Fill(), {
13789 cls: 'x-btn-icon x-btn-clear',
13791 handler: function()
13794 _this.clearValue();
13795 _this.onSelect(false, -1);
13800 this.assetHeight += this.footer.getHeight();
13805 this.tpl = Roo.bootstrap.version == 4 ?
13806 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13807 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13810 this.view = new Roo.View(this.list, this.tpl, {
13811 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13813 //this.view.wrapEl.setDisplayed(false);
13814 this.view.on('click', this.onViewClick, this);
13817 this.store.on('beforeload', this.onBeforeLoad, this);
13818 this.store.on('load', this.onLoad, this);
13819 this.store.on('loadexception', this.onLoadException, this);
13821 if(this.resizable){
13822 this.resizer = new Roo.Resizable(this.list, {
13823 pinned:true, handles:'se'
13825 this.resizer.on('resize', function(r, w, h){
13826 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13827 this.listWidth = w;
13828 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13829 this.restrictHeight();
13831 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13834 if(!this.editable){
13835 this.editable = true;
13836 this.setEditable(false);
13841 if (typeof(this.events.add.listeners) != 'undefined') {
13843 this.addicon = this.wrap.createChild(
13844 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13846 this.addicon.on('click', function(e) {
13847 this.fireEvent('add', this);
13850 if (typeof(this.events.edit.listeners) != 'undefined') {
13852 this.editicon = this.wrap.createChild(
13853 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13854 if (this.addicon) {
13855 this.editicon.setStyle('margin-left', '40px');
13857 this.editicon.on('click', function(e) {
13859 // we fire even if inothing is selected..
13860 this.fireEvent('edit', this, this.lastData );
13866 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13867 "up" : function(e){
13868 this.inKeyMode = true;
13872 "down" : function(e){
13873 if(!this.isExpanded()){
13874 this.onTriggerClick();
13876 this.inKeyMode = true;
13881 "enter" : function(e){
13882 // this.onViewClick();
13886 if(this.fireEvent("specialkey", this, e)){
13887 this.onViewClick(false);
13893 "esc" : function(e){
13897 "tab" : function(e){
13900 if(this.fireEvent("specialkey", this, e)){
13901 this.onViewClick(false);
13909 doRelay : function(foo, bar, hname){
13910 if(hname == 'down' || this.scope.isExpanded()){
13911 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13920 this.queryDelay = Math.max(this.queryDelay || 10,
13921 this.mode == 'local' ? 10 : 250);
13924 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13926 if(this.typeAhead){
13927 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13929 if(this.editable !== false){
13930 this.inputEl().on("keyup", this.onKeyUp, this);
13932 if(this.forceSelection){
13933 this.inputEl().on('blur', this.doForce, this);
13937 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13938 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13942 initTickableEvents: function()
13946 if(this.hiddenName){
13948 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13950 this.hiddenField.dom.value =
13951 this.hiddenValue !== undefined ? this.hiddenValue :
13952 this.value !== undefined ? this.value : '';
13954 // prevent input submission
13955 this.el.dom.removeAttribute('name');
13956 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13961 // this.list = this.el.select('ul.dropdown-menu',true).first();
13963 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13964 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13965 if(this.triggerList){
13966 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
13969 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
13970 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
13972 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
13973 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
13975 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
13976 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
13978 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
13979 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
13980 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
13983 this.cancelBtn.hide();
13988 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13989 _this.list.setWidth(lw);
13992 this.list.on('mouseover', this.onViewOver, this);
13993 this.list.on('mousemove', this.onViewMove, this);
13995 this.list.on('scroll', this.onViewScroll, this);
13998 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
13999 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14002 this.view = new Roo.View(this.list, this.tpl, {
14007 selectedClass: this.selectedClass
14010 //this.view.wrapEl.setDisplayed(false);
14011 this.view.on('click', this.onViewClick, this);
14015 this.store.on('beforeload', this.onBeforeLoad, this);
14016 this.store.on('load', this.onLoad, this);
14017 this.store.on('loadexception', this.onLoadException, this);
14020 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14021 "up" : function(e){
14022 this.inKeyMode = true;
14026 "down" : function(e){
14027 this.inKeyMode = true;
14031 "enter" : function(e){
14032 if(this.fireEvent("specialkey", this, e)){
14033 this.onViewClick(false);
14039 "esc" : function(e){
14040 this.onTickableFooterButtonClick(e, false, false);
14043 "tab" : function(e){
14044 this.fireEvent("specialkey", this, e);
14046 this.onTickableFooterButtonClick(e, false, false);
14053 doRelay : function(e, fn, key){
14054 if(this.scope.isExpanded()){
14055 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14064 this.queryDelay = Math.max(this.queryDelay || 10,
14065 this.mode == 'local' ? 10 : 250);
14068 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14070 if(this.typeAhead){
14071 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14074 if(this.editable !== false){
14075 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14078 this.indicator = this.indicatorEl();
14080 if(this.indicator){
14081 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14082 this.indicator.hide();
14087 onDestroy : function(){
14089 this.view.setStore(null);
14090 this.view.el.removeAllListeners();
14091 this.view.el.remove();
14092 this.view.purgeListeners();
14095 this.list.dom.innerHTML = '';
14099 this.store.un('beforeload', this.onBeforeLoad, this);
14100 this.store.un('load', this.onLoad, this);
14101 this.store.un('loadexception', this.onLoadException, this);
14103 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14107 fireKey : function(e){
14108 if(e.isNavKeyPress() && !this.list.isVisible()){
14109 this.fireEvent("specialkey", this, e);
14114 onResize: function(w, h){
14115 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14117 // if(typeof w != 'number'){
14118 // // we do not handle it!?!?
14121 // var tw = this.trigger.getWidth();
14122 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14123 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14125 // this.inputEl().setWidth( this.adjustWidth('input', x));
14127 // //this.trigger.setStyle('left', x+'px');
14129 // if(this.list && this.listWidth === undefined){
14130 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14131 // this.list.setWidth(lw);
14132 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14140 * Allow or prevent the user from directly editing the field text. If false is passed,
14141 * the user will only be able to select from the items defined in the dropdown list. This method
14142 * is the runtime equivalent of setting the 'editable' config option at config time.
14143 * @param {Boolean} value True to allow the user to directly edit the field text
14145 setEditable : function(value){
14146 if(value == this.editable){
14149 this.editable = value;
14151 this.inputEl().dom.setAttribute('readOnly', true);
14152 this.inputEl().on('mousedown', this.onTriggerClick, this);
14153 this.inputEl().addClass('x-combo-noedit');
14155 this.inputEl().dom.setAttribute('readOnly', false);
14156 this.inputEl().un('mousedown', this.onTriggerClick, this);
14157 this.inputEl().removeClass('x-combo-noedit');
14163 onBeforeLoad : function(combo,opts){
14164 if(!this.hasFocus){
14168 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14170 this.restrictHeight();
14171 this.selectedIndex = -1;
14175 onLoad : function(){
14177 this.hasQuery = false;
14179 if(!this.hasFocus){
14183 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14184 this.loading.hide();
14187 if(this.store.getCount() > 0){
14190 this.restrictHeight();
14191 if(this.lastQuery == this.allQuery){
14192 if(this.editable && !this.tickable){
14193 this.inputEl().dom.select();
14197 !this.selectByValue(this.value, true) &&
14200 !this.store.lastOptions ||
14201 typeof(this.store.lastOptions.add) == 'undefined' ||
14202 this.store.lastOptions.add != true
14205 this.select(0, true);
14208 if(this.autoFocus){
14211 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14212 this.taTask.delay(this.typeAheadDelay);
14216 this.onEmptyResults();
14222 onLoadException : function()
14224 this.hasQuery = false;
14226 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14227 this.loading.hide();
14230 if(this.tickable && this.editable){
14235 // only causes errors at present
14236 //Roo.log(this.store.reader.jsonData);
14237 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14239 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14245 onTypeAhead : function(){
14246 if(this.store.getCount() > 0){
14247 var r = this.store.getAt(0);
14248 var newValue = r.data[this.displayField];
14249 var len = newValue.length;
14250 var selStart = this.getRawValue().length;
14252 if(selStart != len){
14253 this.setRawValue(newValue);
14254 this.selectText(selStart, newValue.length);
14260 onSelect : function(record, index){
14262 if(this.fireEvent('beforeselect', this, record, index) !== false){
14264 this.setFromData(index > -1 ? record.data : false);
14267 this.fireEvent('select', this, record, index);
14272 * Returns the currently selected field value or empty string if no value is set.
14273 * @return {String} value The selected value
14275 getValue : function()
14277 if(Roo.isIOS && this.useNativeIOS){
14278 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14282 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14285 if(this.valueField){
14286 return typeof this.value != 'undefined' ? this.value : '';
14288 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14292 getRawValue : function()
14294 if(Roo.isIOS && this.useNativeIOS){
14295 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14298 var v = this.inputEl().getValue();
14304 * Clears any text/value currently set in the field
14306 clearValue : function(){
14308 if(this.hiddenField){
14309 this.hiddenField.dom.value = '';
14312 this.setRawValue('');
14313 this.lastSelectionText = '';
14314 this.lastData = false;
14316 var close = this.closeTriggerEl();
14327 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14328 * will be displayed in the field. If the value does not match the data value of an existing item,
14329 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14330 * Otherwise the field will be blank (although the value will still be set).
14331 * @param {String} value The value to match
14333 setValue : function(v)
14335 if(Roo.isIOS && this.useNativeIOS){
14336 this.setIOSValue(v);
14346 if(this.valueField){
14347 var r = this.findRecord(this.valueField, v);
14349 text = r.data[this.displayField];
14350 }else if(this.valueNotFoundText !== undefined){
14351 text = this.valueNotFoundText;
14354 this.lastSelectionText = text;
14355 if(this.hiddenField){
14356 this.hiddenField.dom.value = v;
14358 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14361 var close = this.closeTriggerEl();
14364 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14370 * @property {Object} the last set data for the element
14375 * Sets the value of the field based on a object which is related to the record format for the store.
14376 * @param {Object} value the value to set as. or false on reset?
14378 setFromData : function(o){
14385 var dv = ''; // display value
14386 var vv = ''; // value value..
14388 if (this.displayField) {
14389 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14391 // this is an error condition!!!
14392 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14395 if(this.valueField){
14396 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14399 var close = this.closeTriggerEl();
14402 if(dv.length || vv * 1 > 0){
14404 this.blockFocus=true;
14410 if(this.hiddenField){
14411 this.hiddenField.dom.value = vv;
14413 this.lastSelectionText = dv;
14414 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14418 // no hidden field.. - we store the value in 'value', but still display
14419 // display field!!!!
14420 this.lastSelectionText = dv;
14421 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14428 reset : function(){
14429 // overridden so that last data is reset..
14436 this.setValue(this.originalValue);
14437 //this.clearInvalid();
14438 this.lastData = false;
14440 this.view.clearSelections();
14446 findRecord : function(prop, value){
14448 if(this.store.getCount() > 0){
14449 this.store.each(function(r){
14450 if(r.data[prop] == value){
14460 getName: function()
14462 // returns hidden if it's set..
14463 if (!this.rendered) {return ''};
14464 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14468 onViewMove : function(e, t){
14469 this.inKeyMode = false;
14473 onViewOver : function(e, t){
14474 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14477 var item = this.view.findItemFromChild(t);
14480 var index = this.view.indexOf(item);
14481 this.select(index, false);
14486 onViewClick : function(view, doFocus, el, e)
14488 var index = this.view.getSelectedIndexes()[0];
14490 var r = this.store.getAt(index);
14494 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14501 Roo.each(this.tickItems, function(v,k){
14503 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14505 _this.tickItems.splice(k, 1);
14507 if(typeof(e) == 'undefined' && view == false){
14508 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14520 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14521 this.tickItems.push(r.data);
14524 if(typeof(e) == 'undefined' && view == false){
14525 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14532 this.onSelect(r, index);
14534 if(doFocus !== false && !this.blockFocus){
14535 this.inputEl().focus();
14540 restrictHeight : function(){
14541 //this.innerList.dom.style.height = '';
14542 //var inner = this.innerList.dom;
14543 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14544 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14545 //this.list.beginUpdate();
14546 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14547 this.list.alignTo(this.inputEl(), this.listAlign);
14548 this.list.alignTo(this.inputEl(), this.listAlign);
14549 //this.list.endUpdate();
14553 onEmptyResults : function(){
14555 if(this.tickable && this.editable){
14556 this.hasFocus = false;
14557 this.restrictHeight();
14565 * Returns true if the dropdown list is expanded, else false.
14567 isExpanded : function(){
14568 return this.list.isVisible();
14572 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14573 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14574 * @param {String} value The data value of the item to select
14575 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14576 * selected item if it is not currently in view (defaults to true)
14577 * @return {Boolean} True if the value matched an item in the list, else false
14579 selectByValue : function(v, scrollIntoView){
14580 if(v !== undefined && v !== null){
14581 var r = this.findRecord(this.valueField || this.displayField, v);
14583 this.select(this.store.indexOf(r), scrollIntoView);
14591 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14592 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14593 * @param {Number} index The zero-based index of the list item to select
14594 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14595 * selected item if it is not currently in view (defaults to true)
14597 select : function(index, scrollIntoView){
14598 this.selectedIndex = index;
14599 this.view.select(index);
14600 if(scrollIntoView !== false){
14601 var el = this.view.getNode(index);
14603 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14606 this.list.scrollChildIntoView(el, false);
14612 selectNext : function(){
14613 var ct = this.store.getCount();
14615 if(this.selectedIndex == -1){
14617 }else if(this.selectedIndex < ct-1){
14618 this.select(this.selectedIndex+1);
14624 selectPrev : function(){
14625 var ct = this.store.getCount();
14627 if(this.selectedIndex == -1){
14629 }else if(this.selectedIndex != 0){
14630 this.select(this.selectedIndex-1);
14636 onKeyUp : function(e){
14637 if(this.editable !== false && !e.isSpecialKey()){
14638 this.lastKey = e.getKey();
14639 this.dqTask.delay(this.queryDelay);
14644 validateBlur : function(){
14645 return !this.list || !this.list.isVisible();
14649 initQuery : function(){
14651 var v = this.getRawValue();
14653 if(this.tickable && this.editable){
14654 v = this.tickableInputEl().getValue();
14661 doForce : function(){
14662 if(this.inputEl().dom.value.length > 0){
14663 this.inputEl().dom.value =
14664 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14670 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14671 * query allowing the query action to be canceled if needed.
14672 * @param {String} query The SQL query to execute
14673 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14674 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14675 * saved in the current store (defaults to false)
14677 doQuery : function(q, forceAll){
14679 if(q === undefined || q === null){
14684 forceAll: forceAll,
14688 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14693 forceAll = qe.forceAll;
14694 if(forceAll === true || (q.length >= this.minChars)){
14696 this.hasQuery = true;
14698 if(this.lastQuery != q || this.alwaysQuery){
14699 this.lastQuery = q;
14700 if(this.mode == 'local'){
14701 this.selectedIndex = -1;
14703 this.store.clearFilter();
14706 if(this.specialFilter){
14707 this.fireEvent('specialfilter', this);
14712 this.store.filter(this.displayField, q);
14715 this.store.fireEvent("datachanged", this.store);
14722 this.store.baseParams[this.queryParam] = q;
14724 var options = {params : this.getParams(q)};
14727 options.add = true;
14728 options.params.start = this.page * this.pageSize;
14731 this.store.load(options);
14734 * this code will make the page width larger, at the beginning, the list not align correctly,
14735 * we should expand the list on onLoad
14736 * so command out it
14741 this.selectedIndex = -1;
14746 this.loadNext = false;
14750 getParams : function(q){
14752 //p[this.queryParam] = q;
14756 p.limit = this.pageSize;
14762 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14764 collapse : function(){
14765 if(!this.isExpanded()){
14771 this.hasFocus = false;
14775 this.cancelBtn.hide();
14776 this.trigger.show();
14779 this.tickableInputEl().dom.value = '';
14780 this.tickableInputEl().blur();
14785 Roo.get(document).un('mousedown', this.collapseIf, this);
14786 Roo.get(document).un('mousewheel', this.collapseIf, this);
14787 if (!this.editable) {
14788 Roo.get(document).un('keydown', this.listKeyPress, this);
14790 this.fireEvent('collapse', this);
14796 collapseIf : function(e){
14797 var in_combo = e.within(this.el);
14798 var in_list = e.within(this.list);
14799 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14801 if (in_combo || in_list || is_list) {
14802 //e.stopPropagation();
14807 this.onTickableFooterButtonClick(e, false, false);
14815 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14817 expand : function(){
14819 if(this.isExpanded() || !this.hasFocus){
14823 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14824 this.list.setWidth(lw);
14830 this.restrictHeight();
14834 this.tickItems = Roo.apply([], this.item);
14837 this.cancelBtn.show();
14838 this.trigger.hide();
14841 this.tickableInputEl().focus();
14846 Roo.get(document).on('mousedown', this.collapseIf, this);
14847 Roo.get(document).on('mousewheel', this.collapseIf, this);
14848 if (!this.editable) {
14849 Roo.get(document).on('keydown', this.listKeyPress, this);
14852 this.fireEvent('expand', this);
14856 // Implements the default empty TriggerField.onTriggerClick function
14857 onTriggerClick : function(e)
14859 Roo.log('trigger click');
14861 if(this.disabled || !this.triggerList){
14866 this.loadNext = false;
14868 if(this.isExpanded()){
14870 if (!this.blockFocus) {
14871 this.inputEl().focus();
14875 this.hasFocus = true;
14876 if(this.triggerAction == 'all') {
14877 this.doQuery(this.allQuery, true);
14879 this.doQuery(this.getRawValue());
14881 if (!this.blockFocus) {
14882 this.inputEl().focus();
14887 onTickableTriggerClick : function(e)
14894 this.loadNext = false;
14895 this.hasFocus = true;
14897 if(this.triggerAction == 'all') {
14898 this.doQuery(this.allQuery, true);
14900 this.doQuery(this.getRawValue());
14904 onSearchFieldClick : function(e)
14906 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14907 this.onTickableFooterButtonClick(e, false, false);
14911 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14916 this.loadNext = false;
14917 this.hasFocus = true;
14919 if(this.triggerAction == 'all') {
14920 this.doQuery(this.allQuery, true);
14922 this.doQuery(this.getRawValue());
14926 listKeyPress : function(e)
14928 //Roo.log('listkeypress');
14929 // scroll to first matching element based on key pres..
14930 if (e.isSpecialKey()) {
14933 var k = String.fromCharCode(e.getKey()).toUpperCase();
14936 var csel = this.view.getSelectedNodes();
14937 var cselitem = false;
14939 var ix = this.view.indexOf(csel[0]);
14940 cselitem = this.store.getAt(ix);
14941 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14947 this.store.each(function(v) {
14949 // start at existing selection.
14950 if (cselitem.id == v.id) {
14956 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14957 match = this.store.indexOf(v);
14963 if (match === false) {
14964 return true; // no more action?
14967 this.view.select(match);
14968 var sn = Roo.get(this.view.getSelectedNodes()[0]);
14969 sn.scrollIntoView(sn.dom.parentNode, false);
14972 onViewScroll : function(e, t){
14974 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){
14978 this.hasQuery = true;
14980 this.loading = this.list.select('.loading', true).first();
14982 if(this.loading === null){
14983 this.list.createChild({
14985 cls: 'loading roo-select2-more-results roo-select2-active',
14986 html: 'Loading more results...'
14989 this.loading = this.list.select('.loading', true).first();
14991 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
14993 this.loading.hide();
14996 this.loading.show();
15001 this.loadNext = true;
15003 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15008 addItem : function(o)
15010 var dv = ''; // display value
15012 if (this.displayField) {
15013 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15015 // this is an error condition!!!
15016 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15023 var choice = this.choices.createChild({
15025 cls: 'roo-select2-search-choice',
15034 cls: 'roo-select2-search-choice-close fa fa-times',
15039 }, this.searchField);
15041 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15043 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15051 this.inputEl().dom.value = '';
15056 onRemoveItem : function(e, _self, o)
15058 e.preventDefault();
15060 this.lastItem = Roo.apply([], this.item);
15062 var index = this.item.indexOf(o.data) * 1;
15065 Roo.log('not this item?!');
15069 this.item.splice(index, 1);
15074 this.fireEvent('remove', this, e);
15080 syncValue : function()
15082 if(!this.item.length){
15089 Roo.each(this.item, function(i){
15090 if(_this.valueField){
15091 value.push(i[_this.valueField]);
15098 this.value = value.join(',');
15100 if(this.hiddenField){
15101 this.hiddenField.dom.value = this.value;
15104 this.store.fireEvent("datachanged", this.store);
15109 clearItem : function()
15111 if(!this.multiple){
15117 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15125 if(this.tickable && !Roo.isTouch){
15126 this.view.refresh();
15130 inputEl: function ()
15132 if(Roo.isIOS && this.useNativeIOS){
15133 return this.el.select('select.roo-ios-select', true).first();
15136 if(Roo.isTouch && this.mobileTouchView){
15137 return this.el.select('input.form-control',true).first();
15141 return this.searchField;
15144 return this.el.select('input.form-control',true).first();
15147 onTickableFooterButtonClick : function(e, btn, el)
15149 e.preventDefault();
15151 this.lastItem = Roo.apply([], this.item);
15153 if(btn && btn.name == 'cancel'){
15154 this.tickItems = Roo.apply([], this.item);
15163 Roo.each(this.tickItems, function(o){
15171 validate : function()
15173 if(this.getVisibilityEl().hasClass('hidden')){
15177 var v = this.getRawValue();
15180 v = this.getValue();
15183 if(this.disabled || this.allowBlank || v.length){
15188 this.markInvalid();
15192 tickableInputEl : function()
15194 if(!this.tickable || !this.editable){
15195 return this.inputEl();
15198 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15202 getAutoCreateTouchView : function()
15207 cls: 'form-group' //input-group
15213 type : this.inputType,
15214 cls : 'form-control x-combo-noedit',
15215 autocomplete: 'new-password',
15216 placeholder : this.placeholder || '',
15221 input.name = this.name;
15225 input.cls += ' input-' + this.size;
15228 if (this.disabled) {
15229 input.disabled = true;
15240 inputblock.cls += ' input-group';
15242 inputblock.cn.unshift({
15244 cls : 'input-group-addon input-group-prepend input-group-text',
15249 if(this.removable && !this.multiple){
15250 inputblock.cls += ' roo-removable';
15252 inputblock.cn.push({
15255 cls : 'roo-combo-removable-btn close'
15259 if(this.hasFeedback && !this.allowBlank){
15261 inputblock.cls += ' has-feedback';
15263 inputblock.cn.push({
15265 cls: 'glyphicon form-control-feedback'
15272 inputblock.cls += (this.before) ? '' : ' input-group';
15274 inputblock.cn.push({
15276 cls : 'input-group-addon input-group-append input-group-text',
15282 var ibwrap = inputblock;
15287 cls: 'roo-select2-choices',
15291 cls: 'roo-select2-search-field',
15304 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15309 cls: 'form-hidden-field'
15315 if(!this.multiple && this.showToggleBtn){
15322 if (this.caret != false) {
15325 cls: 'fa fa-' + this.caret
15332 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15337 cls: 'combobox-clear',
15351 combobox.cls += ' roo-select2-container-multi';
15354 var align = this.labelAlign || this.parentLabelAlign();
15356 if (align ==='left' && this.fieldLabel.length) {
15361 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15362 tooltip : 'This field is required'
15366 cls : 'control-label col-form-label',
15367 html : this.fieldLabel
15378 var labelCfg = cfg.cn[1];
15379 var contentCfg = cfg.cn[2];
15382 if(this.indicatorpos == 'right'){
15387 cls : 'control-label col-form-label',
15391 html : this.fieldLabel
15395 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15396 tooltip : 'This field is required'
15409 labelCfg = cfg.cn[0];
15410 contentCfg = cfg.cn[1];
15415 if(this.labelWidth > 12){
15416 labelCfg.style = "width: " + this.labelWidth + 'px';
15419 if(this.labelWidth < 13 && this.labelmd == 0){
15420 this.labelmd = this.labelWidth;
15423 if(this.labellg > 0){
15424 labelCfg.cls += ' col-lg-' + this.labellg;
15425 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15428 if(this.labelmd > 0){
15429 labelCfg.cls += ' col-md-' + this.labelmd;
15430 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15433 if(this.labelsm > 0){
15434 labelCfg.cls += ' col-sm-' + this.labelsm;
15435 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15438 if(this.labelxs > 0){
15439 labelCfg.cls += ' col-xs-' + this.labelxs;
15440 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15444 } else if ( this.fieldLabel.length) {
15448 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15449 tooltip : 'This field is required'
15453 cls : 'control-label',
15454 html : this.fieldLabel
15465 if(this.indicatorpos == 'right'){
15469 cls : 'control-label',
15470 html : this.fieldLabel,
15474 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15475 tooltip : 'This field is required'
15492 var settings = this;
15494 ['xs','sm','md','lg'].map(function(size){
15495 if (settings[size]) {
15496 cfg.cls += ' col-' + size + '-' + settings[size];
15503 initTouchView : function()
15505 this.renderTouchView();
15507 this.touchViewEl.on('scroll', function(){
15508 this.el.dom.scrollTop = 0;
15511 this.originalValue = this.getValue();
15513 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15515 this.inputEl().on("click", this.showTouchView, this);
15516 if (this.triggerEl) {
15517 this.triggerEl.on("click", this.showTouchView, this);
15521 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15522 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15524 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15526 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15527 this.store.on('load', this.onTouchViewLoad, this);
15528 this.store.on('loadexception', this.onTouchViewLoadException, this);
15530 if(this.hiddenName){
15532 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15534 this.hiddenField.dom.value =
15535 this.hiddenValue !== undefined ? this.hiddenValue :
15536 this.value !== undefined ? this.value : '';
15538 this.el.dom.removeAttribute('name');
15539 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15543 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15544 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15547 if(this.removable && !this.multiple){
15548 var close = this.closeTriggerEl();
15550 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15551 close.on('click', this.removeBtnClick, this, close);
15555 * fix the bug in Safari iOS8
15557 this.inputEl().on("focus", function(e){
15558 document.activeElement.blur();
15561 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15568 renderTouchView : function()
15570 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15571 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15573 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15574 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15576 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15577 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15578 this.touchViewBodyEl.setStyle('overflow', 'auto');
15580 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15581 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15583 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15584 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15588 showTouchView : function()
15594 this.touchViewHeaderEl.hide();
15596 if(this.modalTitle.length){
15597 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15598 this.touchViewHeaderEl.show();
15601 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15602 this.touchViewEl.show();
15604 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15606 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15607 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15609 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15611 if(this.modalTitle.length){
15612 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15615 this.touchViewBodyEl.setHeight(bodyHeight);
15619 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15621 this.touchViewEl.addClass('in');
15624 if(this._touchViewMask){
15625 Roo.get(document.body).addClass("x-body-masked");
15626 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15627 this._touchViewMask.setStyle('z-index', 10000);
15628 this._touchViewMask.addClass('show');
15631 this.doTouchViewQuery();
15635 hideTouchView : function()
15637 this.touchViewEl.removeClass('in');
15641 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15643 this.touchViewEl.setStyle('display', 'none');
15646 if(this._touchViewMask){
15647 this._touchViewMask.removeClass('show');
15648 Roo.get(document.body).removeClass("x-body-masked");
15652 setTouchViewValue : function()
15659 Roo.each(this.tickItems, function(o){
15664 this.hideTouchView();
15667 doTouchViewQuery : function()
15676 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15680 if(!this.alwaysQuery || this.mode == 'local'){
15681 this.onTouchViewLoad();
15688 onTouchViewBeforeLoad : function(combo,opts)
15694 onTouchViewLoad : function()
15696 if(this.store.getCount() < 1){
15697 this.onTouchViewEmptyResults();
15701 this.clearTouchView();
15703 var rawValue = this.getRawValue();
15705 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15707 this.tickItems = [];
15709 this.store.data.each(function(d, rowIndex){
15710 var row = this.touchViewListGroup.createChild(template);
15712 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15713 row.addClass(d.data.cls);
15716 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15719 html : d.data[this.displayField]
15722 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15723 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15726 row.removeClass('selected');
15727 if(!this.multiple && this.valueField &&
15728 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15731 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15732 row.addClass('selected');
15735 if(this.multiple && this.valueField &&
15736 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15740 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15741 this.tickItems.push(d.data);
15744 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15748 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15750 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15752 if(this.modalTitle.length){
15753 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15756 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15758 if(this.mobile_restrict_height && listHeight < bodyHeight){
15759 this.touchViewBodyEl.setHeight(listHeight);
15764 if(firstChecked && listHeight > bodyHeight){
15765 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15770 onTouchViewLoadException : function()
15772 this.hideTouchView();
15775 onTouchViewEmptyResults : function()
15777 this.clearTouchView();
15779 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15781 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15785 clearTouchView : function()
15787 this.touchViewListGroup.dom.innerHTML = '';
15790 onTouchViewClick : function(e, el, o)
15792 e.preventDefault();
15795 var rowIndex = o.rowIndex;
15797 var r = this.store.getAt(rowIndex);
15799 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15801 if(!this.multiple){
15802 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15803 c.dom.removeAttribute('checked');
15806 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15808 this.setFromData(r.data);
15810 var close = this.closeTriggerEl();
15816 this.hideTouchView();
15818 this.fireEvent('select', this, r, rowIndex);
15823 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15824 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15825 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15829 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15830 this.addItem(r.data);
15831 this.tickItems.push(r.data);
15835 getAutoCreateNativeIOS : function()
15838 cls: 'form-group' //input-group,
15843 cls : 'roo-ios-select'
15847 combobox.name = this.name;
15850 if (this.disabled) {
15851 combobox.disabled = true;
15854 var settings = this;
15856 ['xs','sm','md','lg'].map(function(size){
15857 if (settings[size]) {
15858 cfg.cls += ' col-' + size + '-' + settings[size];
15868 initIOSView : function()
15870 this.store.on('load', this.onIOSViewLoad, this);
15875 onIOSViewLoad : function()
15877 if(this.store.getCount() < 1){
15881 this.clearIOSView();
15883 if(this.allowBlank) {
15885 var default_text = '-- SELECT --';
15887 if(this.placeholder.length){
15888 default_text = this.placeholder;
15891 if(this.emptyTitle.length){
15892 default_text += ' - ' + this.emptyTitle + ' -';
15895 var opt = this.inputEl().createChild({
15898 html : default_text
15902 o[this.valueField] = 0;
15903 o[this.displayField] = default_text;
15905 this.ios_options.push({
15912 this.store.data.each(function(d, rowIndex){
15916 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15917 html = d.data[this.displayField];
15922 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15923 value = d.data[this.valueField];
15932 if(this.value == d.data[this.valueField]){
15933 option['selected'] = true;
15936 var opt = this.inputEl().createChild(option);
15938 this.ios_options.push({
15945 this.inputEl().on('change', function(){
15946 this.fireEvent('select', this);
15951 clearIOSView: function()
15953 this.inputEl().dom.innerHTML = '';
15955 this.ios_options = [];
15958 setIOSValue: function(v)
15962 if(!this.ios_options){
15966 Roo.each(this.ios_options, function(opts){
15968 opts.el.dom.removeAttribute('selected');
15970 if(opts.data[this.valueField] != v){
15974 opts.el.dom.setAttribute('selected', true);
15980 * @cfg {Boolean} grow
15984 * @cfg {Number} growMin
15988 * @cfg {Number} growMax
15997 Roo.apply(Roo.bootstrap.ComboBox, {
16001 cls: 'modal-header',
16023 cls: 'list-group-item',
16027 cls: 'roo-combobox-list-group-item-value'
16031 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16045 listItemCheckbox : {
16047 cls: 'list-group-item',
16051 cls: 'roo-combobox-list-group-item-value'
16055 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16071 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16076 cls: 'modal-footer',
16084 cls: 'col-xs-6 text-left',
16087 cls: 'btn btn-danger roo-touch-view-cancel',
16093 cls: 'col-xs-6 text-right',
16096 cls: 'btn btn-success roo-touch-view-ok',
16107 Roo.apply(Roo.bootstrap.ComboBox, {
16109 touchViewTemplate : {
16111 cls: 'modal fade roo-combobox-touch-view',
16115 cls: 'modal-dialog',
16116 style : 'position:fixed', // we have to fix position....
16120 cls: 'modal-content',
16122 Roo.bootstrap.ComboBox.header,
16123 Roo.bootstrap.ComboBox.body,
16124 Roo.bootstrap.ComboBox.footer
16133 * Ext JS Library 1.1.1
16134 * Copyright(c) 2006-2007, Ext JS, LLC.
16136 * Originally Released Under LGPL - original licence link has changed is not relivant.
16139 * <script type="text/javascript">
16144 * @extends Roo.util.Observable
16145 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16146 * This class also supports single and multi selection modes. <br>
16147 * Create a data model bound view:
16149 var store = new Roo.data.Store(...);
16151 var view = new Roo.View({
16153 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16155 singleSelect: true,
16156 selectedClass: "ydataview-selected",
16160 // listen for node click?
16161 view.on("click", function(vw, index, node, e){
16162 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16166 dataModel.load("foobar.xml");
16168 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16170 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16171 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16173 * Note: old style constructor is still suported (container, template, config)
16176 * Create a new View
16177 * @param {Object} config The config object
16180 Roo.View = function(config, depreciated_tpl, depreciated_config){
16182 this.parent = false;
16184 if (typeof(depreciated_tpl) == 'undefined') {
16185 // new way.. - universal constructor.
16186 Roo.apply(this, config);
16187 this.el = Roo.get(this.el);
16190 this.el = Roo.get(config);
16191 this.tpl = depreciated_tpl;
16192 Roo.apply(this, depreciated_config);
16194 this.wrapEl = this.el.wrap().wrap();
16195 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16198 if(typeof(this.tpl) == "string"){
16199 this.tpl = new Roo.Template(this.tpl);
16201 // support xtype ctors..
16202 this.tpl = new Roo.factory(this.tpl, Roo);
16206 this.tpl.compile();
16211 * @event beforeclick
16212 * Fires before a click is processed. Returns false to cancel the default action.
16213 * @param {Roo.View} this
16214 * @param {Number} index The index of the target node
16215 * @param {HTMLElement} node The target node
16216 * @param {Roo.EventObject} e The raw event object
16218 "beforeclick" : true,
16221 * Fires when a template node is clicked.
16222 * @param {Roo.View} this
16223 * @param {Number} index The index of the target node
16224 * @param {HTMLElement} node The target node
16225 * @param {Roo.EventObject} e The raw event object
16230 * Fires when a template node is double clicked.
16231 * @param {Roo.View} this
16232 * @param {Number} index The index of the target node
16233 * @param {HTMLElement} node The target node
16234 * @param {Roo.EventObject} e The raw event object
16238 * @event contextmenu
16239 * Fires when a template node is right clicked.
16240 * @param {Roo.View} this
16241 * @param {Number} index The index of the target node
16242 * @param {HTMLElement} node The target node
16243 * @param {Roo.EventObject} e The raw event object
16245 "contextmenu" : true,
16247 * @event selectionchange
16248 * Fires when the selected nodes change.
16249 * @param {Roo.View} this
16250 * @param {Array} selections Array of the selected nodes
16252 "selectionchange" : true,
16255 * @event beforeselect
16256 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16257 * @param {Roo.View} this
16258 * @param {HTMLElement} node The node to be selected
16259 * @param {Array} selections Array of currently selected nodes
16261 "beforeselect" : true,
16263 * @event preparedata
16264 * Fires on every row to render, to allow you to change the data.
16265 * @param {Roo.View} this
16266 * @param {Object} data to be rendered (change this)
16268 "preparedata" : true
16276 "click": this.onClick,
16277 "dblclick": this.onDblClick,
16278 "contextmenu": this.onContextMenu,
16282 this.selections = [];
16284 this.cmp = new Roo.CompositeElementLite([]);
16286 this.store = Roo.factory(this.store, Roo.data);
16287 this.setStore(this.store, true);
16290 if ( this.footer && this.footer.xtype) {
16292 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16294 this.footer.dataSource = this.store;
16295 this.footer.container = fctr;
16296 this.footer = Roo.factory(this.footer, Roo);
16297 fctr.insertFirst(this.el);
16299 // this is a bit insane - as the paging toolbar seems to detach the el..
16300 // dom.parentNode.parentNode.parentNode
16301 // they get detached?
16305 Roo.View.superclass.constructor.call(this);
16310 Roo.extend(Roo.View, Roo.util.Observable, {
16313 * @cfg {Roo.data.Store} store Data store to load data from.
16318 * @cfg {String|Roo.Element} el The container element.
16323 * @cfg {String|Roo.Template} tpl The template used by this View
16327 * @cfg {String} dataName the named area of the template to use as the data area
16328 * Works with domtemplates roo-name="name"
16332 * @cfg {String} selectedClass The css class to add to selected nodes
16334 selectedClass : "x-view-selected",
16336 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16341 * @cfg {String} text to display on mask (default Loading)
16345 * @cfg {Boolean} multiSelect Allow multiple selection
16347 multiSelect : false,
16349 * @cfg {Boolean} singleSelect Allow single selection
16351 singleSelect: false,
16354 * @cfg {Boolean} toggleSelect - selecting
16356 toggleSelect : false,
16359 * @cfg {Boolean} tickable - selecting
16364 * Returns the element this view is bound to.
16365 * @return {Roo.Element}
16367 getEl : function(){
16368 return this.wrapEl;
16374 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16376 refresh : function(){
16377 //Roo.log('refresh');
16380 // if we are using something like 'domtemplate', then
16381 // the what gets used is:
16382 // t.applySubtemplate(NAME, data, wrapping data..)
16383 // the outer template then get' applied with
16384 // the store 'extra data'
16385 // and the body get's added to the
16386 // roo-name="data" node?
16387 // <span class='roo-tpl-{name}'></span> ?????
16391 this.clearSelections();
16392 this.el.update("");
16394 var records = this.store.getRange();
16395 if(records.length < 1) {
16397 // is this valid?? = should it render a template??
16399 this.el.update(this.emptyText);
16403 if (this.dataName) {
16404 this.el.update(t.apply(this.store.meta)); //????
16405 el = this.el.child('.roo-tpl-' + this.dataName);
16408 for(var i = 0, len = records.length; i < len; i++){
16409 var data = this.prepareData(records[i].data, i, records[i]);
16410 this.fireEvent("preparedata", this, data, i, records[i]);
16412 var d = Roo.apply({}, data);
16415 Roo.apply(d, {'roo-id' : Roo.id()});
16419 Roo.each(this.parent.item, function(item){
16420 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16423 Roo.apply(d, {'roo-data-checked' : 'checked'});
16427 html[html.length] = Roo.util.Format.trim(
16429 t.applySubtemplate(this.dataName, d, this.store.meta) :
16436 el.update(html.join(""));
16437 this.nodes = el.dom.childNodes;
16438 this.updateIndexes(0);
16443 * Function to override to reformat the data that is sent to
16444 * the template for each node.
16445 * DEPRICATED - use the preparedata event handler.
16446 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16447 * a JSON object for an UpdateManager bound view).
16449 prepareData : function(data, index, record)
16451 this.fireEvent("preparedata", this, data, index, record);
16455 onUpdate : function(ds, record){
16456 // Roo.log('on update');
16457 this.clearSelections();
16458 var index = this.store.indexOf(record);
16459 var n = this.nodes[index];
16460 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16461 n.parentNode.removeChild(n);
16462 this.updateIndexes(index, index);
16468 onAdd : function(ds, records, index)
16470 //Roo.log(['on Add', ds, records, index] );
16471 this.clearSelections();
16472 if(this.nodes.length == 0){
16476 var n = this.nodes[index];
16477 for(var i = 0, len = records.length; i < len; i++){
16478 var d = this.prepareData(records[i].data, i, records[i]);
16480 this.tpl.insertBefore(n, d);
16483 this.tpl.append(this.el, d);
16486 this.updateIndexes(index);
16489 onRemove : function(ds, record, index){
16490 // Roo.log('onRemove');
16491 this.clearSelections();
16492 var el = this.dataName ?
16493 this.el.child('.roo-tpl-' + this.dataName) :
16496 el.dom.removeChild(this.nodes[index]);
16497 this.updateIndexes(index);
16501 * Refresh an individual node.
16502 * @param {Number} index
16504 refreshNode : function(index){
16505 this.onUpdate(this.store, this.store.getAt(index));
16508 updateIndexes : function(startIndex, endIndex){
16509 var ns = this.nodes;
16510 startIndex = startIndex || 0;
16511 endIndex = endIndex || ns.length - 1;
16512 for(var i = startIndex; i <= endIndex; i++){
16513 ns[i].nodeIndex = i;
16518 * Changes the data store this view uses and refresh the view.
16519 * @param {Store} store
16521 setStore : function(store, initial){
16522 if(!initial && this.store){
16523 this.store.un("datachanged", this.refresh);
16524 this.store.un("add", this.onAdd);
16525 this.store.un("remove", this.onRemove);
16526 this.store.un("update", this.onUpdate);
16527 this.store.un("clear", this.refresh);
16528 this.store.un("beforeload", this.onBeforeLoad);
16529 this.store.un("load", this.onLoad);
16530 this.store.un("loadexception", this.onLoad);
16534 store.on("datachanged", this.refresh, this);
16535 store.on("add", this.onAdd, this);
16536 store.on("remove", this.onRemove, this);
16537 store.on("update", this.onUpdate, this);
16538 store.on("clear", this.refresh, this);
16539 store.on("beforeload", this.onBeforeLoad, this);
16540 store.on("load", this.onLoad, this);
16541 store.on("loadexception", this.onLoad, this);
16549 * onbeforeLoad - masks the loading area.
16552 onBeforeLoad : function(store,opts)
16554 //Roo.log('onBeforeLoad');
16556 this.el.update("");
16558 this.el.mask(this.mask ? this.mask : "Loading" );
16560 onLoad : function ()
16567 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16568 * @param {HTMLElement} node
16569 * @return {HTMLElement} The template node
16571 findItemFromChild : function(node){
16572 var el = this.dataName ?
16573 this.el.child('.roo-tpl-' + this.dataName,true) :
16576 if(!node || node.parentNode == el){
16579 var p = node.parentNode;
16580 while(p && p != el){
16581 if(p.parentNode == el){
16590 onClick : function(e){
16591 var item = this.findItemFromChild(e.getTarget());
16593 var index = this.indexOf(item);
16594 if(this.onItemClick(item, index, e) !== false){
16595 this.fireEvent("click", this, index, item, e);
16598 this.clearSelections();
16603 onContextMenu : function(e){
16604 var item = this.findItemFromChild(e.getTarget());
16606 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16611 onDblClick : function(e){
16612 var item = this.findItemFromChild(e.getTarget());
16614 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16618 onItemClick : function(item, index, e)
16620 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16623 if (this.toggleSelect) {
16624 var m = this.isSelected(item) ? 'unselect' : 'select';
16627 _t[m](item, true, false);
16630 if(this.multiSelect || this.singleSelect){
16631 if(this.multiSelect && e.shiftKey && this.lastSelection){
16632 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16634 this.select(item, this.multiSelect && e.ctrlKey);
16635 this.lastSelection = item;
16638 if(!this.tickable){
16639 e.preventDefault();
16647 * Get the number of selected nodes.
16650 getSelectionCount : function(){
16651 return this.selections.length;
16655 * Get the currently selected nodes.
16656 * @return {Array} An array of HTMLElements
16658 getSelectedNodes : function(){
16659 return this.selections;
16663 * Get the indexes of the selected nodes.
16666 getSelectedIndexes : function(){
16667 var indexes = [], s = this.selections;
16668 for(var i = 0, len = s.length; i < len; i++){
16669 indexes.push(s[i].nodeIndex);
16675 * Clear all selections
16676 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16678 clearSelections : function(suppressEvent){
16679 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16680 this.cmp.elements = this.selections;
16681 this.cmp.removeClass(this.selectedClass);
16682 this.selections = [];
16683 if(!suppressEvent){
16684 this.fireEvent("selectionchange", this, this.selections);
16690 * Returns true if the passed node is selected
16691 * @param {HTMLElement/Number} node The node or node index
16692 * @return {Boolean}
16694 isSelected : function(node){
16695 var s = this.selections;
16699 node = this.getNode(node);
16700 return s.indexOf(node) !== -1;
16705 * @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
16706 * @param {Boolean} keepExisting (optional) true to keep existing selections
16707 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16709 select : function(nodeInfo, keepExisting, suppressEvent){
16710 if(nodeInfo instanceof Array){
16712 this.clearSelections(true);
16714 for(var i = 0, len = nodeInfo.length; i < len; i++){
16715 this.select(nodeInfo[i], true, true);
16719 var node = this.getNode(nodeInfo);
16720 if(!node || this.isSelected(node)){
16721 return; // already selected.
16724 this.clearSelections(true);
16727 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16728 Roo.fly(node).addClass(this.selectedClass);
16729 this.selections.push(node);
16730 if(!suppressEvent){
16731 this.fireEvent("selectionchange", this, this.selections);
16739 * @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
16740 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16741 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16743 unselect : function(nodeInfo, keepExisting, suppressEvent)
16745 if(nodeInfo instanceof Array){
16746 Roo.each(this.selections, function(s) {
16747 this.unselect(s, nodeInfo);
16751 var node = this.getNode(nodeInfo);
16752 if(!node || !this.isSelected(node)){
16753 //Roo.log("not selected");
16754 return; // not selected.
16758 Roo.each(this.selections, function(s) {
16760 Roo.fly(node).removeClass(this.selectedClass);
16767 this.selections= ns;
16768 this.fireEvent("selectionchange", this, this.selections);
16772 * Gets a template node.
16773 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16774 * @return {HTMLElement} The node or null if it wasn't found
16776 getNode : function(nodeInfo){
16777 if(typeof nodeInfo == "string"){
16778 return document.getElementById(nodeInfo);
16779 }else if(typeof nodeInfo == "number"){
16780 return this.nodes[nodeInfo];
16786 * Gets a range template nodes.
16787 * @param {Number} startIndex
16788 * @param {Number} endIndex
16789 * @return {Array} An array of nodes
16791 getNodes : function(start, end){
16792 var ns = this.nodes;
16793 start = start || 0;
16794 end = typeof end == "undefined" ? ns.length - 1 : end;
16797 for(var i = start; i <= end; i++){
16801 for(var i = start; i >= end; i--){
16809 * Finds the index of the passed node
16810 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16811 * @return {Number} The index of the node or -1
16813 indexOf : function(node){
16814 node = this.getNode(node);
16815 if(typeof node.nodeIndex == "number"){
16816 return node.nodeIndex;
16818 var ns = this.nodes;
16819 for(var i = 0, len = ns.length; i < len; i++){
16830 * based on jquery fullcalendar
16834 Roo.bootstrap = Roo.bootstrap || {};
16836 * @class Roo.bootstrap.Calendar
16837 * @extends Roo.bootstrap.Component
16838 * Bootstrap Calendar class
16839 * @cfg {Boolean} loadMask (true|false) default false
16840 * @cfg {Object} header generate the user specific header of the calendar, default false
16843 * Create a new Container
16844 * @param {Object} config The config object
16849 Roo.bootstrap.Calendar = function(config){
16850 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16854 * Fires when a date is selected
16855 * @param {DatePicker} this
16856 * @param {Date} date The selected date
16860 * @event monthchange
16861 * Fires when the displayed month changes
16862 * @param {DatePicker} this
16863 * @param {Date} date The selected month
16865 'monthchange': true,
16867 * @event evententer
16868 * Fires when mouse over an event
16869 * @param {Calendar} this
16870 * @param {event} Event
16872 'evententer': true,
16874 * @event eventleave
16875 * Fires when the mouse leaves an
16876 * @param {Calendar} this
16879 'eventleave': true,
16881 * @event eventclick
16882 * Fires when the mouse click an
16883 * @param {Calendar} this
16892 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16895 * @cfg {Number} startDay
16896 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16904 getAutoCreate : function(){
16907 var fc_button = function(name, corner, style, content ) {
16908 return Roo.apply({},{
16910 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16912 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16915 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16926 style : 'width:100%',
16933 cls : 'fc-header-left',
16935 fc_button('prev', 'left', 'arrow', '‹' ),
16936 fc_button('next', 'right', 'arrow', '›' ),
16937 { tag: 'span', cls: 'fc-header-space' },
16938 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16946 cls : 'fc-header-center',
16950 cls: 'fc-header-title',
16953 html : 'month / year'
16961 cls : 'fc-header-right',
16963 /* fc_button('month', 'left', '', 'month' ),
16964 fc_button('week', '', '', 'week' ),
16965 fc_button('day', 'right', '', 'day' )
16977 header = this.header;
16980 var cal_heads = function() {
16982 // fixme - handle this.
16984 for (var i =0; i < Date.dayNames.length; i++) {
16985 var d = Date.dayNames[i];
16988 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
16989 html : d.substring(0,3)
16993 ret[0].cls += ' fc-first';
16994 ret[6].cls += ' fc-last';
16997 var cal_cell = function(n) {
17000 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17005 cls: 'fc-day-number',
17009 cls: 'fc-day-content',
17013 style: 'position: relative;' // height: 17px;
17025 var cal_rows = function() {
17028 for (var r = 0; r < 6; r++) {
17035 for (var i =0; i < Date.dayNames.length; i++) {
17036 var d = Date.dayNames[i];
17037 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17040 row.cn[0].cls+=' fc-first';
17041 row.cn[0].cn[0].style = 'min-height:90px';
17042 row.cn[6].cls+=' fc-last';
17046 ret[0].cls += ' fc-first';
17047 ret[4].cls += ' fc-prev-last';
17048 ret[5].cls += ' fc-last';
17055 cls: 'fc-border-separate',
17056 style : 'width:100%',
17064 cls : 'fc-first fc-last',
17082 cls : 'fc-content',
17083 style : "position: relative;",
17086 cls : 'fc-view fc-view-month fc-grid',
17087 style : 'position: relative',
17088 unselectable : 'on',
17091 cls : 'fc-event-container',
17092 style : 'position:absolute;z-index:8;top:0;left:0;'
17110 initEvents : function()
17113 throw "can not find store for calendar";
17119 style: "text-align:center",
17123 style: "background-color:white;width:50%;margin:250 auto",
17127 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17138 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17140 var size = this.el.select('.fc-content', true).first().getSize();
17141 this.maskEl.setSize(size.width, size.height);
17142 this.maskEl.enableDisplayMode("block");
17143 if(!this.loadMask){
17144 this.maskEl.hide();
17147 this.store = Roo.factory(this.store, Roo.data);
17148 this.store.on('load', this.onLoad, this);
17149 this.store.on('beforeload', this.onBeforeLoad, this);
17153 this.cells = this.el.select('.fc-day',true);
17154 //Roo.log(this.cells);
17155 this.textNodes = this.el.query('.fc-day-number');
17156 this.cells.addClassOnOver('fc-state-hover');
17158 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17159 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17160 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17161 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17163 this.on('monthchange', this.onMonthChange, this);
17165 this.update(new Date().clearTime());
17168 resize : function() {
17169 var sz = this.el.getSize();
17171 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17172 this.el.select('.fc-day-content div',true).setHeight(34);
17177 showPrevMonth : function(e){
17178 this.update(this.activeDate.add("mo", -1));
17180 showToday : function(e){
17181 this.update(new Date().clearTime());
17184 showNextMonth : function(e){
17185 this.update(this.activeDate.add("mo", 1));
17189 showPrevYear : function(){
17190 this.update(this.activeDate.add("y", -1));
17194 showNextYear : function(){
17195 this.update(this.activeDate.add("y", 1));
17200 update : function(date)
17202 var vd = this.activeDate;
17203 this.activeDate = date;
17204 // if(vd && this.el){
17205 // var t = date.getTime();
17206 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17207 // Roo.log('using add remove');
17209 // this.fireEvent('monthchange', this, date);
17211 // this.cells.removeClass("fc-state-highlight");
17212 // this.cells.each(function(c){
17213 // if(c.dateValue == t){
17214 // c.addClass("fc-state-highlight");
17215 // setTimeout(function(){
17216 // try{c.dom.firstChild.focus();}catch(e){}
17226 var days = date.getDaysInMonth();
17228 var firstOfMonth = date.getFirstDateOfMonth();
17229 var startingPos = firstOfMonth.getDay()-this.startDay;
17231 if(startingPos < this.startDay){
17235 var pm = date.add(Date.MONTH, -1);
17236 var prevStart = pm.getDaysInMonth()-startingPos;
17238 this.cells = this.el.select('.fc-day',true);
17239 this.textNodes = this.el.query('.fc-day-number');
17240 this.cells.addClassOnOver('fc-state-hover');
17242 var cells = this.cells.elements;
17243 var textEls = this.textNodes;
17245 Roo.each(cells, function(cell){
17246 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17249 days += startingPos;
17251 // convert everything to numbers so it's fast
17252 var day = 86400000;
17253 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17256 //Roo.log(prevStart);
17258 var today = new Date().clearTime().getTime();
17259 var sel = date.clearTime().getTime();
17260 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17261 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17262 var ddMatch = this.disabledDatesRE;
17263 var ddText = this.disabledDatesText;
17264 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17265 var ddaysText = this.disabledDaysText;
17266 var format = this.format;
17268 var setCellClass = function(cal, cell){
17272 //Roo.log('set Cell Class');
17274 var t = d.getTime();
17278 cell.dateValue = t;
17280 cell.className += " fc-today";
17281 cell.className += " fc-state-highlight";
17282 cell.title = cal.todayText;
17285 // disable highlight in other month..
17286 //cell.className += " fc-state-highlight";
17291 cell.className = " fc-state-disabled";
17292 cell.title = cal.minText;
17296 cell.className = " fc-state-disabled";
17297 cell.title = cal.maxText;
17301 if(ddays.indexOf(d.getDay()) != -1){
17302 cell.title = ddaysText;
17303 cell.className = " fc-state-disabled";
17306 if(ddMatch && format){
17307 var fvalue = d.dateFormat(format);
17308 if(ddMatch.test(fvalue)){
17309 cell.title = ddText.replace("%0", fvalue);
17310 cell.className = " fc-state-disabled";
17314 if (!cell.initialClassName) {
17315 cell.initialClassName = cell.dom.className;
17318 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17323 for(; i < startingPos; i++) {
17324 textEls[i].innerHTML = (++prevStart);
17325 d.setDate(d.getDate()+1);
17327 cells[i].className = "fc-past fc-other-month";
17328 setCellClass(this, cells[i]);
17333 for(; i < days; i++){
17334 intDay = i - startingPos + 1;
17335 textEls[i].innerHTML = (intDay);
17336 d.setDate(d.getDate()+1);
17338 cells[i].className = ''; // "x-date-active";
17339 setCellClass(this, cells[i]);
17343 for(; i < 42; i++) {
17344 textEls[i].innerHTML = (++extraDays);
17345 d.setDate(d.getDate()+1);
17347 cells[i].className = "fc-future fc-other-month";
17348 setCellClass(this, cells[i]);
17351 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17353 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17355 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17356 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17358 if(totalRows != 6){
17359 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17360 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17363 this.fireEvent('monthchange', this, date);
17367 if(!this.internalRender){
17368 var main = this.el.dom.firstChild;
17369 var w = main.offsetWidth;
17370 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17371 Roo.fly(main).setWidth(w);
17372 this.internalRender = true;
17373 // opera does not respect the auto grow header center column
17374 // then, after it gets a width opera refuses to recalculate
17375 // without a second pass
17376 if(Roo.isOpera && !this.secondPass){
17377 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17378 this.secondPass = true;
17379 this.update.defer(10, this, [date]);
17386 findCell : function(dt) {
17387 dt = dt.clearTime().getTime();
17389 this.cells.each(function(c){
17390 //Roo.log("check " +c.dateValue + '?=' + dt);
17391 if(c.dateValue == dt){
17401 findCells : function(ev) {
17402 var s = ev.start.clone().clearTime().getTime();
17404 var e= ev.end.clone().clearTime().getTime();
17407 this.cells.each(function(c){
17408 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17410 if(c.dateValue > e){
17413 if(c.dateValue < s){
17422 // findBestRow: function(cells)
17426 // for (var i =0 ; i < cells.length;i++) {
17427 // ret = Math.max(cells[i].rows || 0,ret);
17434 addItem : function(ev)
17436 // look for vertical location slot in
17437 var cells = this.findCells(ev);
17439 // ev.row = this.findBestRow(cells);
17441 // work out the location.
17445 for(var i =0; i < cells.length; i++) {
17447 cells[i].row = cells[0].row;
17450 cells[i].row = cells[i].row + 1;
17460 if (crow.start.getY() == cells[i].getY()) {
17462 crow.end = cells[i];
17479 cells[0].events.push(ev);
17481 this.calevents.push(ev);
17484 clearEvents: function() {
17486 if(!this.calevents){
17490 Roo.each(this.cells.elements, function(c){
17496 Roo.each(this.calevents, function(e) {
17497 Roo.each(e.els, function(el) {
17498 el.un('mouseenter' ,this.onEventEnter, this);
17499 el.un('mouseleave' ,this.onEventLeave, this);
17504 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17510 renderEvents: function()
17514 this.cells.each(function(c) {
17523 if(c.row != c.events.length){
17524 r = 4 - (4 - (c.row - c.events.length));
17527 c.events = ev.slice(0, r);
17528 c.more = ev.slice(r);
17530 if(c.more.length && c.more.length == 1){
17531 c.events.push(c.more.pop());
17534 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17538 this.cells.each(function(c) {
17540 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17543 for (var e = 0; e < c.events.length; e++){
17544 var ev = c.events[e];
17545 var rows = ev.rows;
17547 for(var i = 0; i < rows.length; i++) {
17549 // how many rows should it span..
17552 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17553 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17555 unselectable : "on",
17558 cls: 'fc-event-inner',
17562 // cls: 'fc-event-time',
17563 // html : cells.length > 1 ? '' : ev.time
17567 cls: 'fc-event-title',
17568 html : String.format('{0}', ev.title)
17575 cls: 'ui-resizable-handle ui-resizable-e',
17576 html : '  '
17583 cfg.cls += ' fc-event-start';
17585 if ((i+1) == rows.length) {
17586 cfg.cls += ' fc-event-end';
17589 var ctr = _this.el.select('.fc-event-container',true).first();
17590 var cg = ctr.createChild(cfg);
17592 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17593 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17595 var r = (c.more.length) ? 1 : 0;
17596 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17597 cg.setWidth(ebox.right - sbox.x -2);
17599 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17600 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17601 cg.on('click', _this.onEventClick, _this, ev);
17612 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17613 style : 'position: absolute',
17614 unselectable : "on",
17617 cls: 'fc-event-inner',
17621 cls: 'fc-event-title',
17629 cls: 'ui-resizable-handle ui-resizable-e',
17630 html : '  '
17636 var ctr = _this.el.select('.fc-event-container',true).first();
17637 var cg = ctr.createChild(cfg);
17639 var sbox = c.select('.fc-day-content',true).first().getBox();
17640 var ebox = c.select('.fc-day-content',true).first().getBox();
17642 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17643 cg.setWidth(ebox.right - sbox.x -2);
17645 cg.on('click', _this.onMoreEventClick, _this, c.more);
17655 onEventEnter: function (e, el,event,d) {
17656 this.fireEvent('evententer', this, el, event);
17659 onEventLeave: function (e, el,event,d) {
17660 this.fireEvent('eventleave', this, el, event);
17663 onEventClick: function (e, el,event,d) {
17664 this.fireEvent('eventclick', this, el, event);
17667 onMonthChange: function () {
17671 onMoreEventClick: function(e, el, more)
17675 this.calpopover.placement = 'right';
17676 this.calpopover.setTitle('More');
17678 this.calpopover.setContent('');
17680 var ctr = this.calpopover.el.select('.popover-content', true).first();
17682 Roo.each(more, function(m){
17684 cls : 'fc-event-hori fc-event-draggable',
17687 var cg = ctr.createChild(cfg);
17689 cg.on('click', _this.onEventClick, _this, m);
17692 this.calpopover.show(el);
17697 onLoad: function ()
17699 this.calevents = [];
17702 if(this.store.getCount() > 0){
17703 this.store.data.each(function(d){
17706 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17707 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17708 time : d.data.start_time,
17709 title : d.data.title,
17710 description : d.data.description,
17711 venue : d.data.venue
17716 this.renderEvents();
17718 if(this.calevents.length && this.loadMask){
17719 this.maskEl.hide();
17723 onBeforeLoad: function()
17725 this.clearEvents();
17727 this.maskEl.show();
17741 * @class Roo.bootstrap.Popover
17742 * @extends Roo.bootstrap.Component
17743 * Bootstrap Popover class
17744 * @cfg {String} html contents of the popover (or false to use children..)
17745 * @cfg {String} title of popover (or false to hide)
17746 * @cfg {String} placement how it is placed
17747 * @cfg {String} trigger click || hover (or false to trigger manually)
17748 * @cfg {String} over what (parent or false to trigger manually.)
17749 * @cfg {Number} delay - delay before showing
17752 * Create a new Popover
17753 * @param {Object} config The config object
17756 Roo.bootstrap.Popover = function(config){
17757 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17763 * After the popover show
17765 * @param {Roo.bootstrap.Popover} this
17770 * After the popover hide
17772 * @param {Roo.bootstrap.Popover} this
17778 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17780 title: 'Fill in a title',
17783 placement : 'right',
17784 trigger : 'hover', // hover
17790 can_build_overlaid : false,
17792 getChildContainer : function()
17794 return this.el.select('.popover-content',true).first();
17797 getAutoCreate : function(){
17800 cls : 'popover roo-dynamic',
17801 style: 'display:block',
17807 cls : 'popover-inner',
17811 cls: 'popover-title popover-header',
17815 cls : 'popover-content popover-body',
17826 setTitle: function(str)
17829 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17831 setContent: function(str)
17834 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17836 // as it get's added to the bottom of the page.
17837 onRender : function(ct, position)
17839 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17841 var cfg = Roo.apply({}, this.getAutoCreate());
17845 cfg.cls += ' ' + this.cls;
17848 cfg.style = this.style;
17850 //Roo.log("adding to ");
17851 this.el = Roo.get(document.body).createChild(cfg, position);
17852 // Roo.log(this.el);
17857 initEvents : function()
17859 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17860 this.el.enableDisplayMode('block');
17862 if (this.over === false) {
17865 if (this.triggers === false) {
17868 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17869 var triggers = this.trigger ? this.trigger.split(' ') : [];
17870 Roo.each(triggers, function(trigger) {
17872 if (trigger == 'click') {
17873 on_el.on('click', this.toggle, this);
17874 } else if (trigger != 'manual') {
17875 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17876 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17878 on_el.on(eventIn ,this.enter, this);
17879 on_el.on(eventOut, this.leave, this);
17890 toggle : function () {
17891 this.hoverState == 'in' ? this.leave() : this.enter();
17894 enter : function () {
17896 clearTimeout(this.timeout);
17898 this.hoverState = 'in';
17900 if (!this.delay || !this.delay.show) {
17905 this.timeout = setTimeout(function () {
17906 if (_t.hoverState == 'in') {
17909 }, this.delay.show)
17912 leave : function() {
17913 clearTimeout(this.timeout);
17915 this.hoverState = 'out';
17917 if (!this.delay || !this.delay.hide) {
17922 this.timeout = setTimeout(function () {
17923 if (_t.hoverState == 'out') {
17926 }, this.delay.hide)
17929 show : function (on_el)
17932 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17936 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17937 if (this.html !== false) {
17938 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17940 this.el.removeClass([
17941 'fade','top','bottom', 'left', 'right','in',
17942 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17944 if (!this.title.length) {
17945 this.el.select('.popover-title',true).hide();
17948 var placement = typeof this.placement == 'function' ?
17949 this.placement.call(this, this.el, on_el) :
17952 var autoToken = /\s?auto?\s?/i;
17953 var autoPlace = autoToken.test(placement);
17955 placement = placement.replace(autoToken, '') || 'top';
17959 //this.el.setXY([0,0]);
17961 this.el.dom.style.display='block';
17962 this.el.addClass(placement);
17964 //this.el.appendTo(on_el);
17966 var p = this.getPosition();
17967 var box = this.el.getBox();
17972 var align = Roo.bootstrap.Popover.alignment[placement];
17975 this.el.alignTo(on_el, align[0],align[1]);
17976 //var arrow = this.el.select('.arrow',true).first();
17977 //arrow.set(align[2],
17979 this.el.addClass('in');
17982 if (this.el.hasClass('fade')) {
17986 this.hoverState = 'in';
17988 this.fireEvent('show', this);
17993 this.el.setXY([0,0]);
17994 this.el.removeClass('in');
17996 this.hoverState = null;
17998 this.fireEvent('hide', this);
18003 Roo.bootstrap.Popover.alignment = {
18004 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18005 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18006 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18007 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18018 * @class Roo.bootstrap.Progress
18019 * @extends Roo.bootstrap.Component
18020 * Bootstrap Progress class
18021 * @cfg {Boolean} striped striped of the progress bar
18022 * @cfg {Boolean} active animated of the progress bar
18026 * Create a new Progress
18027 * @param {Object} config The config object
18030 Roo.bootstrap.Progress = function(config){
18031 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18034 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18039 getAutoCreate : function(){
18047 cfg.cls += ' progress-striped';
18051 cfg.cls += ' active';
18070 * @class Roo.bootstrap.ProgressBar
18071 * @extends Roo.bootstrap.Component
18072 * Bootstrap ProgressBar class
18073 * @cfg {Number} aria_valuenow aria-value now
18074 * @cfg {Number} aria_valuemin aria-value min
18075 * @cfg {Number} aria_valuemax aria-value max
18076 * @cfg {String} label label for the progress bar
18077 * @cfg {String} panel (success | info | warning | danger )
18078 * @cfg {String} role role of the progress bar
18079 * @cfg {String} sr_only text
18083 * Create a new ProgressBar
18084 * @param {Object} config The config object
18087 Roo.bootstrap.ProgressBar = function(config){
18088 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18091 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18095 aria_valuemax : 100,
18101 getAutoCreate : function()
18106 cls: 'progress-bar',
18107 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18119 cfg.role = this.role;
18122 if(this.aria_valuenow){
18123 cfg['aria-valuenow'] = this.aria_valuenow;
18126 if(this.aria_valuemin){
18127 cfg['aria-valuemin'] = this.aria_valuemin;
18130 if(this.aria_valuemax){
18131 cfg['aria-valuemax'] = this.aria_valuemax;
18134 if(this.label && !this.sr_only){
18135 cfg.html = this.label;
18139 cfg.cls += ' progress-bar-' + this.panel;
18145 update : function(aria_valuenow)
18147 this.aria_valuenow = aria_valuenow;
18149 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18164 * @class Roo.bootstrap.TabGroup
18165 * @extends Roo.bootstrap.Column
18166 * Bootstrap Column class
18167 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18168 * @cfg {Boolean} carousel true to make the group behave like a carousel
18169 * @cfg {Boolean} bullets show bullets for the panels
18170 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18171 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18172 * @cfg {Boolean} showarrow (true|false) show arrow default true
18175 * Create a new TabGroup
18176 * @param {Object} config The config object
18179 Roo.bootstrap.TabGroup = function(config){
18180 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18182 this.navId = Roo.id();
18185 Roo.bootstrap.TabGroup.register(this);
18189 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18192 transition : false,
18197 slideOnTouch : false,
18200 getAutoCreate : function()
18202 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18204 cfg.cls += ' tab-content';
18206 if (this.carousel) {
18207 cfg.cls += ' carousel slide';
18210 cls : 'carousel-inner',
18214 if(this.bullets && !Roo.isTouch){
18217 cls : 'carousel-bullets',
18221 if(this.bullets_cls){
18222 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18229 cfg.cn[0].cn.push(bullets);
18232 if(this.showarrow){
18233 cfg.cn[0].cn.push({
18235 class : 'carousel-arrow',
18239 class : 'carousel-prev',
18243 class : 'fa fa-chevron-left'
18249 class : 'carousel-next',
18253 class : 'fa fa-chevron-right'
18266 initEvents: function()
18268 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18269 // this.el.on("touchstart", this.onTouchStart, this);
18272 if(this.autoslide){
18275 this.slideFn = window.setInterval(function() {
18276 _this.showPanelNext();
18280 if(this.showarrow){
18281 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18282 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18288 // onTouchStart : function(e, el, o)
18290 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18294 // this.showPanelNext();
18298 getChildContainer : function()
18300 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18304 * register a Navigation item
18305 * @param {Roo.bootstrap.NavItem} the navitem to add
18307 register : function(item)
18309 this.tabs.push( item);
18310 item.navId = this.navId; // not really needed..
18315 getActivePanel : function()
18318 Roo.each(this.tabs, function(t) {
18328 getPanelByName : function(n)
18331 Roo.each(this.tabs, function(t) {
18332 if (t.tabId == n) {
18340 indexOfPanel : function(p)
18343 Roo.each(this.tabs, function(t,i) {
18344 if (t.tabId == p.tabId) {
18353 * show a specific panel
18354 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18355 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18357 showPanel : function (pan)
18359 if(this.transition || typeof(pan) == 'undefined'){
18360 Roo.log("waiting for the transitionend");
18364 if (typeof(pan) == 'number') {
18365 pan = this.tabs[pan];
18368 if (typeof(pan) == 'string') {
18369 pan = this.getPanelByName(pan);
18372 var cur = this.getActivePanel();
18375 Roo.log('pan or acitve pan is undefined');
18379 if (pan.tabId == this.getActivePanel().tabId) {
18383 if (false === cur.fireEvent('beforedeactivate')) {
18387 if(this.bullets > 0 && !Roo.isTouch){
18388 this.setActiveBullet(this.indexOfPanel(pan));
18391 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18393 //class="carousel-item carousel-item-next carousel-item-left"
18395 this.transition = true;
18396 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18397 var lr = dir == 'next' ? 'left' : 'right';
18398 pan.el.addClass(dir); // or prev
18399 pan.el.addClass('carousel-item-' + dir); // or prev
18400 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18401 cur.el.addClass(lr); // or right
18402 pan.el.addClass(lr);
18403 cur.el.addClass('carousel-item-' +lr); // or right
18404 pan.el.addClass('carousel-item-' +lr);
18408 cur.el.on('transitionend', function() {
18409 Roo.log("trans end?");
18411 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18412 pan.setActive(true);
18414 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18415 cur.setActive(false);
18417 _this.transition = false;
18419 }, this, { single: true } );
18424 cur.setActive(false);
18425 pan.setActive(true);
18430 showPanelNext : function()
18432 var i = this.indexOfPanel(this.getActivePanel());
18434 if (i >= this.tabs.length - 1 && !this.autoslide) {
18438 if (i >= this.tabs.length - 1 && this.autoslide) {
18442 this.showPanel(this.tabs[i+1]);
18445 showPanelPrev : function()
18447 var i = this.indexOfPanel(this.getActivePanel());
18449 if (i < 1 && !this.autoslide) {
18453 if (i < 1 && this.autoslide) {
18454 i = this.tabs.length;
18457 this.showPanel(this.tabs[i-1]);
18461 addBullet: function()
18463 if(!this.bullets || Roo.isTouch){
18466 var ctr = this.el.select('.carousel-bullets',true).first();
18467 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18468 var bullet = ctr.createChild({
18469 cls : 'bullet bullet-' + i
18470 },ctr.dom.lastChild);
18475 bullet.on('click', (function(e, el, o, ii, t){
18477 e.preventDefault();
18479 this.showPanel(ii);
18481 if(this.autoslide && this.slideFn){
18482 clearInterval(this.slideFn);
18483 this.slideFn = window.setInterval(function() {
18484 _this.showPanelNext();
18488 }).createDelegate(this, [i, bullet], true));
18493 setActiveBullet : function(i)
18499 Roo.each(this.el.select('.bullet', true).elements, function(el){
18500 el.removeClass('selected');
18503 var bullet = this.el.select('.bullet-' + i, true).first();
18509 bullet.addClass('selected');
18520 Roo.apply(Roo.bootstrap.TabGroup, {
18524 * register a Navigation Group
18525 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18527 register : function(navgrp)
18529 this.groups[navgrp.navId] = navgrp;
18533 * fetch a Navigation Group based on the navigation ID
18534 * if one does not exist , it will get created.
18535 * @param {string} the navgroup to add
18536 * @returns {Roo.bootstrap.NavGroup} the navgroup
18538 get: function(navId) {
18539 if (typeof(this.groups[navId]) == 'undefined') {
18540 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18542 return this.groups[navId] ;
18557 * @class Roo.bootstrap.TabPanel
18558 * @extends Roo.bootstrap.Component
18559 * Bootstrap TabPanel class
18560 * @cfg {Boolean} active panel active
18561 * @cfg {String} html panel content
18562 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18563 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18564 * @cfg {String} href click to link..
18568 * Create a new TabPanel
18569 * @param {Object} config The config object
18572 Roo.bootstrap.TabPanel = function(config){
18573 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18577 * Fires when the active status changes
18578 * @param {Roo.bootstrap.TabPanel} this
18579 * @param {Boolean} state the new state
18584 * @event beforedeactivate
18585 * Fires before a tab is de-activated - can be used to do validation on a form.
18586 * @param {Roo.bootstrap.TabPanel} this
18587 * @return {Boolean} false if there is an error
18590 'beforedeactivate': true
18593 this.tabId = this.tabId || Roo.id();
18597 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18605 getAutoCreate : function(){
18610 // item is needed for carousel - not sure if it has any effect otherwise
18611 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18612 html: this.html || ''
18616 cfg.cls += ' active';
18620 cfg.tabId = this.tabId;
18628 initEvents: function()
18630 var p = this.parent();
18632 this.navId = this.navId || p.navId;
18634 if (typeof(this.navId) != 'undefined') {
18635 // not really needed.. but just in case.. parent should be a NavGroup.
18636 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18640 var i = tg.tabs.length - 1;
18642 if(this.active && tg.bullets > 0 && i < tg.bullets){
18643 tg.setActiveBullet(i);
18647 this.el.on('click', this.onClick, this);
18650 this.el.on("touchstart", this.onTouchStart, this);
18651 this.el.on("touchmove", this.onTouchMove, this);
18652 this.el.on("touchend", this.onTouchEnd, this);
18657 onRender : function(ct, position)
18659 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18662 setActive : function(state)
18664 Roo.log("panel - set active " + this.tabId + "=" + state);
18666 this.active = state;
18668 this.el.removeClass('active');
18670 } else if (!this.el.hasClass('active')) {
18671 this.el.addClass('active');
18674 this.fireEvent('changed', this, state);
18677 onClick : function(e)
18679 e.preventDefault();
18681 if(!this.href.length){
18685 window.location.href = this.href;
18694 onTouchStart : function(e)
18696 this.swiping = false;
18698 this.startX = e.browserEvent.touches[0].clientX;
18699 this.startY = e.browserEvent.touches[0].clientY;
18702 onTouchMove : function(e)
18704 this.swiping = true;
18706 this.endX = e.browserEvent.touches[0].clientX;
18707 this.endY = e.browserEvent.touches[0].clientY;
18710 onTouchEnd : function(e)
18717 var tabGroup = this.parent();
18719 if(this.endX > this.startX){ // swiping right
18720 tabGroup.showPanelPrev();
18724 if(this.startX > this.endX){ // swiping left
18725 tabGroup.showPanelNext();
18744 * @class Roo.bootstrap.DateField
18745 * @extends Roo.bootstrap.Input
18746 * Bootstrap DateField class
18747 * @cfg {Number} weekStart default 0
18748 * @cfg {String} viewMode default empty, (months|years)
18749 * @cfg {String} minViewMode default empty, (months|years)
18750 * @cfg {Number} startDate default -Infinity
18751 * @cfg {Number} endDate default Infinity
18752 * @cfg {Boolean} todayHighlight default false
18753 * @cfg {Boolean} todayBtn default false
18754 * @cfg {Boolean} calendarWeeks default false
18755 * @cfg {Object} daysOfWeekDisabled default empty
18756 * @cfg {Boolean} singleMode default false (true | false)
18758 * @cfg {Boolean} keyboardNavigation default true
18759 * @cfg {String} language default en
18762 * Create a new DateField
18763 * @param {Object} config The config object
18766 Roo.bootstrap.DateField = function(config){
18767 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18771 * Fires when this field show.
18772 * @param {Roo.bootstrap.DateField} this
18773 * @param {Mixed} date The date value
18778 * Fires when this field hide.
18779 * @param {Roo.bootstrap.DateField} this
18780 * @param {Mixed} date The date value
18785 * Fires when select a date.
18786 * @param {Roo.bootstrap.DateField} this
18787 * @param {Mixed} date The date value
18791 * @event beforeselect
18792 * Fires when before select a date.
18793 * @param {Roo.bootstrap.DateField} this
18794 * @param {Mixed} date The date value
18796 beforeselect : true
18800 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18803 * @cfg {String} format
18804 * The default date format string which can be overriden for localization support. The format must be
18805 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18809 * @cfg {String} altFormats
18810 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18811 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18813 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18821 todayHighlight : false,
18827 keyboardNavigation: true,
18829 calendarWeeks: false,
18831 startDate: -Infinity,
18835 daysOfWeekDisabled: [],
18839 singleMode : false,
18841 UTCDate: function()
18843 return new Date(Date.UTC.apply(Date, arguments));
18846 UTCToday: function()
18848 var today = new Date();
18849 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18852 getDate: function() {
18853 var d = this.getUTCDate();
18854 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18857 getUTCDate: function() {
18861 setDate: function(d) {
18862 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18865 setUTCDate: function(d) {
18867 this.setValue(this.formatDate(this.date));
18870 onRender: function(ct, position)
18873 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18875 this.language = this.language || 'en';
18876 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18877 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18879 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18880 this.format = this.format || 'm/d/y';
18881 this.isInline = false;
18882 this.isInput = true;
18883 this.component = this.el.select('.add-on', true).first() || false;
18884 this.component = (this.component && this.component.length === 0) ? false : this.component;
18885 this.hasInput = this.component && this.inputEl().length;
18887 if (typeof(this.minViewMode === 'string')) {
18888 switch (this.minViewMode) {
18890 this.minViewMode = 1;
18893 this.minViewMode = 2;
18896 this.minViewMode = 0;
18901 if (typeof(this.viewMode === 'string')) {
18902 switch (this.viewMode) {
18915 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18917 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18919 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18921 this.picker().on('mousedown', this.onMousedown, this);
18922 this.picker().on('click', this.onClick, this);
18924 this.picker().addClass('datepicker-dropdown');
18926 this.startViewMode = this.viewMode;
18928 if(this.singleMode){
18929 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18930 v.setVisibilityMode(Roo.Element.DISPLAY);
18934 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18935 v.setStyle('width', '189px');
18939 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18940 if(!this.calendarWeeks){
18945 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18946 v.attr('colspan', function(i, val){
18947 return parseInt(val) + 1;
18952 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18954 this.setStartDate(this.startDate);
18955 this.setEndDate(this.endDate);
18957 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18964 if(this.isInline) {
18969 picker : function()
18971 return this.pickerEl;
18972 // return this.el.select('.datepicker', true).first();
18975 fillDow: function()
18977 var dowCnt = this.weekStart;
18986 if(this.calendarWeeks){
18994 while (dowCnt < this.weekStart + 7) {
18998 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19002 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19005 fillMonths: function()
19008 var months = this.picker().select('>.datepicker-months td', true).first();
19010 months.dom.innerHTML = '';
19016 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19019 months.createChild(month);
19026 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;
19028 if (this.date < this.startDate) {
19029 this.viewDate = new Date(this.startDate);
19030 } else if (this.date > this.endDate) {
19031 this.viewDate = new Date(this.endDate);
19033 this.viewDate = new Date(this.date);
19041 var d = new Date(this.viewDate),
19042 year = d.getUTCFullYear(),
19043 month = d.getUTCMonth(),
19044 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19045 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19046 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19047 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19048 currentDate = this.date && this.date.valueOf(),
19049 today = this.UTCToday();
19051 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19053 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19055 // this.picker.select('>tfoot th.today').
19056 // .text(dates[this.language].today)
19057 // .toggle(this.todayBtn !== false);
19059 this.updateNavArrows();
19062 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19064 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19066 prevMonth.setUTCDate(day);
19068 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19070 var nextMonth = new Date(prevMonth);
19072 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19074 nextMonth = nextMonth.valueOf();
19076 var fillMonths = false;
19078 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19080 while(prevMonth.valueOf() <= nextMonth) {
19083 if (prevMonth.getUTCDay() === this.weekStart) {
19085 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19093 if(this.calendarWeeks){
19094 // ISO 8601: First week contains first thursday.
19095 // ISO also states week starts on Monday, but we can be more abstract here.
19097 // Start of current week: based on weekstart/current date
19098 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19099 // Thursday of this week
19100 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19101 // First Thursday of year, year from thursday
19102 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19103 // Calendar week: ms between thursdays, div ms per day, div 7 days
19104 calWeek = (th - yth) / 864e5 / 7 + 1;
19106 fillMonths.cn.push({
19114 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19116 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19119 if (this.todayHighlight &&
19120 prevMonth.getUTCFullYear() == today.getFullYear() &&
19121 prevMonth.getUTCMonth() == today.getMonth() &&
19122 prevMonth.getUTCDate() == today.getDate()) {
19123 clsName += ' today';
19126 if (currentDate && prevMonth.valueOf() === currentDate) {
19127 clsName += ' active';
19130 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19131 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19132 clsName += ' disabled';
19135 fillMonths.cn.push({
19137 cls: 'day ' + clsName,
19138 html: prevMonth.getDate()
19141 prevMonth.setDate(prevMonth.getDate()+1);
19144 var currentYear = this.date && this.date.getUTCFullYear();
19145 var currentMonth = this.date && this.date.getUTCMonth();
19147 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19149 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19150 v.removeClass('active');
19152 if(currentYear === year && k === currentMonth){
19153 v.addClass('active');
19156 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19157 v.addClass('disabled');
19163 year = parseInt(year/10, 10) * 10;
19165 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19167 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19170 for (var i = -1; i < 11; i++) {
19171 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19173 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19181 showMode: function(dir)
19184 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19187 Roo.each(this.picker().select('>div',true).elements, function(v){
19188 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19191 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19196 if(this.isInline) {
19200 this.picker().removeClass(['bottom', 'top']);
19202 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19204 * place to the top of element!
19208 this.picker().addClass('top');
19209 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19214 this.picker().addClass('bottom');
19216 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19219 parseDate : function(value)
19221 if(!value || value instanceof Date){
19224 var v = Date.parseDate(value, this.format);
19225 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19226 v = Date.parseDate(value, 'Y-m-d');
19228 if(!v && this.altFormats){
19229 if(!this.altFormatsArray){
19230 this.altFormatsArray = this.altFormats.split("|");
19232 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19233 v = Date.parseDate(value, this.altFormatsArray[i]);
19239 formatDate : function(date, fmt)
19241 return (!date || !(date instanceof Date)) ?
19242 date : date.dateFormat(fmt || this.format);
19245 onFocus : function()
19247 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19251 onBlur : function()
19253 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19255 var d = this.inputEl().getValue();
19262 showPopup : function()
19264 this.picker().show();
19268 this.fireEvent('showpopup', this, this.date);
19271 hidePopup : function()
19273 if(this.isInline) {
19276 this.picker().hide();
19277 this.viewMode = this.startViewMode;
19280 this.fireEvent('hidepopup', this, this.date);
19284 onMousedown: function(e)
19286 e.stopPropagation();
19287 e.preventDefault();
19292 Roo.bootstrap.DateField.superclass.keyup.call(this);
19296 setValue: function(v)
19298 if(this.fireEvent('beforeselect', this, v) !== false){
19299 var d = new Date(this.parseDate(v) ).clearTime();
19301 if(isNaN(d.getTime())){
19302 this.date = this.viewDate = '';
19303 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19307 v = this.formatDate(d);
19309 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19311 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19315 this.fireEvent('select', this, this.date);
19319 getValue: function()
19321 return this.formatDate(this.date);
19324 fireKey: function(e)
19326 if (!this.picker().isVisible()){
19327 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19333 var dateChanged = false,
19335 newDate, newViewDate;
19340 e.preventDefault();
19344 if (!this.keyboardNavigation) {
19347 dir = e.keyCode == 37 ? -1 : 1;
19350 newDate = this.moveYear(this.date, dir);
19351 newViewDate = this.moveYear(this.viewDate, dir);
19352 } else if (e.shiftKey){
19353 newDate = this.moveMonth(this.date, dir);
19354 newViewDate = this.moveMonth(this.viewDate, dir);
19356 newDate = new Date(this.date);
19357 newDate.setUTCDate(this.date.getUTCDate() + dir);
19358 newViewDate = new Date(this.viewDate);
19359 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19361 if (this.dateWithinRange(newDate)){
19362 this.date = newDate;
19363 this.viewDate = newViewDate;
19364 this.setValue(this.formatDate(this.date));
19366 e.preventDefault();
19367 dateChanged = true;
19372 if (!this.keyboardNavigation) {
19375 dir = e.keyCode == 38 ? -1 : 1;
19377 newDate = this.moveYear(this.date, dir);
19378 newViewDate = this.moveYear(this.viewDate, dir);
19379 } else if (e.shiftKey){
19380 newDate = this.moveMonth(this.date, dir);
19381 newViewDate = this.moveMonth(this.viewDate, dir);
19383 newDate = new Date(this.date);
19384 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19385 newViewDate = new Date(this.viewDate);
19386 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19388 if (this.dateWithinRange(newDate)){
19389 this.date = newDate;
19390 this.viewDate = newViewDate;
19391 this.setValue(this.formatDate(this.date));
19393 e.preventDefault();
19394 dateChanged = true;
19398 this.setValue(this.formatDate(this.date));
19400 e.preventDefault();
19403 this.setValue(this.formatDate(this.date));
19417 onClick: function(e)
19419 e.stopPropagation();
19420 e.preventDefault();
19422 var target = e.getTarget();
19424 if(target.nodeName.toLowerCase() === 'i'){
19425 target = Roo.get(target).dom.parentNode;
19428 var nodeName = target.nodeName;
19429 var className = target.className;
19430 var html = target.innerHTML;
19431 //Roo.log(nodeName);
19433 switch(nodeName.toLowerCase()) {
19435 switch(className) {
19441 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19442 switch(this.viewMode){
19444 this.viewDate = this.moveMonth(this.viewDate, dir);
19448 this.viewDate = this.moveYear(this.viewDate, dir);
19454 var date = new Date();
19455 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19457 this.setValue(this.formatDate(this.date));
19464 if (className.indexOf('disabled') < 0) {
19465 this.viewDate.setUTCDate(1);
19466 if (className.indexOf('month') > -1) {
19467 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19469 var year = parseInt(html, 10) || 0;
19470 this.viewDate.setUTCFullYear(year);
19474 if(this.singleMode){
19475 this.setValue(this.formatDate(this.viewDate));
19486 //Roo.log(className);
19487 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19488 var day = parseInt(html, 10) || 1;
19489 var year = this.viewDate.getUTCFullYear(),
19490 month = this.viewDate.getUTCMonth();
19492 if (className.indexOf('old') > -1) {
19499 } else if (className.indexOf('new') > -1) {
19507 //Roo.log([year,month,day]);
19508 this.date = this.UTCDate(year, month, day,0,0,0,0);
19509 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19511 //Roo.log(this.formatDate(this.date));
19512 this.setValue(this.formatDate(this.date));
19519 setStartDate: function(startDate)
19521 this.startDate = startDate || -Infinity;
19522 if (this.startDate !== -Infinity) {
19523 this.startDate = this.parseDate(this.startDate);
19526 this.updateNavArrows();
19529 setEndDate: function(endDate)
19531 this.endDate = endDate || Infinity;
19532 if (this.endDate !== Infinity) {
19533 this.endDate = this.parseDate(this.endDate);
19536 this.updateNavArrows();
19539 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19541 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19542 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19543 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19545 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19546 return parseInt(d, 10);
19549 this.updateNavArrows();
19552 updateNavArrows: function()
19554 if(this.singleMode){
19558 var d = new Date(this.viewDate),
19559 year = d.getUTCFullYear(),
19560 month = d.getUTCMonth();
19562 Roo.each(this.picker().select('.prev', true).elements, function(v){
19564 switch (this.viewMode) {
19567 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19573 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19580 Roo.each(this.picker().select('.next', true).elements, function(v){
19582 switch (this.viewMode) {
19585 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19591 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19599 moveMonth: function(date, dir)
19604 var new_date = new Date(date.valueOf()),
19605 day = new_date.getUTCDate(),
19606 month = new_date.getUTCMonth(),
19607 mag = Math.abs(dir),
19609 dir = dir > 0 ? 1 : -1;
19612 // If going back one month, make sure month is not current month
19613 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19615 return new_date.getUTCMonth() == month;
19617 // If going forward one month, make sure month is as expected
19618 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19620 return new_date.getUTCMonth() != new_month;
19622 new_month = month + dir;
19623 new_date.setUTCMonth(new_month);
19624 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19625 if (new_month < 0 || new_month > 11) {
19626 new_month = (new_month + 12) % 12;
19629 // For magnitudes >1, move one month at a time...
19630 for (var i=0; i<mag; i++) {
19631 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19632 new_date = this.moveMonth(new_date, dir);
19634 // ...then reset the day, keeping it in the new month
19635 new_month = new_date.getUTCMonth();
19636 new_date.setUTCDate(day);
19638 return new_month != new_date.getUTCMonth();
19641 // Common date-resetting loop -- if date is beyond end of month, make it
19644 new_date.setUTCDate(--day);
19645 new_date.setUTCMonth(new_month);
19650 moveYear: function(date, dir)
19652 return this.moveMonth(date, dir*12);
19655 dateWithinRange: function(date)
19657 return date >= this.startDate && date <= this.endDate;
19663 this.picker().remove();
19666 validateValue : function(value)
19668 if(this.getVisibilityEl().hasClass('hidden')){
19672 if(value.length < 1) {
19673 if(this.allowBlank){
19679 if(value.length < this.minLength){
19682 if(value.length > this.maxLength){
19686 var vt = Roo.form.VTypes;
19687 if(!vt[this.vtype](value, this)){
19691 if(typeof this.validator == "function"){
19692 var msg = this.validator(value);
19698 if(this.regex && !this.regex.test(value)){
19702 if(typeof(this.parseDate(value)) == 'undefined'){
19706 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19710 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19720 this.date = this.viewDate = '';
19722 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19727 Roo.apply(Roo.bootstrap.DateField, {
19738 html: '<i class="fa fa-arrow-left"/>'
19748 html: '<i class="fa fa-arrow-right"/>'
19790 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19791 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19792 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19793 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19794 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19807 navFnc: 'FullYear',
19812 navFnc: 'FullYear',
19817 Roo.apply(Roo.bootstrap.DateField, {
19821 cls: 'datepicker dropdown-menu roo-dynamic',
19825 cls: 'datepicker-days',
19829 cls: 'table-condensed',
19831 Roo.bootstrap.DateField.head,
19835 Roo.bootstrap.DateField.footer
19842 cls: 'datepicker-months',
19846 cls: 'table-condensed',
19848 Roo.bootstrap.DateField.head,
19849 Roo.bootstrap.DateField.content,
19850 Roo.bootstrap.DateField.footer
19857 cls: 'datepicker-years',
19861 cls: 'table-condensed',
19863 Roo.bootstrap.DateField.head,
19864 Roo.bootstrap.DateField.content,
19865 Roo.bootstrap.DateField.footer
19884 * @class Roo.bootstrap.TimeField
19885 * @extends Roo.bootstrap.Input
19886 * Bootstrap DateField class
19890 * Create a new TimeField
19891 * @param {Object} config The config object
19894 Roo.bootstrap.TimeField = function(config){
19895 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19899 * Fires when this field show.
19900 * @param {Roo.bootstrap.DateField} thisthis
19901 * @param {Mixed} date The date value
19906 * Fires when this field hide.
19907 * @param {Roo.bootstrap.DateField} this
19908 * @param {Mixed} date The date value
19913 * Fires when select a date.
19914 * @param {Roo.bootstrap.DateField} this
19915 * @param {Mixed} date The date value
19921 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19924 * @cfg {String} format
19925 * The default time format string which can be overriden for localization support. The format must be
19926 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19930 onRender: function(ct, position)
19933 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19935 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19937 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19939 this.pop = this.picker().select('>.datepicker-time',true).first();
19940 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19942 this.picker().on('mousedown', this.onMousedown, this);
19943 this.picker().on('click', this.onClick, this);
19945 this.picker().addClass('datepicker-dropdown');
19950 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19951 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19952 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19953 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19954 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19955 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19959 fireKey: function(e){
19960 if (!this.picker().isVisible()){
19961 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19967 e.preventDefault();
19975 this.onTogglePeriod();
19978 this.onIncrementMinutes();
19981 this.onDecrementMinutes();
19990 onClick: function(e) {
19991 e.stopPropagation();
19992 e.preventDefault();
19995 picker : function()
19997 return this.el.select('.datepicker', true).first();
20000 fillTime: function()
20002 var time = this.pop.select('tbody', true).first();
20004 time.dom.innerHTML = '';
20019 cls: 'hours-up glyphicon glyphicon-chevron-up'
20039 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20060 cls: 'timepicker-hour',
20075 cls: 'timepicker-minute',
20090 cls: 'btn btn-primary period',
20112 cls: 'hours-down glyphicon glyphicon-chevron-down'
20132 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20150 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20157 var hours = this.time.getHours();
20158 var minutes = this.time.getMinutes();
20171 hours = hours - 12;
20175 hours = '0' + hours;
20179 minutes = '0' + minutes;
20182 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20183 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20184 this.pop.select('button', true).first().dom.innerHTML = period;
20190 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20192 var cls = ['bottom'];
20194 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20201 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20206 this.picker().addClass(cls.join('-'));
20210 Roo.each(cls, function(c){
20212 _this.picker().setTop(_this.inputEl().getHeight());
20216 _this.picker().setTop(0 - _this.picker().getHeight());
20221 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20225 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20232 onFocus : function()
20234 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20238 onBlur : function()
20240 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20246 this.picker().show();
20251 this.fireEvent('show', this, this.date);
20256 this.picker().hide();
20259 this.fireEvent('hide', this, this.date);
20262 setTime : function()
20265 this.setValue(this.time.format(this.format));
20267 this.fireEvent('select', this, this.date);
20272 onMousedown: function(e){
20273 e.stopPropagation();
20274 e.preventDefault();
20277 onIncrementHours: function()
20279 Roo.log('onIncrementHours');
20280 this.time = this.time.add(Date.HOUR, 1);
20285 onDecrementHours: function()
20287 Roo.log('onDecrementHours');
20288 this.time = this.time.add(Date.HOUR, -1);
20292 onIncrementMinutes: function()
20294 Roo.log('onIncrementMinutes');
20295 this.time = this.time.add(Date.MINUTE, 1);
20299 onDecrementMinutes: function()
20301 Roo.log('onDecrementMinutes');
20302 this.time = this.time.add(Date.MINUTE, -1);
20306 onTogglePeriod: function()
20308 Roo.log('onTogglePeriod');
20309 this.time = this.time.add(Date.HOUR, 12);
20316 Roo.apply(Roo.bootstrap.TimeField, {
20346 cls: 'btn btn-info ok',
20358 Roo.apply(Roo.bootstrap.TimeField, {
20362 cls: 'datepicker dropdown-menu',
20366 cls: 'datepicker-time',
20370 cls: 'table-condensed',
20372 Roo.bootstrap.TimeField.content,
20373 Roo.bootstrap.TimeField.footer
20392 * @class Roo.bootstrap.MonthField
20393 * @extends Roo.bootstrap.Input
20394 * Bootstrap MonthField class
20396 * @cfg {String} language default en
20399 * Create a new MonthField
20400 * @param {Object} config The config object
20403 Roo.bootstrap.MonthField = function(config){
20404 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20409 * Fires when this field show.
20410 * @param {Roo.bootstrap.MonthField} this
20411 * @param {Mixed} date The date value
20416 * Fires when this field hide.
20417 * @param {Roo.bootstrap.MonthField} this
20418 * @param {Mixed} date The date value
20423 * Fires when select a date.
20424 * @param {Roo.bootstrap.MonthField} this
20425 * @param {String} oldvalue The old value
20426 * @param {String} newvalue The new value
20432 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20434 onRender: function(ct, position)
20437 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20439 this.language = this.language || 'en';
20440 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20441 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20443 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20444 this.isInline = false;
20445 this.isInput = true;
20446 this.component = this.el.select('.add-on', true).first() || false;
20447 this.component = (this.component && this.component.length === 0) ? false : this.component;
20448 this.hasInput = this.component && this.inputEL().length;
20450 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20452 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20454 this.picker().on('mousedown', this.onMousedown, this);
20455 this.picker().on('click', this.onClick, this);
20457 this.picker().addClass('datepicker-dropdown');
20459 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20460 v.setStyle('width', '189px');
20467 if(this.isInline) {
20473 setValue: function(v, suppressEvent)
20475 var o = this.getValue();
20477 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20481 if(suppressEvent !== true){
20482 this.fireEvent('select', this, o, v);
20487 getValue: function()
20492 onClick: function(e)
20494 e.stopPropagation();
20495 e.preventDefault();
20497 var target = e.getTarget();
20499 if(target.nodeName.toLowerCase() === 'i'){
20500 target = Roo.get(target).dom.parentNode;
20503 var nodeName = target.nodeName;
20504 var className = target.className;
20505 var html = target.innerHTML;
20507 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20511 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20513 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20519 picker : function()
20521 return this.pickerEl;
20524 fillMonths: function()
20527 var months = this.picker().select('>.datepicker-months td', true).first();
20529 months.dom.innerHTML = '';
20535 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20538 months.createChild(month);
20547 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20548 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20551 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20552 e.removeClass('active');
20554 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20555 e.addClass('active');
20562 if(this.isInline) {
20566 this.picker().removeClass(['bottom', 'top']);
20568 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20570 * place to the top of element!
20574 this.picker().addClass('top');
20575 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20580 this.picker().addClass('bottom');
20582 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20585 onFocus : function()
20587 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20591 onBlur : function()
20593 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20595 var d = this.inputEl().getValue();
20604 this.picker().show();
20605 this.picker().select('>.datepicker-months', true).first().show();
20609 this.fireEvent('show', this, this.date);
20614 if(this.isInline) {
20617 this.picker().hide();
20618 this.fireEvent('hide', this, this.date);
20622 onMousedown: function(e)
20624 e.stopPropagation();
20625 e.preventDefault();
20630 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20634 fireKey: function(e)
20636 if (!this.picker().isVisible()){
20637 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20648 e.preventDefault();
20652 dir = e.keyCode == 37 ? -1 : 1;
20654 this.vIndex = this.vIndex + dir;
20656 if(this.vIndex < 0){
20660 if(this.vIndex > 11){
20664 if(isNaN(this.vIndex)){
20668 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20674 dir = e.keyCode == 38 ? -1 : 1;
20676 this.vIndex = this.vIndex + dir * 4;
20678 if(this.vIndex < 0){
20682 if(this.vIndex > 11){
20686 if(isNaN(this.vIndex)){
20690 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20695 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20696 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20700 e.preventDefault();
20703 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20704 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20720 this.picker().remove();
20725 Roo.apply(Roo.bootstrap.MonthField, {
20744 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20745 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20750 Roo.apply(Roo.bootstrap.MonthField, {
20754 cls: 'datepicker dropdown-menu roo-dynamic',
20758 cls: 'datepicker-months',
20762 cls: 'table-condensed',
20764 Roo.bootstrap.DateField.content
20784 * @class Roo.bootstrap.CheckBox
20785 * @extends Roo.bootstrap.Input
20786 * Bootstrap CheckBox class
20788 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20789 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20790 * @cfg {String} boxLabel The text that appears beside the checkbox
20791 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20792 * @cfg {Boolean} checked initnal the element
20793 * @cfg {Boolean} inline inline the element (default false)
20794 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20795 * @cfg {String} tooltip label tooltip
20798 * Create a new CheckBox
20799 * @param {Object} config The config object
20802 Roo.bootstrap.CheckBox = function(config){
20803 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20808 * Fires when the element is checked or unchecked.
20809 * @param {Roo.bootstrap.CheckBox} this This input
20810 * @param {Boolean} checked The new checked value
20815 * Fires when the element is click.
20816 * @param {Roo.bootstrap.CheckBox} this This input
20823 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20825 inputType: 'checkbox',
20834 getAutoCreate : function()
20836 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20842 cfg.cls = 'form-group ' + this.inputType; //input-group
20845 cfg.cls += ' ' + this.inputType + '-inline';
20851 type : this.inputType,
20852 value : this.inputValue,
20853 cls : 'roo-' + this.inputType, //'form-box',
20854 placeholder : this.placeholder || ''
20858 if(this.inputType != 'radio'){
20862 cls : 'roo-hidden-value',
20863 value : this.checked ? this.inputValue : this.valueOff
20868 if (this.weight) { // Validity check?
20869 cfg.cls += " " + this.inputType + "-" + this.weight;
20872 if (this.disabled) {
20873 input.disabled=true;
20877 input.checked = this.checked;
20882 input.name = this.name;
20884 if(this.inputType != 'radio'){
20885 hidden.name = this.name;
20886 input.name = '_hidden_' + this.name;
20891 input.cls += ' input-' + this.size;
20896 ['xs','sm','md','lg'].map(function(size){
20897 if (settings[size]) {
20898 cfg.cls += ' col-' + size + '-' + settings[size];
20902 var inputblock = input;
20904 if (this.before || this.after) {
20907 cls : 'input-group',
20912 inputblock.cn.push({
20914 cls : 'input-group-addon',
20919 inputblock.cn.push(input);
20921 if(this.inputType != 'radio'){
20922 inputblock.cn.push(hidden);
20926 inputblock.cn.push({
20928 cls : 'input-group-addon',
20935 if (align ==='left' && this.fieldLabel.length) {
20936 // Roo.log("left and has label");
20941 cls : 'control-label',
20942 html : this.fieldLabel
20952 if(this.labelWidth > 12){
20953 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20956 if(this.labelWidth < 13 && this.labelmd == 0){
20957 this.labelmd = this.labelWidth;
20960 if(this.labellg > 0){
20961 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20962 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20965 if(this.labelmd > 0){
20966 cfg.cn[0].cls += ' col-md-' + this.labelmd;
20967 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
20970 if(this.labelsm > 0){
20971 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
20972 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
20975 if(this.labelxs > 0){
20976 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
20977 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
20980 } else if ( this.fieldLabel.length) {
20981 // Roo.log(" label");
20985 tag: this.boxLabel ? 'span' : 'label',
20987 cls: 'control-label box-input-label',
20988 //cls : 'input-group-addon',
20989 html : this.fieldLabel
20998 // Roo.log(" no label && no align");
20999 cfg.cn = [ inputblock ] ;
21005 var boxLabelCfg = {
21007 //'for': id, // box label is handled by onclick - so no for...
21009 html: this.boxLabel
21013 boxLabelCfg.tooltip = this.tooltip;
21016 cfg.cn.push(boxLabelCfg);
21019 if(this.inputType != 'radio'){
21020 cfg.cn.push(hidden);
21028 * return the real input element.
21030 inputEl: function ()
21032 return this.el.select('input.roo-' + this.inputType,true).first();
21034 hiddenEl: function ()
21036 return this.el.select('input.roo-hidden-value',true).first();
21039 labelEl: function()
21041 return this.el.select('label.control-label',true).first();
21043 /* depricated... */
21047 return this.labelEl();
21050 boxLabelEl: function()
21052 return this.el.select('label.box-label',true).first();
21055 initEvents : function()
21057 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21059 this.inputEl().on('click', this.onClick, this);
21061 if (this.boxLabel) {
21062 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21065 this.startValue = this.getValue();
21068 Roo.bootstrap.CheckBox.register(this);
21072 onClick : function(e)
21074 if(this.fireEvent('click', this, e) !== false){
21075 this.setChecked(!this.checked);
21080 setChecked : function(state,suppressEvent)
21082 this.startValue = this.getValue();
21084 if(this.inputType == 'radio'){
21086 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21087 e.dom.checked = false;
21090 this.inputEl().dom.checked = true;
21092 this.inputEl().dom.value = this.inputValue;
21094 if(suppressEvent !== true){
21095 this.fireEvent('check', this, true);
21103 this.checked = state;
21105 this.inputEl().dom.checked = state;
21108 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21110 if(suppressEvent !== true){
21111 this.fireEvent('check', this, state);
21117 getValue : function()
21119 if(this.inputType == 'radio'){
21120 return this.getGroupValue();
21123 return this.hiddenEl().dom.value;
21127 getGroupValue : function()
21129 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21133 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21136 setValue : function(v,suppressEvent)
21138 if(this.inputType == 'radio'){
21139 this.setGroupValue(v, suppressEvent);
21143 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21148 setGroupValue : function(v, suppressEvent)
21150 this.startValue = this.getValue();
21152 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21153 e.dom.checked = false;
21155 if(e.dom.value == v){
21156 e.dom.checked = true;
21160 if(suppressEvent !== true){
21161 this.fireEvent('check', this, true);
21169 validate : function()
21171 if(this.getVisibilityEl().hasClass('hidden')){
21177 (this.inputType == 'radio' && this.validateRadio()) ||
21178 (this.inputType == 'checkbox' && this.validateCheckbox())
21184 this.markInvalid();
21188 validateRadio : function()
21190 if(this.getVisibilityEl().hasClass('hidden')){
21194 if(this.allowBlank){
21200 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21201 if(!e.dom.checked){
21213 validateCheckbox : function()
21216 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21217 //return (this.getValue() == this.inputValue) ? true : false;
21220 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21228 for(var i in group){
21229 if(group[i].el.isVisible(true)){
21237 for(var i in group){
21242 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21249 * Mark this field as valid
21251 markValid : function()
21255 this.fireEvent('valid', this);
21257 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21260 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21267 if(this.inputType == 'radio'){
21268 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21269 var fg = e.findParent('.form-group', false, true);
21270 if (Roo.bootstrap.version == 3) {
21271 fg.removeClass([_this.invalidClass, _this.validClass]);
21272 fg.addClass(_this.validClass);
21274 fg.removeClass(['is-valid', 'is-invalid']);
21275 fg.addClass('is-valid');
21283 var fg = this.el.findParent('.form-group', false, true);
21284 if (Roo.bootstrap.version == 3) {
21285 fg.removeClass([this.invalidClass, this.validClass]);
21286 fg.addClass(this.validClass);
21288 fg.removeClass(['is-valid', 'is-invalid']);
21289 fg.addClass('is-valid');
21294 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21300 for(var i in group){
21301 var fg = group[i].el.findParent('.form-group', false, true);
21302 if (Roo.bootstrap.version == 3) {
21303 fg.removeClass([this.invalidClass, this.validClass]);
21304 fg.addClass(this.validClass);
21306 fg.removeClass(['is-valid', 'is-invalid']);
21307 fg.addClass('is-valid');
21313 * Mark this field as invalid
21314 * @param {String} msg The validation message
21316 markInvalid : function(msg)
21318 if(this.allowBlank){
21324 this.fireEvent('invalid', this, msg);
21326 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21329 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21333 label.markInvalid();
21336 if(this.inputType == 'radio'){
21338 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21339 var fg = e.findParent('.form-group', false, true);
21340 if (Roo.bootstrap.version == 3) {
21341 fg.removeClass([_this.invalidClass, _this.validClass]);
21342 fg.addClass(_this.invalidClass);
21344 fg.removeClass(['is-invalid', 'is-valid']);
21345 fg.addClass('is-invalid');
21353 var fg = this.el.findParent('.form-group', false, true);
21354 if (Roo.bootstrap.version == 3) {
21355 fg.removeClass([_this.invalidClass, _this.validClass]);
21356 fg.addClass(_this.invalidClass);
21358 fg.removeClass(['is-invalid', 'is-valid']);
21359 fg.addClass('is-invalid');
21364 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21370 for(var i in group){
21371 var fg = group[i].el.findParent('.form-group', false, true);
21372 if (Roo.bootstrap.version == 3) {
21373 fg.removeClass([_this.invalidClass, _this.validClass]);
21374 fg.addClass(_this.invalidClass);
21376 fg.removeClass(['is-invalid', 'is-valid']);
21377 fg.addClass('is-invalid');
21383 clearInvalid : function()
21385 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21387 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21389 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21391 if (label && label.iconEl) {
21392 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21393 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21397 disable : function()
21399 if(this.inputType != 'radio'){
21400 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21407 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21408 _this.getActionEl().addClass(this.disabledClass);
21409 e.dom.disabled = true;
21413 this.disabled = true;
21414 this.fireEvent("disable", this);
21418 enable : function()
21420 if(this.inputType != 'radio'){
21421 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21428 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21429 _this.getActionEl().removeClass(this.disabledClass);
21430 e.dom.disabled = false;
21434 this.disabled = false;
21435 this.fireEvent("enable", this);
21439 setBoxLabel : function(v)
21444 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21450 Roo.apply(Roo.bootstrap.CheckBox, {
21455 * register a CheckBox Group
21456 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21458 register : function(checkbox)
21460 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21461 this.groups[checkbox.groupId] = {};
21464 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21468 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21472 * fetch a CheckBox Group based on the group ID
21473 * @param {string} the group ID
21474 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21476 get: function(groupId) {
21477 if (typeof(this.groups[groupId]) == 'undefined') {
21481 return this.groups[groupId] ;
21494 * @class Roo.bootstrap.Radio
21495 * @extends Roo.bootstrap.Component
21496 * Bootstrap Radio class
21497 * @cfg {String} boxLabel - the label associated
21498 * @cfg {String} value - the value of radio
21501 * Create a new Radio
21502 * @param {Object} config The config object
21504 Roo.bootstrap.Radio = function(config){
21505 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21509 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21515 getAutoCreate : function()
21519 cls : 'form-group radio',
21524 html : this.boxLabel
21532 initEvents : function()
21534 this.parent().register(this);
21536 this.el.on('click', this.onClick, this);
21540 onClick : function(e)
21542 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21543 this.setChecked(true);
21547 setChecked : function(state, suppressEvent)
21549 this.parent().setValue(this.value, suppressEvent);
21553 setBoxLabel : function(v)
21558 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21573 * @class Roo.bootstrap.SecurePass
21574 * @extends Roo.bootstrap.Input
21575 * Bootstrap SecurePass class
21579 * Create a new SecurePass
21580 * @param {Object} config The config object
21583 Roo.bootstrap.SecurePass = function (config) {
21584 // these go here, so the translation tool can replace them..
21586 PwdEmpty: "Please type a password, and then retype it to confirm.",
21587 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21588 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21589 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21590 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21591 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21592 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21593 TooWeak: "Your password is Too Weak."
21595 this.meterLabel = "Password strength:";
21596 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21597 this.meterClass = [
21598 "roo-password-meter-tooweak",
21599 "roo-password-meter-weak",
21600 "roo-password-meter-medium",
21601 "roo-password-meter-strong",
21602 "roo-password-meter-grey"
21607 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21610 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21612 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21614 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21615 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21616 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21617 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21618 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21619 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21620 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21630 * @cfg {String/Object} Label for the strength meter (defaults to
21631 * 'Password strength:')
21636 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21637 * ['Weak', 'Medium', 'Strong'])
21640 pwdStrengths: false,
21653 initEvents: function ()
21655 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21657 if (this.el.is('input[type=password]') && Roo.isSafari) {
21658 this.el.on('keydown', this.SafariOnKeyDown, this);
21661 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21664 onRender: function (ct, position)
21666 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21667 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21668 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21670 this.trigger.createChild({
21675 cls: 'roo-password-meter-grey col-xs-12',
21678 //width: this.meterWidth + 'px'
21682 cls: 'roo-password-meter-text'
21688 if (this.hideTrigger) {
21689 this.trigger.setDisplayed(false);
21691 this.setSize(this.width || '', this.height || '');
21694 onDestroy: function ()
21696 if (this.trigger) {
21697 this.trigger.removeAllListeners();
21698 this.trigger.remove();
21701 this.wrap.remove();
21703 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21706 checkStrength: function ()
21708 var pwd = this.inputEl().getValue();
21709 if (pwd == this._lastPwd) {
21714 if (this.ClientSideStrongPassword(pwd)) {
21716 } else if (this.ClientSideMediumPassword(pwd)) {
21718 } else if (this.ClientSideWeakPassword(pwd)) {
21724 Roo.log('strength1: ' + strength);
21726 //var pm = this.trigger.child('div/div/div').dom;
21727 var pm = this.trigger.child('div/div');
21728 pm.removeClass(this.meterClass);
21729 pm.addClass(this.meterClass[strength]);
21732 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21734 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21736 this._lastPwd = pwd;
21740 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21742 this._lastPwd = '';
21744 var pm = this.trigger.child('div/div');
21745 pm.removeClass(this.meterClass);
21746 pm.addClass('roo-password-meter-grey');
21749 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21752 this.inputEl().dom.type='password';
21755 validateValue: function (value)
21758 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21761 if (value.length == 0) {
21762 if (this.allowBlank) {
21763 this.clearInvalid();
21767 this.markInvalid(this.errors.PwdEmpty);
21768 this.errorMsg = this.errors.PwdEmpty;
21776 if ('[\x21-\x7e]*'.match(value)) {
21777 this.markInvalid(this.errors.PwdBadChar);
21778 this.errorMsg = this.errors.PwdBadChar;
21781 if (value.length < 6) {
21782 this.markInvalid(this.errors.PwdShort);
21783 this.errorMsg = this.errors.PwdShort;
21786 if (value.length > 16) {
21787 this.markInvalid(this.errors.PwdLong);
21788 this.errorMsg = this.errors.PwdLong;
21792 if (this.ClientSideStrongPassword(value)) {
21794 } else if (this.ClientSideMediumPassword(value)) {
21796 } else if (this.ClientSideWeakPassword(value)) {
21803 if (strength < 2) {
21804 //this.markInvalid(this.errors.TooWeak);
21805 this.errorMsg = this.errors.TooWeak;
21810 console.log('strength2: ' + strength);
21812 //var pm = this.trigger.child('div/div/div').dom;
21814 var pm = this.trigger.child('div/div');
21815 pm.removeClass(this.meterClass);
21816 pm.addClass(this.meterClass[strength]);
21818 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21820 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21822 this.errorMsg = '';
21826 CharacterSetChecks: function (type)
21829 this.fResult = false;
21832 isctype: function (character, type)
21835 case this.kCapitalLetter:
21836 if (character >= 'A' && character <= 'Z') {
21841 case this.kSmallLetter:
21842 if (character >= 'a' && character <= 'z') {
21848 if (character >= '0' && character <= '9') {
21853 case this.kPunctuation:
21854 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21865 IsLongEnough: function (pwd, size)
21867 return !(pwd == null || isNaN(size) || pwd.length < size);
21870 SpansEnoughCharacterSets: function (word, nb)
21872 if (!this.IsLongEnough(word, nb))
21877 var characterSetChecks = new Array(
21878 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21879 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21882 for (var index = 0; index < word.length; ++index) {
21883 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21884 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21885 characterSetChecks[nCharSet].fResult = true;
21892 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21893 if (characterSetChecks[nCharSet].fResult) {
21898 if (nCharSets < nb) {
21904 ClientSideStrongPassword: function (pwd)
21906 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21909 ClientSideMediumPassword: function (pwd)
21911 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21914 ClientSideWeakPassword: function (pwd)
21916 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21919 })//<script type="text/javascript">
21922 * Based Ext JS Library 1.1.1
21923 * Copyright(c) 2006-2007, Ext JS, LLC.
21929 * @class Roo.HtmlEditorCore
21930 * @extends Roo.Component
21931 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21933 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21936 Roo.HtmlEditorCore = function(config){
21939 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21944 * @event initialize
21945 * Fires when the editor is fully initialized (including the iframe)
21946 * @param {Roo.HtmlEditorCore} this
21951 * Fires when the editor is first receives the focus. Any insertion must wait
21952 * until after this event.
21953 * @param {Roo.HtmlEditorCore} this
21957 * @event beforesync
21958 * Fires before the textarea is updated with content from the editor iframe. Return false
21959 * to cancel the sync.
21960 * @param {Roo.HtmlEditorCore} this
21961 * @param {String} html
21965 * @event beforepush
21966 * Fires before the iframe editor is updated with content from the textarea. Return false
21967 * to cancel the push.
21968 * @param {Roo.HtmlEditorCore} this
21969 * @param {String} html
21974 * Fires when the textarea is updated with content from the editor iframe.
21975 * @param {Roo.HtmlEditorCore} this
21976 * @param {String} html
21981 * Fires when the iframe editor is updated with content from the textarea.
21982 * @param {Roo.HtmlEditorCore} this
21983 * @param {String} html
21988 * @event editorevent
21989 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
21990 * @param {Roo.HtmlEditorCore} this
21996 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
21998 // defaults : white / black...
21999 this.applyBlacklists();
22006 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22010 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22016 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22021 * @cfg {Number} height (in pixels)
22025 * @cfg {Number} width (in pixels)
22030 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22033 stylesheets: false,
22038 // private properties
22039 validationEvent : false,
22041 initialized : false,
22043 sourceEditMode : false,
22044 onFocus : Roo.emptyFn,
22046 hideMode:'offsets',
22050 // blacklist + whitelisted elements..
22057 * Protected method that will not generally be called directly. It
22058 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22059 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22061 getDocMarkup : function(){
22065 // inherit styels from page...??
22066 if (this.stylesheets === false) {
22068 Roo.get(document.head).select('style').each(function(node) {
22069 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22072 Roo.get(document.head).select('link').each(function(node) {
22073 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22076 } else if (!this.stylesheets.length) {
22078 st = '<style type="text/css">' +
22079 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22082 st = '<style type="text/css">' +
22087 st += '<style type="text/css">' +
22088 'IMG { cursor: pointer } ' +
22091 var cls = 'roo-htmleditor-body';
22093 if(this.bodyCls.length){
22094 cls += ' ' + this.bodyCls;
22097 return '<html><head>' + st +
22098 //<style type="text/css">' +
22099 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22101 ' </head><body class="' + cls + '"></body></html>';
22105 onRender : function(ct, position)
22108 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22109 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22112 this.el.dom.style.border = '0 none';
22113 this.el.dom.setAttribute('tabIndex', -1);
22114 this.el.addClass('x-hidden hide');
22118 if(Roo.isIE){ // fix IE 1px bogus margin
22119 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22123 this.frameId = Roo.id();
22127 var iframe = this.owner.wrap.createChild({
22129 cls: 'form-control', // bootstrap..
22131 name: this.frameId,
22132 frameBorder : 'no',
22133 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22138 this.iframe = iframe.dom;
22140 this.assignDocWin();
22142 this.doc.designMode = 'on';
22145 this.doc.write(this.getDocMarkup());
22149 var task = { // must defer to wait for browser to be ready
22151 //console.log("run task?" + this.doc.readyState);
22152 this.assignDocWin();
22153 if(this.doc.body || this.doc.readyState == 'complete'){
22155 this.doc.designMode="on";
22159 Roo.TaskMgr.stop(task);
22160 this.initEditor.defer(10, this);
22167 Roo.TaskMgr.start(task);
22172 onResize : function(w, h)
22174 Roo.log('resize: ' +w + ',' + h );
22175 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22179 if(typeof w == 'number'){
22181 this.iframe.style.width = w + 'px';
22183 if(typeof h == 'number'){
22185 this.iframe.style.height = h + 'px';
22187 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22194 * Toggles the editor between standard and source edit mode.
22195 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22197 toggleSourceEdit : function(sourceEditMode){
22199 this.sourceEditMode = sourceEditMode === true;
22201 if(this.sourceEditMode){
22203 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22206 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22207 //this.iframe.className = '';
22210 //this.setSize(this.owner.wrap.getSize());
22211 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22218 * Protected method that will not generally be called directly. If you need/want
22219 * custom HTML cleanup, this is the method you should override.
22220 * @param {String} html The HTML to be cleaned
22221 * return {String} The cleaned HTML
22223 cleanHtml : function(html){
22224 html = String(html);
22225 if(html.length > 5){
22226 if(Roo.isSafari){ // strip safari nonsense
22227 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22230 if(html == ' '){
22237 * HTML Editor -> Textarea
22238 * Protected method that will not generally be called directly. Syncs the contents
22239 * of the editor iframe with the textarea.
22241 syncValue : function(){
22242 if(this.initialized){
22243 var bd = (this.doc.body || this.doc.documentElement);
22244 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22245 var html = bd.innerHTML;
22247 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22248 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22250 html = '<div style="'+m[0]+'">' + html + '</div>';
22253 html = this.cleanHtml(html);
22254 // fix up the special chars.. normaly like back quotes in word...
22255 // however we do not want to do this with chinese..
22256 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22257 var cc = b.charCodeAt();
22259 (cc >= 0x4E00 && cc < 0xA000 ) ||
22260 (cc >= 0x3400 && cc < 0x4E00 ) ||
22261 (cc >= 0xf900 && cc < 0xfb00 )
22267 if(this.owner.fireEvent('beforesync', this, html) !== false){
22268 this.el.dom.value = html;
22269 this.owner.fireEvent('sync', this, html);
22275 * Protected method that will not generally be called directly. Pushes the value of the textarea
22276 * into the iframe editor.
22278 pushValue : function(){
22279 if(this.initialized){
22280 var v = this.el.dom.value.trim();
22282 // if(v.length < 1){
22286 if(this.owner.fireEvent('beforepush', this, v) !== false){
22287 var d = (this.doc.body || this.doc.documentElement);
22289 this.cleanUpPaste();
22290 this.el.dom.value = d.innerHTML;
22291 this.owner.fireEvent('push', this, v);
22297 deferFocus : function(){
22298 this.focus.defer(10, this);
22302 focus : function(){
22303 if(this.win && !this.sourceEditMode){
22310 assignDocWin: function()
22312 var iframe = this.iframe;
22315 this.doc = iframe.contentWindow.document;
22316 this.win = iframe.contentWindow;
22318 // if (!Roo.get(this.frameId)) {
22321 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22322 // this.win = Roo.get(this.frameId).dom.contentWindow;
22324 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22328 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22329 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22334 initEditor : function(){
22335 //console.log("INIT EDITOR");
22336 this.assignDocWin();
22340 this.doc.designMode="on";
22342 this.doc.write(this.getDocMarkup());
22345 var dbody = (this.doc.body || this.doc.documentElement);
22346 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22347 // this copies styles from the containing element into thsi one..
22348 // not sure why we need all of this..
22349 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22351 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22352 //ss['background-attachment'] = 'fixed'; // w3c
22353 dbody.bgProperties = 'fixed'; // ie
22354 //Roo.DomHelper.applyStyles(dbody, ss);
22355 Roo.EventManager.on(this.doc, {
22356 //'mousedown': this.onEditorEvent,
22357 'mouseup': this.onEditorEvent,
22358 'dblclick': this.onEditorEvent,
22359 'click': this.onEditorEvent,
22360 'keyup': this.onEditorEvent,
22365 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22367 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22368 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22370 this.initialized = true;
22372 this.owner.fireEvent('initialize', this);
22377 onDestroy : function(){
22383 //for (var i =0; i < this.toolbars.length;i++) {
22384 // // fixme - ask toolbars for heights?
22385 // this.toolbars[i].onDestroy();
22388 //this.wrap.dom.innerHTML = '';
22389 //this.wrap.remove();
22394 onFirstFocus : function(){
22396 this.assignDocWin();
22399 this.activated = true;
22402 if(Roo.isGecko){ // prevent silly gecko errors
22404 var s = this.win.getSelection();
22405 if(!s.focusNode || s.focusNode.nodeType != 3){
22406 var r = s.getRangeAt(0);
22407 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22412 this.execCmd('useCSS', true);
22413 this.execCmd('styleWithCSS', false);
22416 this.owner.fireEvent('activate', this);
22420 adjustFont: function(btn){
22421 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22422 //if(Roo.isSafari){ // safari
22425 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22426 if(Roo.isSafari){ // safari
22427 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22428 v = (v < 10) ? 10 : v;
22429 v = (v > 48) ? 48 : v;
22430 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22435 v = Math.max(1, v+adjust);
22437 this.execCmd('FontSize', v );
22440 onEditorEvent : function(e)
22442 this.owner.fireEvent('editorevent', this, e);
22443 // this.updateToolbar();
22444 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22447 insertTag : function(tg)
22449 // could be a bit smarter... -> wrap the current selected tRoo..
22450 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22452 range = this.createRange(this.getSelection());
22453 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22454 wrappingNode.appendChild(range.extractContents());
22455 range.insertNode(wrappingNode);
22462 this.execCmd("formatblock", tg);
22466 insertText : function(txt)
22470 var range = this.createRange();
22471 range.deleteContents();
22472 //alert(Sender.getAttribute('label'));
22474 range.insertNode(this.doc.createTextNode(txt));
22480 * Executes a Midas editor command on the editor document and performs necessary focus and
22481 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22482 * @param {String} cmd The Midas command
22483 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22485 relayCmd : function(cmd, value){
22487 this.execCmd(cmd, value);
22488 this.owner.fireEvent('editorevent', this);
22489 //this.updateToolbar();
22490 this.owner.deferFocus();
22494 * Executes a Midas editor command directly on the editor document.
22495 * For visual commands, you should use {@link #relayCmd} instead.
22496 * <b>This should only be called after the editor is initialized.</b>
22497 * @param {String} cmd The Midas command
22498 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22500 execCmd : function(cmd, value){
22501 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22508 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22510 * @param {String} text | dom node..
22512 insertAtCursor : function(text)
22515 if(!this.activated){
22521 var r = this.doc.selection.createRange();
22532 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22536 // from jquery ui (MIT licenced)
22538 var win = this.win;
22540 if (win.getSelection && win.getSelection().getRangeAt) {
22541 range = win.getSelection().getRangeAt(0);
22542 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22543 range.insertNode(node);
22544 } else if (win.document.selection && win.document.selection.createRange) {
22545 // no firefox support
22546 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22547 win.document.selection.createRange().pasteHTML(txt);
22549 // no firefox support
22550 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22551 this.execCmd('InsertHTML', txt);
22560 mozKeyPress : function(e){
22562 var c = e.getCharCode(), cmd;
22565 c = String.fromCharCode(c).toLowerCase();
22579 this.cleanUpPaste.defer(100, this);
22587 e.preventDefault();
22595 fixKeys : function(){ // load time branching for fastest keydown performance
22597 return function(e){
22598 var k = e.getKey(), r;
22601 r = this.doc.selection.createRange();
22604 r.pasteHTML('    ');
22611 r = this.doc.selection.createRange();
22613 var target = r.parentElement();
22614 if(!target || target.tagName.toLowerCase() != 'li'){
22616 r.pasteHTML('<br />');
22622 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22623 this.cleanUpPaste.defer(100, this);
22629 }else if(Roo.isOpera){
22630 return function(e){
22631 var k = e.getKey();
22635 this.execCmd('InsertHTML','    ');
22638 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22639 this.cleanUpPaste.defer(100, this);
22644 }else if(Roo.isSafari){
22645 return function(e){
22646 var k = e.getKey();
22650 this.execCmd('InsertText','\t');
22654 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22655 this.cleanUpPaste.defer(100, this);
22663 getAllAncestors: function()
22665 var p = this.getSelectedNode();
22668 a.push(p); // push blank onto stack..
22669 p = this.getParentElement();
22673 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22677 a.push(this.doc.body);
22681 lastSelNode : false,
22684 getSelection : function()
22686 this.assignDocWin();
22687 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22690 getSelectedNode: function()
22692 // this may only work on Gecko!!!
22694 // should we cache this!!!!
22699 var range = this.createRange(this.getSelection()).cloneRange();
22702 var parent = range.parentElement();
22704 var testRange = range.duplicate();
22705 testRange.moveToElementText(parent);
22706 if (testRange.inRange(range)) {
22709 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22712 parent = parent.parentElement;
22717 // is ancestor a text element.
22718 var ac = range.commonAncestorContainer;
22719 if (ac.nodeType == 3) {
22720 ac = ac.parentNode;
22723 var ar = ac.childNodes;
22726 var other_nodes = [];
22727 var has_other_nodes = false;
22728 for (var i=0;i<ar.length;i++) {
22729 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22732 // fullly contained node.
22734 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22739 // probably selected..
22740 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22741 other_nodes.push(ar[i]);
22745 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22750 has_other_nodes = true;
22752 if (!nodes.length && other_nodes.length) {
22753 nodes= other_nodes;
22755 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22761 createRange: function(sel)
22763 // this has strange effects when using with
22764 // top toolbar - not sure if it's a great idea.
22765 //this.editor.contentWindow.focus();
22766 if (typeof sel != "undefined") {
22768 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22770 return this.doc.createRange();
22773 return this.doc.createRange();
22776 getParentElement: function()
22779 this.assignDocWin();
22780 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22782 var range = this.createRange(sel);
22785 var p = range.commonAncestorContainer;
22786 while (p.nodeType == 3) { // text node
22797 * Range intersection.. the hard stuff...
22801 * [ -- selected range --- ]
22805 * if end is before start or hits it. fail.
22806 * if start is after end or hits it fail.
22808 * if either hits (but other is outside. - then it's not
22814 // @see http://www.thismuchiknow.co.uk/?p=64.
22815 rangeIntersectsNode : function(range, node)
22817 var nodeRange = node.ownerDocument.createRange();
22819 nodeRange.selectNode(node);
22821 nodeRange.selectNodeContents(node);
22824 var rangeStartRange = range.cloneRange();
22825 rangeStartRange.collapse(true);
22827 var rangeEndRange = range.cloneRange();
22828 rangeEndRange.collapse(false);
22830 var nodeStartRange = nodeRange.cloneRange();
22831 nodeStartRange.collapse(true);
22833 var nodeEndRange = nodeRange.cloneRange();
22834 nodeEndRange.collapse(false);
22836 return rangeStartRange.compareBoundaryPoints(
22837 Range.START_TO_START, nodeEndRange) == -1 &&
22838 rangeEndRange.compareBoundaryPoints(
22839 Range.START_TO_START, nodeStartRange) == 1;
22843 rangeCompareNode : function(range, node)
22845 var nodeRange = node.ownerDocument.createRange();
22847 nodeRange.selectNode(node);
22849 nodeRange.selectNodeContents(node);
22853 range.collapse(true);
22855 nodeRange.collapse(true);
22857 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22858 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22860 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22862 var nodeIsBefore = ss == 1;
22863 var nodeIsAfter = ee == -1;
22865 if (nodeIsBefore && nodeIsAfter) {
22868 if (!nodeIsBefore && nodeIsAfter) {
22869 return 1; //right trailed.
22872 if (nodeIsBefore && !nodeIsAfter) {
22873 return 2; // left trailed.
22879 // private? - in a new class?
22880 cleanUpPaste : function()
22882 // cleans up the whole document..
22883 Roo.log('cleanuppaste');
22885 this.cleanUpChildren(this.doc.body);
22886 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22887 if (clean != this.doc.body.innerHTML) {
22888 this.doc.body.innerHTML = clean;
22893 cleanWordChars : function(input) {// change the chars to hex code
22894 var he = Roo.HtmlEditorCore;
22896 var output = input;
22897 Roo.each(he.swapCodes, function(sw) {
22898 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22900 output = output.replace(swapper, sw[1]);
22907 cleanUpChildren : function (n)
22909 if (!n.childNodes.length) {
22912 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22913 this.cleanUpChild(n.childNodes[i]);
22920 cleanUpChild : function (node)
22923 //console.log(node);
22924 if (node.nodeName == "#text") {
22925 // clean up silly Windows -- stuff?
22928 if (node.nodeName == "#comment") {
22929 node.parentNode.removeChild(node);
22930 // clean up silly Windows -- stuff?
22933 var lcname = node.tagName.toLowerCase();
22934 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22935 // whitelist of tags..
22937 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22939 node.parentNode.removeChild(node);
22944 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22946 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22947 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22949 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22950 // remove_keep_children = true;
22953 if (remove_keep_children) {
22954 this.cleanUpChildren(node);
22955 // inserts everything just before this node...
22956 while (node.childNodes.length) {
22957 var cn = node.childNodes[0];
22958 node.removeChild(cn);
22959 node.parentNode.insertBefore(cn, node);
22961 node.parentNode.removeChild(node);
22965 if (!node.attributes || !node.attributes.length) {
22966 this.cleanUpChildren(node);
22970 function cleanAttr(n,v)
22973 if (v.match(/^\./) || v.match(/^\//)) {
22976 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
22979 if (v.match(/^#/)) {
22982 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
22983 node.removeAttribute(n);
22987 var cwhite = this.cwhite;
22988 var cblack = this.cblack;
22990 function cleanStyle(n,v)
22992 if (v.match(/expression/)) { //XSS?? should we even bother..
22993 node.removeAttribute(n);
22997 var parts = v.split(/;/);
23000 Roo.each(parts, function(p) {
23001 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23005 var l = p.split(':').shift().replace(/\s+/g,'');
23006 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23008 if ( cwhite.length && cblack.indexOf(l) > -1) {
23009 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23010 //node.removeAttribute(n);
23014 // only allow 'c whitelisted system attributes'
23015 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23016 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23017 //node.removeAttribute(n);
23027 if (clean.length) {
23028 node.setAttribute(n, clean.join(';'));
23030 node.removeAttribute(n);
23036 for (var i = node.attributes.length-1; i > -1 ; i--) {
23037 var a = node.attributes[i];
23040 if (a.name.toLowerCase().substr(0,2)=='on') {
23041 node.removeAttribute(a.name);
23044 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23045 node.removeAttribute(a.name);
23048 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23049 cleanAttr(a.name,a.value); // fixme..
23052 if (a.name == 'style') {
23053 cleanStyle(a.name,a.value);
23056 /// clean up MS crap..
23057 // tecnically this should be a list of valid class'es..
23060 if (a.name == 'class') {
23061 if (a.value.match(/^Mso/)) {
23062 node.className = '';
23065 if (a.value.match(/^body$/)) {
23066 node.className = '';
23077 this.cleanUpChildren(node);
23083 * Clean up MS wordisms...
23085 cleanWord : function(node)
23090 this.cleanWord(this.doc.body);
23093 if (node.nodeName == "#text") {
23094 // clean up silly Windows -- stuff?
23097 if (node.nodeName == "#comment") {
23098 node.parentNode.removeChild(node);
23099 // clean up silly Windows -- stuff?
23103 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23104 node.parentNode.removeChild(node);
23108 // remove - but keep children..
23109 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23110 while (node.childNodes.length) {
23111 var cn = node.childNodes[0];
23112 node.removeChild(cn);
23113 node.parentNode.insertBefore(cn, node);
23115 node.parentNode.removeChild(node);
23116 this.iterateChildren(node, this.cleanWord);
23120 if (node.className.length) {
23122 var cn = node.className.split(/\W+/);
23124 Roo.each(cn, function(cls) {
23125 if (cls.match(/Mso[a-zA-Z]+/)) {
23130 node.className = cna.length ? cna.join(' ') : '';
23132 node.removeAttribute("class");
23136 if (node.hasAttribute("lang")) {
23137 node.removeAttribute("lang");
23140 if (node.hasAttribute("style")) {
23142 var styles = node.getAttribute("style").split(";");
23144 Roo.each(styles, function(s) {
23145 if (!s.match(/:/)) {
23148 var kv = s.split(":");
23149 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23152 // what ever is left... we allow.
23155 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23156 if (!nstyle.length) {
23157 node.removeAttribute('style');
23160 this.iterateChildren(node, this.cleanWord);
23166 * iterateChildren of a Node, calling fn each time, using this as the scole..
23167 * @param {DomNode} node node to iterate children of.
23168 * @param {Function} fn method of this class to call on each item.
23170 iterateChildren : function(node, fn)
23172 if (!node.childNodes.length) {
23175 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23176 fn.call(this, node.childNodes[i])
23182 * cleanTableWidths.
23184 * Quite often pasting from word etc.. results in tables with column and widths.
23185 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23188 cleanTableWidths : function(node)
23193 this.cleanTableWidths(this.doc.body);
23198 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23201 Roo.log(node.tagName);
23202 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23203 this.iterateChildren(node, this.cleanTableWidths);
23206 if (node.hasAttribute('width')) {
23207 node.removeAttribute('width');
23211 if (node.hasAttribute("style")) {
23214 var styles = node.getAttribute("style").split(";");
23216 Roo.each(styles, function(s) {
23217 if (!s.match(/:/)) {
23220 var kv = s.split(":");
23221 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23224 // what ever is left... we allow.
23227 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23228 if (!nstyle.length) {
23229 node.removeAttribute('style');
23233 this.iterateChildren(node, this.cleanTableWidths);
23241 domToHTML : function(currentElement, depth, nopadtext) {
23243 depth = depth || 0;
23244 nopadtext = nopadtext || false;
23246 if (!currentElement) {
23247 return this.domToHTML(this.doc.body);
23250 //Roo.log(currentElement);
23252 var allText = false;
23253 var nodeName = currentElement.nodeName;
23254 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23256 if (nodeName == '#text') {
23258 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23263 if (nodeName != 'BODY') {
23266 // Prints the node tagName, such as <A>, <IMG>, etc
23269 for(i = 0; i < currentElement.attributes.length;i++) {
23271 var aname = currentElement.attributes.item(i).name;
23272 if (!currentElement.attributes.item(i).value.length) {
23275 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23278 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23287 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23290 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23295 // Traverse the tree
23297 var currentElementChild = currentElement.childNodes.item(i);
23298 var allText = true;
23299 var innerHTML = '';
23301 while (currentElementChild) {
23302 // Formatting code (indent the tree so it looks nice on the screen)
23303 var nopad = nopadtext;
23304 if (lastnode == 'SPAN') {
23308 if (currentElementChild.nodeName == '#text') {
23309 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23310 toadd = nopadtext ? toadd : toadd.trim();
23311 if (!nopad && toadd.length > 80) {
23312 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23314 innerHTML += toadd;
23317 currentElementChild = currentElement.childNodes.item(i);
23323 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23325 // Recursively traverse the tree structure of the child node
23326 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23327 lastnode = currentElementChild.nodeName;
23329 currentElementChild=currentElement.childNodes.item(i);
23335 // The remaining code is mostly for formatting the tree
23336 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23341 ret+= "</"+tagName+">";
23347 applyBlacklists : function()
23349 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23350 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23354 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23355 if (b.indexOf(tag) > -1) {
23358 this.white.push(tag);
23362 Roo.each(w, function(tag) {
23363 if (b.indexOf(tag) > -1) {
23366 if (this.white.indexOf(tag) > -1) {
23369 this.white.push(tag);
23374 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23375 if (w.indexOf(tag) > -1) {
23378 this.black.push(tag);
23382 Roo.each(b, function(tag) {
23383 if (w.indexOf(tag) > -1) {
23386 if (this.black.indexOf(tag) > -1) {
23389 this.black.push(tag);
23394 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23395 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23399 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23400 if (b.indexOf(tag) > -1) {
23403 this.cwhite.push(tag);
23407 Roo.each(w, function(tag) {
23408 if (b.indexOf(tag) > -1) {
23411 if (this.cwhite.indexOf(tag) > -1) {
23414 this.cwhite.push(tag);
23419 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23420 if (w.indexOf(tag) > -1) {
23423 this.cblack.push(tag);
23427 Roo.each(b, function(tag) {
23428 if (w.indexOf(tag) > -1) {
23431 if (this.cblack.indexOf(tag) > -1) {
23434 this.cblack.push(tag);
23439 setStylesheets : function(stylesheets)
23441 if(typeof(stylesheets) == 'string'){
23442 Roo.get(this.iframe.contentDocument.head).createChild({
23444 rel : 'stylesheet',
23453 Roo.each(stylesheets, function(s) {
23458 Roo.get(_this.iframe.contentDocument.head).createChild({
23460 rel : 'stylesheet',
23469 removeStylesheets : function()
23473 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23478 setStyle : function(style)
23480 Roo.get(this.iframe.contentDocument.head).createChild({
23489 // hide stuff that is not compatible
23503 * @event specialkey
23507 * @cfg {String} fieldClass @hide
23510 * @cfg {String} focusClass @hide
23513 * @cfg {String} autoCreate @hide
23516 * @cfg {String} inputType @hide
23519 * @cfg {String} invalidClass @hide
23522 * @cfg {String} invalidText @hide
23525 * @cfg {String} msgFx @hide
23528 * @cfg {String} validateOnBlur @hide
23532 Roo.HtmlEditorCore.white = [
23533 'area', 'br', 'img', 'input', 'hr', 'wbr',
23535 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23536 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23537 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23538 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23539 'table', 'ul', 'xmp',
23541 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23544 'dir', 'menu', 'ol', 'ul', 'dl',
23550 Roo.HtmlEditorCore.black = [
23551 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23553 'base', 'basefont', 'bgsound', 'blink', 'body',
23554 'frame', 'frameset', 'head', 'html', 'ilayer',
23555 'iframe', 'layer', 'link', 'meta', 'object',
23556 'script', 'style' ,'title', 'xml' // clean later..
23558 Roo.HtmlEditorCore.clean = [
23559 'script', 'style', 'title', 'xml'
23561 Roo.HtmlEditorCore.remove = [
23566 Roo.HtmlEditorCore.ablack = [
23570 Roo.HtmlEditorCore.aclean = [
23571 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23575 Roo.HtmlEditorCore.pwhite= [
23576 'http', 'https', 'mailto'
23579 // white listed style attributes.
23580 Roo.HtmlEditorCore.cwhite= [
23581 // 'text-align', /// default is to allow most things..
23587 // black listed style attributes.
23588 Roo.HtmlEditorCore.cblack= [
23589 // 'font-size' -- this can be set by the project
23593 Roo.HtmlEditorCore.swapCodes =[
23612 * @class Roo.bootstrap.HtmlEditor
23613 * @extends Roo.bootstrap.TextArea
23614 * Bootstrap HtmlEditor class
23617 * Create a new HtmlEditor
23618 * @param {Object} config The config object
23621 Roo.bootstrap.HtmlEditor = function(config){
23622 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23623 if (!this.toolbars) {
23624 this.toolbars = [];
23627 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23630 * @event initialize
23631 * Fires when the editor is fully initialized (including the iframe)
23632 * @param {HtmlEditor} this
23637 * Fires when the editor is first receives the focus. Any insertion must wait
23638 * until after this event.
23639 * @param {HtmlEditor} this
23643 * @event beforesync
23644 * Fires before the textarea is updated with content from the editor iframe. Return false
23645 * to cancel the sync.
23646 * @param {HtmlEditor} this
23647 * @param {String} html
23651 * @event beforepush
23652 * Fires before the iframe editor is updated with content from the textarea. Return false
23653 * to cancel the push.
23654 * @param {HtmlEditor} this
23655 * @param {String} html
23660 * Fires when the textarea is updated with content from the editor iframe.
23661 * @param {HtmlEditor} this
23662 * @param {String} html
23667 * Fires when the iframe editor is updated with content from the textarea.
23668 * @param {HtmlEditor} this
23669 * @param {String} html
23673 * @event editmodechange
23674 * Fires when the editor switches edit modes
23675 * @param {HtmlEditor} this
23676 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23678 editmodechange: true,
23680 * @event editorevent
23681 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23682 * @param {HtmlEditor} this
23686 * @event firstfocus
23687 * Fires when on first focus - needed by toolbars..
23688 * @param {HtmlEditor} this
23693 * Auto save the htmlEditor value as a file into Events
23694 * @param {HtmlEditor} this
23698 * @event savedpreview
23699 * preview the saved version of htmlEditor
23700 * @param {HtmlEditor} this
23707 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23711 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23716 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23721 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23726 * @cfg {Number} height (in pixels)
23730 * @cfg {Number} width (in pixels)
23735 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23738 stylesheets: false,
23743 // private properties
23744 validationEvent : false,
23746 initialized : false,
23749 onFocus : Roo.emptyFn,
23751 hideMode:'offsets',
23753 tbContainer : false,
23757 toolbarContainer :function() {
23758 return this.wrap.select('.x-html-editor-tb',true).first();
23762 * Protected method that will not generally be called directly. It
23763 * is called when the editor creates its toolbar. Override this method if you need to
23764 * add custom toolbar buttons.
23765 * @param {HtmlEditor} editor
23767 createToolbar : function(){
23768 Roo.log('renewing');
23769 Roo.log("create toolbars");
23771 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23772 this.toolbars[0].render(this.toolbarContainer());
23776 // if (!editor.toolbars || !editor.toolbars.length) {
23777 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23780 // for (var i =0 ; i < editor.toolbars.length;i++) {
23781 // editor.toolbars[i] = Roo.factory(
23782 // typeof(editor.toolbars[i]) == 'string' ?
23783 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23784 // Roo.bootstrap.HtmlEditor);
23785 // editor.toolbars[i].init(editor);
23791 onRender : function(ct, position)
23793 // Roo.log("Call onRender: " + this.xtype);
23795 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23797 this.wrap = this.inputEl().wrap({
23798 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23801 this.editorcore.onRender(ct, position);
23803 if (this.resizable) {
23804 this.resizeEl = new Roo.Resizable(this.wrap, {
23808 minHeight : this.height,
23809 height: this.height,
23810 handles : this.resizable,
23813 resize : function(r, w, h) {
23814 _t.onResize(w,h); // -something
23820 this.createToolbar(this);
23823 if(!this.width && this.resizable){
23824 this.setSize(this.wrap.getSize());
23826 if (this.resizeEl) {
23827 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23828 // should trigger onReize..
23834 onResize : function(w, h)
23836 Roo.log('resize: ' +w + ',' + h );
23837 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23841 if(this.inputEl() ){
23842 if(typeof w == 'number'){
23843 var aw = w - this.wrap.getFrameWidth('lr');
23844 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23847 if(typeof h == 'number'){
23848 var tbh = -11; // fixme it needs to tool bar size!
23849 for (var i =0; i < this.toolbars.length;i++) {
23850 // fixme - ask toolbars for heights?
23851 tbh += this.toolbars[i].el.getHeight();
23852 //if (this.toolbars[i].footer) {
23853 // tbh += this.toolbars[i].footer.el.getHeight();
23861 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23862 ah -= 5; // knock a few pixes off for look..
23863 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23867 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23868 this.editorcore.onResize(ew,eh);
23873 * Toggles the editor between standard and source edit mode.
23874 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23876 toggleSourceEdit : function(sourceEditMode)
23878 this.editorcore.toggleSourceEdit(sourceEditMode);
23880 if(this.editorcore.sourceEditMode){
23881 Roo.log('editor - showing textarea');
23884 // Roo.log(this.syncValue());
23886 this.inputEl().removeClass(['hide', 'x-hidden']);
23887 this.inputEl().dom.removeAttribute('tabIndex');
23888 this.inputEl().focus();
23890 Roo.log('editor - hiding textarea');
23892 // Roo.log(this.pushValue());
23895 this.inputEl().addClass(['hide', 'x-hidden']);
23896 this.inputEl().dom.setAttribute('tabIndex', -1);
23897 //this.deferFocus();
23900 if(this.resizable){
23901 this.setSize(this.wrap.getSize());
23904 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23907 // private (for BoxComponent)
23908 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23910 // private (for BoxComponent)
23911 getResizeEl : function(){
23915 // private (for BoxComponent)
23916 getPositionEl : function(){
23921 initEvents : function(){
23922 this.originalValue = this.getValue();
23926 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23929 // markInvalid : Roo.emptyFn,
23931 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23934 // clearInvalid : Roo.emptyFn,
23936 setValue : function(v){
23937 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23938 this.editorcore.pushValue();
23943 deferFocus : function(){
23944 this.focus.defer(10, this);
23948 focus : function(){
23949 this.editorcore.focus();
23955 onDestroy : function(){
23961 for (var i =0; i < this.toolbars.length;i++) {
23962 // fixme - ask toolbars for heights?
23963 this.toolbars[i].onDestroy();
23966 this.wrap.dom.innerHTML = '';
23967 this.wrap.remove();
23972 onFirstFocus : function(){
23973 //Roo.log("onFirstFocus");
23974 this.editorcore.onFirstFocus();
23975 for (var i =0; i < this.toolbars.length;i++) {
23976 this.toolbars[i].onFirstFocus();
23982 syncValue : function()
23984 this.editorcore.syncValue();
23987 pushValue : function()
23989 this.editorcore.pushValue();
23993 // hide stuff that is not compatible
24007 * @event specialkey
24011 * @cfg {String} fieldClass @hide
24014 * @cfg {String} focusClass @hide
24017 * @cfg {String} autoCreate @hide
24020 * @cfg {String} inputType @hide
24024 * @cfg {String} invalidText @hide
24027 * @cfg {String} msgFx @hide
24030 * @cfg {String} validateOnBlur @hide
24039 Roo.namespace('Roo.bootstrap.htmleditor');
24041 * @class Roo.bootstrap.HtmlEditorToolbar1
24046 new Roo.bootstrap.HtmlEditor({
24049 new Roo.bootstrap.HtmlEditorToolbar1({
24050 disable : { fonts: 1 , format: 1, ..., ... , ...],
24056 * @cfg {Object} disable List of elements to disable..
24057 * @cfg {Array} btns List of additional buttons.
24061 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24064 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24067 Roo.apply(this, config);
24069 // default disabled, based on 'good practice'..
24070 this.disable = this.disable || {};
24071 Roo.applyIf(this.disable, {
24074 specialElements : true
24076 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24078 this.editor = config.editor;
24079 this.editorcore = config.editor.editorcore;
24081 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24083 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24084 // dont call parent... till later.
24086 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24091 editorcore : false,
24096 "h1","h2","h3","h4","h5","h6",
24098 "abbr", "acronym", "address", "cite", "samp", "var",
24102 onRender : function(ct, position)
24104 // Roo.log("Call onRender: " + this.xtype);
24106 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24108 this.el.dom.style.marginBottom = '0';
24110 var editorcore = this.editorcore;
24111 var editor= this.editor;
24114 var btn = function(id,cmd , toggle, handler, html){
24116 var event = toggle ? 'toggle' : 'click';
24121 xns: Roo.bootstrap,
24125 enableToggle:toggle !== false,
24127 pressed : toggle ? false : null,
24130 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24131 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24137 // var cb_box = function...
24142 xns: Roo.bootstrap,
24147 xns: Roo.bootstrap,
24151 Roo.each(this.formats, function(f) {
24152 style.menu.items.push({
24154 xns: Roo.bootstrap,
24155 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24160 editorcore.insertTag(this.tagname);
24167 children.push(style);
24169 btn('bold',false,true);
24170 btn('italic',false,true);
24171 btn('align-left', 'justifyleft',true);
24172 btn('align-center', 'justifycenter',true);
24173 btn('align-right' , 'justifyright',true);
24174 btn('link', false, false, function(btn) {
24175 //Roo.log("create link?");
24176 var url = prompt(this.createLinkText, this.defaultLinkValue);
24177 if(url && url != 'http:/'+'/'){
24178 this.editorcore.relayCmd('createlink', url);
24181 btn('list','insertunorderedlist',true);
24182 btn('pencil', false,true, function(btn){
24184 this.toggleSourceEdit(btn.pressed);
24187 if (this.editor.btns.length > 0) {
24188 for (var i = 0; i<this.editor.btns.length; i++) {
24189 children.push(this.editor.btns[i]);
24197 xns: Roo.bootstrap,
24202 xns: Roo.bootstrap,
24207 cog.menu.items.push({
24209 xns: Roo.bootstrap,
24210 html : Clean styles,
24215 editorcore.insertTag(this.tagname);
24224 this.xtype = 'NavSimplebar';
24226 for(var i=0;i< children.length;i++) {
24228 this.buttons.add(this.addxtypeChild(children[i]));
24232 editor.on('editorevent', this.updateToolbar, this);
24234 onBtnClick : function(id)
24236 this.editorcore.relayCmd(id);
24237 this.editorcore.focus();
24241 * Protected method that will not generally be called directly. It triggers
24242 * a toolbar update by reading the markup state of the current selection in the editor.
24244 updateToolbar: function(){
24246 if(!this.editorcore.activated){
24247 this.editor.onFirstFocus(); // is this neeed?
24251 var btns = this.buttons;
24252 var doc = this.editorcore.doc;
24253 btns.get('bold').setActive(doc.queryCommandState('bold'));
24254 btns.get('italic').setActive(doc.queryCommandState('italic'));
24255 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24257 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24258 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24259 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24261 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24262 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24265 var ans = this.editorcore.getAllAncestors();
24266 if (this.formatCombo) {
24269 var store = this.formatCombo.store;
24270 this.formatCombo.setValue("");
24271 for (var i =0; i < ans.length;i++) {
24272 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24274 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24282 // hides menus... - so this cant be on a menu...
24283 Roo.bootstrap.MenuMgr.hideAll();
24285 Roo.bootstrap.MenuMgr.hideAll();
24286 //this.editorsyncValue();
24288 onFirstFocus: function() {
24289 this.buttons.each(function(item){
24293 toggleSourceEdit : function(sourceEditMode){
24296 if(sourceEditMode){
24297 Roo.log("disabling buttons");
24298 this.buttons.each( function(item){
24299 if(item.cmd != 'pencil'){
24305 Roo.log("enabling buttons");
24306 if(this.editorcore.initialized){
24307 this.buttons.each( function(item){
24313 Roo.log("calling toggole on editor");
24314 // tell the editor that it's been pressed..
24315 this.editor.toggleSourceEdit(sourceEditMode);
24325 * @class Roo.bootstrap.Table.AbstractSelectionModel
24326 * @extends Roo.util.Observable
24327 * Abstract base class for grid SelectionModels. It provides the interface that should be
24328 * implemented by descendant classes. This class should not be directly instantiated.
24331 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24332 this.locked = false;
24333 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24337 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24338 /** @ignore Called by the grid automatically. Do not call directly. */
24339 init : function(grid){
24345 * Locks the selections.
24348 this.locked = true;
24352 * Unlocks the selections.
24354 unlock : function(){
24355 this.locked = false;
24359 * Returns true if the selections are locked.
24360 * @return {Boolean}
24362 isLocked : function(){
24363 return this.locked;
24367 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24368 * @class Roo.bootstrap.Table.RowSelectionModel
24369 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24370 * It supports multiple selections and keyboard selection/navigation.
24372 * @param {Object} config
24375 Roo.bootstrap.Table.RowSelectionModel = function(config){
24376 Roo.apply(this, config);
24377 this.selections = new Roo.util.MixedCollection(false, function(o){
24382 this.lastActive = false;
24386 * @event selectionchange
24387 * Fires when the selection changes
24388 * @param {SelectionModel} this
24390 "selectionchange" : true,
24392 * @event afterselectionchange
24393 * Fires after the selection changes (eg. by key press or clicking)
24394 * @param {SelectionModel} this
24396 "afterselectionchange" : true,
24398 * @event beforerowselect
24399 * Fires when a row is selected being selected, return false to cancel.
24400 * @param {SelectionModel} this
24401 * @param {Number} rowIndex The selected index
24402 * @param {Boolean} keepExisting False if other selections will be cleared
24404 "beforerowselect" : true,
24407 * Fires when a row is selected.
24408 * @param {SelectionModel} this
24409 * @param {Number} rowIndex The selected index
24410 * @param {Roo.data.Record} r The record
24412 "rowselect" : true,
24414 * @event rowdeselect
24415 * Fires when a row is deselected.
24416 * @param {SelectionModel} this
24417 * @param {Number} rowIndex The selected index
24419 "rowdeselect" : true
24421 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24422 this.locked = false;
24425 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24427 * @cfg {Boolean} singleSelect
24428 * True to allow selection of only one row at a time (defaults to false)
24430 singleSelect : false,
24433 initEvents : function()
24436 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24437 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24438 //}else{ // allow click to work like normal
24439 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24441 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24442 this.grid.on("rowclick", this.handleMouseDown, this);
24444 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24445 "up" : function(e){
24447 this.selectPrevious(e.shiftKey);
24448 }else if(this.last !== false && this.lastActive !== false){
24449 var last = this.last;
24450 this.selectRange(this.last, this.lastActive-1);
24451 this.grid.getView().focusRow(this.lastActive);
24452 if(last !== false){
24456 this.selectFirstRow();
24458 this.fireEvent("afterselectionchange", this);
24460 "down" : function(e){
24462 this.selectNext(e.shiftKey);
24463 }else if(this.last !== false && this.lastActive !== false){
24464 var last = this.last;
24465 this.selectRange(this.last, this.lastActive+1);
24466 this.grid.getView().focusRow(this.lastActive);
24467 if(last !== false){
24471 this.selectFirstRow();
24473 this.fireEvent("afterselectionchange", this);
24477 this.grid.store.on('load', function(){
24478 this.selections.clear();
24481 var view = this.grid.view;
24482 view.on("refresh", this.onRefresh, this);
24483 view.on("rowupdated", this.onRowUpdated, this);
24484 view.on("rowremoved", this.onRemove, this);
24489 onRefresh : function()
24491 var ds = this.grid.store, i, v = this.grid.view;
24492 var s = this.selections;
24493 s.each(function(r){
24494 if((i = ds.indexOfId(r.id)) != -1){
24503 onRemove : function(v, index, r){
24504 this.selections.remove(r);
24508 onRowUpdated : function(v, index, r){
24509 if(this.isSelected(r)){
24510 v.onRowSelect(index);
24516 * @param {Array} records The records to select
24517 * @param {Boolean} keepExisting (optional) True to keep existing selections
24519 selectRecords : function(records, keepExisting)
24522 this.clearSelections();
24524 var ds = this.grid.store;
24525 for(var i = 0, len = records.length; i < len; i++){
24526 this.selectRow(ds.indexOf(records[i]), true);
24531 * Gets the number of selected rows.
24534 getCount : function(){
24535 return this.selections.length;
24539 * Selects the first row in the grid.
24541 selectFirstRow : function(){
24546 * Select the last row.
24547 * @param {Boolean} keepExisting (optional) True to keep existing selections
24549 selectLastRow : function(keepExisting){
24550 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24551 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24555 * Selects the row immediately following the last selected row.
24556 * @param {Boolean} keepExisting (optional) True to keep existing selections
24558 selectNext : function(keepExisting)
24560 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24561 this.selectRow(this.last+1, keepExisting);
24562 this.grid.getView().focusRow(this.last);
24567 * Selects the row that precedes the last selected row.
24568 * @param {Boolean} keepExisting (optional) True to keep existing selections
24570 selectPrevious : function(keepExisting){
24572 this.selectRow(this.last-1, keepExisting);
24573 this.grid.getView().focusRow(this.last);
24578 * Returns the selected records
24579 * @return {Array} Array of selected records
24581 getSelections : function(){
24582 return [].concat(this.selections.items);
24586 * Returns the first selected record.
24589 getSelected : function(){
24590 return this.selections.itemAt(0);
24595 * Clears all selections.
24597 clearSelections : function(fast)
24603 var ds = this.grid.store;
24604 var s = this.selections;
24605 s.each(function(r){
24606 this.deselectRow(ds.indexOfId(r.id));
24610 this.selections.clear();
24617 * Selects all rows.
24619 selectAll : function(){
24623 this.selections.clear();
24624 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24625 this.selectRow(i, true);
24630 * Returns True if there is a selection.
24631 * @return {Boolean}
24633 hasSelection : function(){
24634 return this.selections.length > 0;
24638 * Returns True if the specified row is selected.
24639 * @param {Number/Record} record The record or index of the record to check
24640 * @return {Boolean}
24642 isSelected : function(index){
24643 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24644 return (r && this.selections.key(r.id) ? true : false);
24648 * Returns True if the specified record id is selected.
24649 * @param {String} id The id of record to check
24650 * @return {Boolean}
24652 isIdSelected : function(id){
24653 return (this.selections.key(id) ? true : false);
24658 handleMouseDBClick : function(e, t){
24662 handleMouseDown : function(e, t)
24664 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24665 if(this.isLocked() || rowIndex < 0 ){
24668 if(e.shiftKey && this.last !== false){
24669 var last = this.last;
24670 this.selectRange(last, rowIndex, e.ctrlKey);
24671 this.last = last; // reset the last
24675 var isSelected = this.isSelected(rowIndex);
24676 //Roo.log("select row:" + rowIndex);
24678 this.deselectRow(rowIndex);
24680 this.selectRow(rowIndex, true);
24684 if(e.button !== 0 && isSelected){
24685 alert('rowIndex 2: ' + rowIndex);
24686 view.focusRow(rowIndex);
24687 }else if(e.ctrlKey && isSelected){
24688 this.deselectRow(rowIndex);
24689 }else if(!isSelected){
24690 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24691 view.focusRow(rowIndex);
24695 this.fireEvent("afterselectionchange", this);
24698 handleDragableRowClick : function(grid, rowIndex, e)
24700 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24701 this.selectRow(rowIndex, false);
24702 grid.view.focusRow(rowIndex);
24703 this.fireEvent("afterselectionchange", this);
24708 * Selects multiple rows.
24709 * @param {Array} rows Array of the indexes of the row to select
24710 * @param {Boolean} keepExisting (optional) True to keep existing selections
24712 selectRows : function(rows, keepExisting){
24714 this.clearSelections();
24716 for(var i = 0, len = rows.length; i < len; i++){
24717 this.selectRow(rows[i], true);
24722 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24723 * @param {Number} startRow The index of the first row in the range
24724 * @param {Number} endRow The index of the last row in the range
24725 * @param {Boolean} keepExisting (optional) True to retain existing selections
24727 selectRange : function(startRow, endRow, keepExisting){
24732 this.clearSelections();
24734 if(startRow <= endRow){
24735 for(var i = startRow; i <= endRow; i++){
24736 this.selectRow(i, true);
24739 for(var i = startRow; i >= endRow; i--){
24740 this.selectRow(i, true);
24746 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24747 * @param {Number} startRow The index of the first row in the range
24748 * @param {Number} endRow The index of the last row in the range
24750 deselectRange : function(startRow, endRow, preventViewNotify){
24754 for(var i = startRow; i <= endRow; i++){
24755 this.deselectRow(i, preventViewNotify);
24761 * @param {Number} row The index of the row to select
24762 * @param {Boolean} keepExisting (optional) True to keep existing selections
24764 selectRow : function(index, keepExisting, preventViewNotify)
24766 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24769 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24770 if(!keepExisting || this.singleSelect){
24771 this.clearSelections();
24774 var r = this.grid.store.getAt(index);
24775 //console.log('selectRow - record id :' + r.id);
24777 this.selections.add(r);
24778 this.last = this.lastActive = index;
24779 if(!preventViewNotify){
24780 var proxy = new Roo.Element(
24781 this.grid.getRowDom(index)
24783 proxy.addClass('bg-info info');
24785 this.fireEvent("rowselect", this, index, r);
24786 this.fireEvent("selectionchange", this);
24792 * @param {Number} row The index of the row to deselect
24794 deselectRow : function(index, preventViewNotify)
24799 if(this.last == index){
24802 if(this.lastActive == index){
24803 this.lastActive = false;
24806 var r = this.grid.store.getAt(index);
24811 this.selections.remove(r);
24812 //.console.log('deselectRow - record id :' + r.id);
24813 if(!preventViewNotify){
24815 var proxy = new Roo.Element(
24816 this.grid.getRowDom(index)
24818 proxy.removeClass('bg-info info');
24820 this.fireEvent("rowdeselect", this, index);
24821 this.fireEvent("selectionchange", this);
24825 restoreLast : function(){
24827 this.last = this._last;
24832 acceptsNav : function(row, col, cm){
24833 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24837 onEditorKey : function(field, e){
24838 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24843 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24845 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24847 }else if(k == e.ENTER && !e.ctrlKey){
24851 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24853 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24855 }else if(k == e.ESC){
24859 g.startEditing(newCell[0], newCell[1]);
24865 * Ext JS Library 1.1.1
24866 * Copyright(c) 2006-2007, Ext JS, LLC.
24868 * Originally Released Under LGPL - original licence link has changed is not relivant.
24871 * <script type="text/javascript">
24875 * @class Roo.bootstrap.PagingToolbar
24876 * @extends Roo.bootstrap.NavSimplebar
24877 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24879 * Create a new PagingToolbar
24880 * @param {Object} config The config object
24881 * @param {Roo.data.Store} store
24883 Roo.bootstrap.PagingToolbar = function(config)
24885 // old args format still supported... - xtype is prefered..
24886 // created from xtype...
24888 this.ds = config.dataSource;
24890 if (config.store && !this.ds) {
24891 this.store= Roo.factory(config.store, Roo.data);
24892 this.ds = this.store;
24893 this.ds.xmodule = this.xmodule || false;
24896 this.toolbarItems = [];
24897 if (config.items) {
24898 this.toolbarItems = config.items;
24901 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24906 this.bind(this.ds);
24909 if (Roo.bootstrap.version == 4) {
24910 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24912 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24917 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24919 * @cfg {Roo.data.Store} dataSource
24920 * The underlying data store providing the paged data
24923 * @cfg {String/HTMLElement/Element} container
24924 * container The id or element that will contain the toolbar
24927 * @cfg {Boolean} displayInfo
24928 * True to display the displayMsg (defaults to false)
24931 * @cfg {Number} pageSize
24932 * The number of records to display per page (defaults to 20)
24936 * @cfg {String} displayMsg
24937 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24939 displayMsg : 'Displaying {0} - {1} of {2}',
24941 * @cfg {String} emptyMsg
24942 * The message to display when no records are found (defaults to "No data to display")
24944 emptyMsg : 'No data to display',
24946 * Customizable piece of the default paging text (defaults to "Page")
24949 beforePageText : "Page",
24951 * Customizable piece of the default paging text (defaults to "of %0")
24954 afterPageText : "of {0}",
24956 * Customizable piece of the default paging text (defaults to "First Page")
24959 firstText : "First Page",
24961 * Customizable piece of the default paging text (defaults to "Previous Page")
24964 prevText : "Previous Page",
24966 * Customizable piece of the default paging text (defaults to "Next Page")
24969 nextText : "Next Page",
24971 * Customizable piece of the default paging text (defaults to "Last Page")
24974 lastText : "Last Page",
24976 * Customizable piece of the default paging text (defaults to "Refresh")
24979 refreshText : "Refresh",
24983 onRender : function(ct, position)
24985 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
24986 this.navgroup.parentId = this.id;
24987 this.navgroup.onRender(this.el, null);
24988 // add the buttons to the navgroup
24990 if(this.displayInfo){
24991 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
24992 this.displayEl = this.el.select('.x-paging-info', true).first();
24993 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
24994 // this.displayEl = navel.el.select('span',true).first();
25000 Roo.each(_this.buttons, function(e){ // this might need to use render????
25001 Roo.factory(e).render(_this.el);
25005 Roo.each(_this.toolbarItems, function(e) {
25006 _this.navgroup.addItem(e);
25010 this.first = this.navgroup.addItem({
25011 tooltip: this.firstText,
25012 cls: "prev btn-outline-secondary",
25013 html : ' <i class="fa fa-step-backward"></i>',
25015 preventDefault: true,
25016 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25019 this.prev = this.navgroup.addItem({
25020 tooltip: this.prevText,
25021 cls: "prev btn-outline-secondary",
25022 html : ' <i class="fa fa-backward"></i>',
25024 preventDefault: true,
25025 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25027 //this.addSeparator();
25030 var field = this.navgroup.addItem( {
25032 cls : 'x-paging-position btn-outline-secondary',
25034 html : this.beforePageText +
25035 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25036 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25039 this.field = field.el.select('input', true).first();
25040 this.field.on("keydown", this.onPagingKeydown, this);
25041 this.field.on("focus", function(){this.dom.select();});
25044 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25045 //this.field.setHeight(18);
25046 //this.addSeparator();
25047 this.next = this.navgroup.addItem({
25048 tooltip: this.nextText,
25049 cls: "next btn-outline-secondary",
25050 html : ' <i class="fa fa-forward"></i>',
25052 preventDefault: true,
25053 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25055 this.last = this.navgroup.addItem({
25056 tooltip: this.lastText,
25057 html : ' <i class="fa fa-step-forward"></i>',
25058 cls: "next btn-outline-secondary",
25060 preventDefault: true,
25061 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25063 //this.addSeparator();
25064 this.loading = this.navgroup.addItem({
25065 tooltip: this.refreshText,
25066 cls: "btn-outline-secondary",
25067 html : ' <i class="fa fa-refresh"></i>',
25068 preventDefault: true,
25069 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25075 updateInfo : function(){
25076 if(this.displayEl){
25077 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25078 var msg = count == 0 ?
25082 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25084 this.displayEl.update(msg);
25089 onLoad : function(ds, r, o)
25091 this.cursor = o.params.start ? o.params.start : 0;
25093 var d = this.getPageData(),
25098 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25099 this.field.dom.value = ap;
25100 this.first.setDisabled(ap == 1);
25101 this.prev.setDisabled(ap == 1);
25102 this.next.setDisabled(ap == ps);
25103 this.last.setDisabled(ap == ps);
25104 this.loading.enable();
25109 getPageData : function(){
25110 var total = this.ds.getTotalCount();
25113 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25114 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25119 onLoadError : function(){
25120 this.loading.enable();
25124 onPagingKeydown : function(e){
25125 var k = e.getKey();
25126 var d = this.getPageData();
25128 var v = this.field.dom.value, pageNum;
25129 if(!v || isNaN(pageNum = parseInt(v, 10))){
25130 this.field.dom.value = d.activePage;
25133 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25134 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25137 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))
25139 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25140 this.field.dom.value = pageNum;
25141 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25144 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25146 var v = this.field.dom.value, pageNum;
25147 var increment = (e.shiftKey) ? 10 : 1;
25148 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25151 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25152 this.field.dom.value = d.activePage;
25155 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25157 this.field.dom.value = parseInt(v, 10) + increment;
25158 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25159 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25166 beforeLoad : function(){
25168 this.loading.disable();
25173 onClick : function(which){
25182 ds.load({params:{start: 0, limit: this.pageSize}});
25185 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25188 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25191 var total = ds.getTotalCount();
25192 var extra = total % this.pageSize;
25193 var lastStart = extra ? (total - extra) : total-this.pageSize;
25194 ds.load({params:{start: lastStart, limit: this.pageSize}});
25197 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25203 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25204 * @param {Roo.data.Store} store The data store to unbind
25206 unbind : function(ds){
25207 ds.un("beforeload", this.beforeLoad, this);
25208 ds.un("load", this.onLoad, this);
25209 ds.un("loadexception", this.onLoadError, this);
25210 ds.un("remove", this.updateInfo, this);
25211 ds.un("add", this.updateInfo, this);
25212 this.ds = undefined;
25216 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25217 * @param {Roo.data.Store} store The data store to bind
25219 bind : function(ds){
25220 ds.on("beforeload", this.beforeLoad, this);
25221 ds.on("load", this.onLoad, this);
25222 ds.on("loadexception", this.onLoadError, this);
25223 ds.on("remove", this.updateInfo, this);
25224 ds.on("add", this.updateInfo, this);
25235 * @class Roo.bootstrap.MessageBar
25236 * @extends Roo.bootstrap.Component
25237 * Bootstrap MessageBar class
25238 * @cfg {String} html contents of the MessageBar
25239 * @cfg {String} weight (info | success | warning | danger) default info
25240 * @cfg {String} beforeClass insert the bar before the given class
25241 * @cfg {Boolean} closable (true | false) default false
25242 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25245 * Create a new Element
25246 * @param {Object} config The config object
25249 Roo.bootstrap.MessageBar = function(config){
25250 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25253 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25259 beforeClass: 'bootstrap-sticky-wrap',
25261 getAutoCreate : function(){
25265 cls: 'alert alert-dismissable alert-' + this.weight,
25270 html: this.html || ''
25276 cfg.cls += ' alert-messages-fixed';
25290 onRender : function(ct, position)
25292 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25295 var cfg = Roo.apply({}, this.getAutoCreate());
25299 cfg.cls += ' ' + this.cls;
25302 cfg.style = this.style;
25304 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25306 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25309 this.el.select('>button.close').on('click', this.hide, this);
25315 if (!this.rendered) {
25321 this.fireEvent('show', this);
25327 if (!this.rendered) {
25333 this.fireEvent('hide', this);
25336 update : function()
25338 // var e = this.el.dom.firstChild;
25340 // if(this.closable){
25341 // e = e.nextSibling;
25344 // e.data = this.html || '';
25346 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25362 * @class Roo.bootstrap.Graph
25363 * @extends Roo.bootstrap.Component
25364 * Bootstrap Graph class
25368 @cfg {String} graphtype bar | vbar | pie
25369 @cfg {number} g_x coodinator | centre x (pie)
25370 @cfg {number} g_y coodinator | centre y (pie)
25371 @cfg {number} g_r radius (pie)
25372 @cfg {number} g_height height of the chart (respected by all elements in the set)
25373 @cfg {number} g_width width of the chart (respected by all elements in the set)
25374 @cfg {Object} title The title of the chart
25377 -opts (object) options for the chart
25379 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25380 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25382 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.
25383 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25385 o stretch (boolean)
25387 -opts (object) options for the pie
25390 o startAngle (number)
25391 o endAngle (number)
25395 * Create a new Input
25396 * @param {Object} config The config object
25399 Roo.bootstrap.Graph = function(config){
25400 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25406 * The img click event for the img.
25407 * @param {Roo.EventObject} e
25413 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25424 //g_colors: this.colors,
25431 getAutoCreate : function(){
25442 onRender : function(ct,position){
25445 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25447 if (typeof(Raphael) == 'undefined') {
25448 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25452 this.raphael = Raphael(this.el.dom);
25454 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25455 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25456 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25457 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25459 r.text(160, 10, "Single Series Chart").attr(txtattr);
25460 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25461 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25462 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25464 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25465 r.barchart(330, 10, 300, 220, data1);
25466 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25467 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25470 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25471 // r.barchart(30, 30, 560, 250, xdata, {
25472 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25473 // axis : "0 0 1 1",
25474 // axisxlabels : xdata
25475 // //yvalues : cols,
25478 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25480 // this.load(null,xdata,{
25481 // axis : "0 0 1 1",
25482 // axisxlabels : xdata
25487 load : function(graphtype,xdata,opts)
25489 this.raphael.clear();
25491 graphtype = this.graphtype;
25496 var r = this.raphael,
25497 fin = function () {
25498 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25500 fout = function () {
25501 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25503 pfin = function() {
25504 this.sector.stop();
25505 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25508 this.label[0].stop();
25509 this.label[0].attr({ r: 7.5 });
25510 this.label[1].attr({ "font-weight": 800 });
25513 pfout = function() {
25514 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25517 this.label[0].animate({ r: 5 }, 500, "bounce");
25518 this.label[1].attr({ "font-weight": 400 });
25524 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25527 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25530 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25531 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25533 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25540 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25545 setTitle: function(o)
25550 initEvents: function() {
25553 this.el.on('click', this.onClick, this);
25557 onClick : function(e)
25559 Roo.log('img onclick');
25560 this.fireEvent('click', this, e);
25572 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25575 * @class Roo.bootstrap.dash.NumberBox
25576 * @extends Roo.bootstrap.Component
25577 * Bootstrap NumberBox class
25578 * @cfg {String} headline Box headline
25579 * @cfg {String} content Box content
25580 * @cfg {String} icon Box icon
25581 * @cfg {String} footer Footer text
25582 * @cfg {String} fhref Footer href
25585 * Create a new NumberBox
25586 * @param {Object} config The config object
25590 Roo.bootstrap.dash.NumberBox = function(config){
25591 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25595 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25604 getAutoCreate : function(){
25608 cls : 'small-box ',
25616 cls : 'roo-headline',
25617 html : this.headline
25621 cls : 'roo-content',
25622 html : this.content
25636 cls : 'ion ' + this.icon
25645 cls : 'small-box-footer',
25646 href : this.fhref || '#',
25650 cfg.cn.push(footer);
25657 onRender : function(ct,position){
25658 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25665 setHeadline: function (value)
25667 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25670 setFooter: function (value, href)
25672 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25675 this.el.select('a.small-box-footer',true).first().attr('href', href);
25680 setContent: function (value)
25682 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25685 initEvents: function()
25699 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25702 * @class Roo.bootstrap.dash.TabBox
25703 * @extends Roo.bootstrap.Component
25704 * Bootstrap TabBox class
25705 * @cfg {String} title Title of the TabBox
25706 * @cfg {String} icon Icon of the TabBox
25707 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25708 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25711 * Create a new TabBox
25712 * @param {Object} config The config object
25716 Roo.bootstrap.dash.TabBox = function(config){
25717 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25722 * When a pane is added
25723 * @param {Roo.bootstrap.dash.TabPane} pane
25727 * @event activatepane
25728 * When a pane is activated
25729 * @param {Roo.bootstrap.dash.TabPane} pane
25731 "activatepane" : true
25739 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25744 tabScrollable : false,
25746 getChildContainer : function()
25748 return this.el.select('.tab-content', true).first();
25751 getAutoCreate : function(){
25755 cls: 'pull-left header',
25763 cls: 'fa ' + this.icon
25769 cls: 'nav nav-tabs pull-right',
25775 if(this.tabScrollable){
25782 cls: 'nav nav-tabs pull-right',
25793 cls: 'nav-tabs-custom',
25798 cls: 'tab-content no-padding',
25806 initEvents : function()
25808 //Roo.log('add add pane handler');
25809 this.on('addpane', this.onAddPane, this);
25812 * Updates the box title
25813 * @param {String} html to set the title to.
25815 setTitle : function(value)
25817 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25819 onAddPane : function(pane)
25821 this.panes.push(pane);
25822 //Roo.log('addpane');
25824 // tabs are rendere left to right..
25825 if(!this.showtabs){
25829 var ctr = this.el.select('.nav-tabs', true).first();
25832 var existing = ctr.select('.nav-tab',true);
25833 var qty = existing.getCount();;
25836 var tab = ctr.createChild({
25838 cls : 'nav-tab' + (qty ? '' : ' active'),
25846 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25849 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25851 pane.el.addClass('active');
25856 onTabClick : function(ev,un,ob,pane)
25858 //Roo.log('tab - prev default');
25859 ev.preventDefault();
25862 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25863 pane.tab.addClass('active');
25864 //Roo.log(pane.title);
25865 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25866 // technically we should have a deactivate event.. but maybe add later.
25867 // and it should not de-activate the selected tab...
25868 this.fireEvent('activatepane', pane);
25869 pane.el.addClass('active');
25870 pane.fireEvent('activate');
25875 getActivePane : function()
25878 Roo.each(this.panes, function(p) {
25879 if(p.el.hasClass('active')){
25900 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25902 * @class Roo.bootstrap.TabPane
25903 * @extends Roo.bootstrap.Component
25904 * Bootstrap TabPane class
25905 * @cfg {Boolean} active (false | true) Default false
25906 * @cfg {String} title title of panel
25910 * Create a new TabPane
25911 * @param {Object} config The config object
25914 Roo.bootstrap.dash.TabPane = function(config){
25915 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25921 * When a pane is activated
25922 * @param {Roo.bootstrap.dash.TabPane} pane
25929 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25934 // the tabBox that this is attached to.
25937 getAutoCreate : function()
25945 cfg.cls += ' active';
25950 initEvents : function()
25952 //Roo.log('trigger add pane handler');
25953 this.parent().fireEvent('addpane', this)
25957 * Updates the tab title
25958 * @param {String} html to set the title to.
25960 setTitle: function(str)
25966 this.tab.select('a', true).first().dom.innerHTML = str;
25983 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
25986 * @class Roo.bootstrap.menu.Menu
25987 * @extends Roo.bootstrap.Component
25988 * Bootstrap Menu class - container for Menu
25989 * @cfg {String} html Text of the menu
25990 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
25991 * @cfg {String} icon Font awesome icon
25992 * @cfg {String} pos Menu align to (top | bottom) default bottom
25996 * Create a new Menu
25997 * @param {Object} config The config object
26001 Roo.bootstrap.menu.Menu = function(config){
26002 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26006 * @event beforeshow
26007 * Fires before this menu is displayed
26008 * @param {Roo.bootstrap.menu.Menu} this
26012 * @event beforehide
26013 * Fires before this menu is hidden
26014 * @param {Roo.bootstrap.menu.Menu} this
26019 * Fires after this menu is displayed
26020 * @param {Roo.bootstrap.menu.Menu} this
26025 * Fires after this menu is hidden
26026 * @param {Roo.bootstrap.menu.Menu} this
26031 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26032 * @param {Roo.bootstrap.menu.Menu} this
26033 * @param {Roo.EventObject} e
26040 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26044 weight : 'default',
26049 getChildContainer : function() {
26050 if(this.isSubMenu){
26054 return this.el.select('ul.dropdown-menu', true).first();
26057 getAutoCreate : function()
26062 cls : 'roo-menu-text',
26070 cls : 'fa ' + this.icon
26081 cls : 'dropdown-button btn btn-' + this.weight,
26086 cls : 'dropdown-toggle btn btn-' + this.weight,
26096 cls : 'dropdown-menu'
26102 if(this.pos == 'top'){
26103 cfg.cls += ' dropup';
26106 if(this.isSubMenu){
26109 cls : 'dropdown-menu'
26116 onRender : function(ct, position)
26118 this.isSubMenu = ct.hasClass('dropdown-submenu');
26120 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26123 initEvents : function()
26125 if(this.isSubMenu){
26129 this.hidden = true;
26131 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26132 this.triggerEl.on('click', this.onTriggerPress, this);
26134 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26135 this.buttonEl.on('click', this.onClick, this);
26141 if(this.isSubMenu){
26145 return this.el.select('ul.dropdown-menu', true).first();
26148 onClick : function(e)
26150 this.fireEvent("click", this, e);
26153 onTriggerPress : function(e)
26155 if (this.isVisible()) {
26162 isVisible : function(){
26163 return !this.hidden;
26168 this.fireEvent("beforeshow", this);
26170 this.hidden = false;
26171 this.el.addClass('open');
26173 Roo.get(document).on("mouseup", this.onMouseUp, this);
26175 this.fireEvent("show", this);
26182 this.fireEvent("beforehide", this);
26184 this.hidden = true;
26185 this.el.removeClass('open');
26187 Roo.get(document).un("mouseup", this.onMouseUp);
26189 this.fireEvent("hide", this);
26192 onMouseUp : function()
26206 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26209 * @class Roo.bootstrap.menu.Item
26210 * @extends Roo.bootstrap.Component
26211 * Bootstrap MenuItem class
26212 * @cfg {Boolean} submenu (true | false) default false
26213 * @cfg {String} html text of the item
26214 * @cfg {String} href the link
26215 * @cfg {Boolean} disable (true | false) default false
26216 * @cfg {Boolean} preventDefault (true | false) default true
26217 * @cfg {String} icon Font awesome icon
26218 * @cfg {String} pos Submenu align to (left | right) default right
26222 * Create a new Item
26223 * @param {Object} config The config object
26227 Roo.bootstrap.menu.Item = function(config){
26228 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26232 * Fires when the mouse is hovering over this menu
26233 * @param {Roo.bootstrap.menu.Item} this
26234 * @param {Roo.EventObject} e
26239 * Fires when the mouse exits this menu
26240 * @param {Roo.bootstrap.menu.Item} this
26241 * @param {Roo.EventObject} e
26247 * The raw click event for the entire grid.
26248 * @param {Roo.EventObject} e
26254 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26259 preventDefault: true,
26264 getAutoCreate : function()
26269 cls : 'roo-menu-item-text',
26277 cls : 'fa ' + this.icon
26286 href : this.href || '#',
26293 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26297 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26299 if(this.pos == 'left'){
26300 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26307 initEvents : function()
26309 this.el.on('mouseover', this.onMouseOver, this);
26310 this.el.on('mouseout', this.onMouseOut, this);
26312 this.el.select('a', true).first().on('click', this.onClick, this);
26316 onClick : function(e)
26318 if(this.preventDefault){
26319 e.preventDefault();
26322 this.fireEvent("click", this, e);
26325 onMouseOver : function(e)
26327 if(this.submenu && this.pos == 'left'){
26328 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26331 this.fireEvent("mouseover", this, e);
26334 onMouseOut : function(e)
26336 this.fireEvent("mouseout", this, e);
26348 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26351 * @class Roo.bootstrap.menu.Separator
26352 * @extends Roo.bootstrap.Component
26353 * Bootstrap Separator class
26356 * Create a new Separator
26357 * @param {Object} config The config object
26361 Roo.bootstrap.menu.Separator = function(config){
26362 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26365 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26367 getAutoCreate : function(){
26388 * @class Roo.bootstrap.Tooltip
26389 * Bootstrap Tooltip class
26390 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26391 * to determine which dom element triggers the tooltip.
26393 * It needs to add support for additional attributes like tooltip-position
26396 * Create a new Toolti
26397 * @param {Object} config The config object
26400 Roo.bootstrap.Tooltip = function(config){
26401 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26403 this.alignment = Roo.bootstrap.Tooltip.alignment;
26405 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26406 this.alignment = config.alignment;
26411 Roo.apply(Roo.bootstrap.Tooltip, {
26413 * @function init initialize tooltip monitoring.
26417 currentTip : false,
26418 currentRegion : false,
26424 Roo.get(document).on('mouseover', this.enter ,this);
26425 Roo.get(document).on('mouseout', this.leave, this);
26428 this.currentTip = new Roo.bootstrap.Tooltip();
26431 enter : function(ev)
26433 var dom = ev.getTarget();
26435 //Roo.log(['enter',dom]);
26436 var el = Roo.fly(dom);
26437 if (this.currentEl) {
26439 //Roo.log(this.currentEl);
26440 //Roo.log(this.currentEl.contains(dom));
26441 if (this.currentEl == el) {
26444 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26450 if (this.currentTip.el) {
26451 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26455 if(!el || el.dom == document){
26461 // you can not look for children, as if el is the body.. then everythign is the child..
26462 if (!el.attr('tooltip')) { //
26463 if (!el.select("[tooltip]").elements.length) {
26466 // is the mouse over this child...?
26467 bindEl = el.select("[tooltip]").first();
26468 var xy = ev.getXY();
26469 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26470 //Roo.log("not in region.");
26473 //Roo.log("child element over..");
26476 this.currentEl = bindEl;
26477 this.currentTip.bind(bindEl);
26478 this.currentRegion = Roo.lib.Region.getRegion(dom);
26479 this.currentTip.enter();
26482 leave : function(ev)
26484 var dom = ev.getTarget();
26485 //Roo.log(['leave',dom]);
26486 if (!this.currentEl) {
26491 if (dom != this.currentEl.dom) {
26494 var xy = ev.getXY();
26495 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26498 // only activate leave if mouse cursor is outside... bounding box..
26503 if (this.currentTip) {
26504 this.currentTip.leave();
26506 //Roo.log('clear currentEl');
26507 this.currentEl = false;
26512 'left' : ['r-l', [-2,0], 'right'],
26513 'right' : ['l-r', [2,0], 'left'],
26514 'bottom' : ['t-b', [0,2], 'top'],
26515 'top' : [ 'b-t', [0,-2], 'bottom']
26521 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26526 delay : null, // can be { show : 300 , hide: 500}
26530 hoverState : null, //???
26532 placement : 'bottom',
26536 getAutoCreate : function(){
26543 cls : 'tooltip-arrow'
26546 cls : 'tooltip-inner'
26553 bind : function(el)
26559 enter : function () {
26561 if (this.timeout != null) {
26562 clearTimeout(this.timeout);
26565 this.hoverState = 'in';
26566 //Roo.log("enter - show");
26567 if (!this.delay || !this.delay.show) {
26572 this.timeout = setTimeout(function () {
26573 if (_t.hoverState == 'in') {
26576 }, this.delay.show);
26580 clearTimeout(this.timeout);
26582 this.hoverState = 'out';
26583 if (!this.delay || !this.delay.hide) {
26589 this.timeout = setTimeout(function () {
26590 //Roo.log("leave - timeout");
26592 if (_t.hoverState == 'out') {
26594 Roo.bootstrap.Tooltip.currentEl = false;
26599 show : function (msg)
26602 this.render(document.body);
26605 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26607 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26609 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26611 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26613 var placement = typeof this.placement == 'function' ?
26614 this.placement.call(this, this.el, on_el) :
26617 var autoToken = /\s?auto?\s?/i;
26618 var autoPlace = autoToken.test(placement);
26620 placement = placement.replace(autoToken, '') || 'top';
26624 //this.el.setXY([0,0]);
26626 //this.el.dom.style.display='block';
26628 //this.el.appendTo(on_el);
26630 var p = this.getPosition();
26631 var box = this.el.getBox();
26637 var align = this.alignment[placement];
26639 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26641 if(placement == 'top' || placement == 'bottom'){
26643 placement = 'right';
26646 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26647 placement = 'left';
26650 var scroll = Roo.select('body', true).first().getScroll();
26652 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26656 align = this.alignment[placement];
26659 this.el.alignTo(this.bindEl, align[0],align[1]);
26660 //var arrow = this.el.select('.arrow',true).first();
26661 //arrow.set(align[2],
26663 this.el.addClass(placement);
26665 this.el.addClass('in fade');
26667 this.hoverState = null;
26669 if (this.el.hasClass('fade')) {
26680 //this.el.setXY([0,0]);
26681 this.el.removeClass('in');
26697 * @class Roo.bootstrap.LocationPicker
26698 * @extends Roo.bootstrap.Component
26699 * Bootstrap LocationPicker class
26700 * @cfg {Number} latitude Position when init default 0
26701 * @cfg {Number} longitude Position when init default 0
26702 * @cfg {Number} zoom default 15
26703 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26704 * @cfg {Boolean} mapTypeControl default false
26705 * @cfg {Boolean} disableDoubleClickZoom default false
26706 * @cfg {Boolean} scrollwheel default true
26707 * @cfg {Boolean} streetViewControl default false
26708 * @cfg {Number} radius default 0
26709 * @cfg {String} locationName
26710 * @cfg {Boolean} draggable default true
26711 * @cfg {Boolean} enableAutocomplete default false
26712 * @cfg {Boolean} enableReverseGeocode default true
26713 * @cfg {String} markerTitle
26716 * Create a new LocationPicker
26717 * @param {Object} config The config object
26721 Roo.bootstrap.LocationPicker = function(config){
26723 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26728 * Fires when the picker initialized.
26729 * @param {Roo.bootstrap.LocationPicker} this
26730 * @param {Google Location} location
26734 * @event positionchanged
26735 * Fires when the picker position changed.
26736 * @param {Roo.bootstrap.LocationPicker} this
26737 * @param {Google Location} location
26739 positionchanged : true,
26742 * Fires when the map resize.
26743 * @param {Roo.bootstrap.LocationPicker} this
26748 * Fires when the map show.
26749 * @param {Roo.bootstrap.LocationPicker} this
26754 * Fires when the map hide.
26755 * @param {Roo.bootstrap.LocationPicker} this
26760 * Fires when click the map.
26761 * @param {Roo.bootstrap.LocationPicker} this
26762 * @param {Map event} e
26766 * @event mapRightClick
26767 * Fires when right click the map.
26768 * @param {Roo.bootstrap.LocationPicker} this
26769 * @param {Map event} e
26771 mapRightClick : true,
26773 * @event markerClick
26774 * Fires when click the marker.
26775 * @param {Roo.bootstrap.LocationPicker} this
26776 * @param {Map event} e
26778 markerClick : true,
26780 * @event markerRightClick
26781 * Fires when right click the marker.
26782 * @param {Roo.bootstrap.LocationPicker} this
26783 * @param {Map event} e
26785 markerRightClick : true,
26787 * @event OverlayViewDraw
26788 * Fires when OverlayView Draw
26789 * @param {Roo.bootstrap.LocationPicker} this
26791 OverlayViewDraw : true,
26793 * @event OverlayViewOnAdd
26794 * Fires when OverlayView Draw
26795 * @param {Roo.bootstrap.LocationPicker} this
26797 OverlayViewOnAdd : true,
26799 * @event OverlayViewOnRemove
26800 * Fires when OverlayView Draw
26801 * @param {Roo.bootstrap.LocationPicker} this
26803 OverlayViewOnRemove : true,
26805 * @event OverlayViewShow
26806 * Fires when OverlayView Draw
26807 * @param {Roo.bootstrap.LocationPicker} this
26808 * @param {Pixel} cpx
26810 OverlayViewShow : true,
26812 * @event OverlayViewHide
26813 * Fires when OverlayView Draw
26814 * @param {Roo.bootstrap.LocationPicker} this
26816 OverlayViewHide : true,
26818 * @event loadexception
26819 * Fires when load google lib failed.
26820 * @param {Roo.bootstrap.LocationPicker} this
26822 loadexception : true
26827 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26829 gMapContext: false,
26835 mapTypeControl: false,
26836 disableDoubleClickZoom: false,
26838 streetViewControl: false,
26842 enableAutocomplete: false,
26843 enableReverseGeocode: true,
26846 getAutoCreate: function()
26851 cls: 'roo-location-picker'
26857 initEvents: function(ct, position)
26859 if(!this.el.getWidth() || this.isApplied()){
26863 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26868 initial: function()
26870 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26871 this.fireEvent('loadexception', this);
26875 if(!this.mapTypeId){
26876 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26879 this.gMapContext = this.GMapContext();
26881 this.initOverlayView();
26883 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26887 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26888 _this.setPosition(_this.gMapContext.marker.position);
26891 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26892 _this.fireEvent('mapClick', this, event);
26896 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26897 _this.fireEvent('mapRightClick', this, event);
26901 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26902 _this.fireEvent('markerClick', this, event);
26906 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26907 _this.fireEvent('markerRightClick', this, event);
26911 this.setPosition(this.gMapContext.location);
26913 this.fireEvent('initial', this, this.gMapContext.location);
26916 initOverlayView: function()
26920 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26924 _this.fireEvent('OverlayViewDraw', _this);
26929 _this.fireEvent('OverlayViewOnAdd', _this);
26932 onRemove: function()
26934 _this.fireEvent('OverlayViewOnRemove', _this);
26937 show: function(cpx)
26939 _this.fireEvent('OverlayViewShow', _this, cpx);
26944 _this.fireEvent('OverlayViewHide', _this);
26950 fromLatLngToContainerPixel: function(event)
26952 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26955 isApplied: function()
26957 return this.getGmapContext() == false ? false : true;
26960 getGmapContext: function()
26962 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26965 GMapContext: function()
26967 var position = new google.maps.LatLng(this.latitude, this.longitude);
26969 var _map = new google.maps.Map(this.el.dom, {
26972 mapTypeId: this.mapTypeId,
26973 mapTypeControl: this.mapTypeControl,
26974 disableDoubleClickZoom: this.disableDoubleClickZoom,
26975 scrollwheel: this.scrollwheel,
26976 streetViewControl: this.streetViewControl,
26977 locationName: this.locationName,
26978 draggable: this.draggable,
26979 enableAutocomplete: this.enableAutocomplete,
26980 enableReverseGeocode: this.enableReverseGeocode
26983 var _marker = new google.maps.Marker({
26984 position: position,
26986 title: this.markerTitle,
26987 draggable: this.draggable
26994 location: position,
26995 radius: this.radius,
26996 locationName: this.locationName,
26997 addressComponents: {
26998 formatted_address: null,
26999 addressLine1: null,
27000 addressLine2: null,
27002 streetNumber: null,
27006 stateOrProvince: null
27009 domContainer: this.el.dom,
27010 geodecoder: new google.maps.Geocoder()
27014 drawCircle: function(center, radius, options)
27016 if (this.gMapContext.circle != null) {
27017 this.gMapContext.circle.setMap(null);
27021 options = Roo.apply({}, options, {
27022 strokeColor: "#0000FF",
27023 strokeOpacity: .35,
27025 fillColor: "#0000FF",
27029 options.map = this.gMapContext.map;
27030 options.radius = radius;
27031 options.center = center;
27032 this.gMapContext.circle = new google.maps.Circle(options);
27033 return this.gMapContext.circle;
27039 setPosition: function(location)
27041 this.gMapContext.location = location;
27042 this.gMapContext.marker.setPosition(location);
27043 this.gMapContext.map.panTo(location);
27044 this.drawCircle(location, this.gMapContext.radius, {});
27048 if (this.gMapContext.settings.enableReverseGeocode) {
27049 this.gMapContext.geodecoder.geocode({
27050 latLng: this.gMapContext.location
27051 }, function(results, status) {
27053 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27054 _this.gMapContext.locationName = results[0].formatted_address;
27055 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27057 _this.fireEvent('positionchanged', this, location);
27064 this.fireEvent('positionchanged', this, location);
27069 google.maps.event.trigger(this.gMapContext.map, "resize");
27071 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27073 this.fireEvent('resize', this);
27076 setPositionByLatLng: function(latitude, longitude)
27078 this.setPosition(new google.maps.LatLng(latitude, longitude));
27081 getCurrentPosition: function()
27084 latitude: this.gMapContext.location.lat(),
27085 longitude: this.gMapContext.location.lng()
27089 getAddressName: function()
27091 return this.gMapContext.locationName;
27094 getAddressComponents: function()
27096 return this.gMapContext.addressComponents;
27099 address_component_from_google_geocode: function(address_components)
27103 for (var i = 0; i < address_components.length; i++) {
27104 var component = address_components[i];
27105 if (component.types.indexOf("postal_code") >= 0) {
27106 result.postalCode = component.short_name;
27107 } else if (component.types.indexOf("street_number") >= 0) {
27108 result.streetNumber = component.short_name;
27109 } else if (component.types.indexOf("route") >= 0) {
27110 result.streetName = component.short_name;
27111 } else if (component.types.indexOf("neighborhood") >= 0) {
27112 result.city = component.short_name;
27113 } else if (component.types.indexOf("locality") >= 0) {
27114 result.city = component.short_name;
27115 } else if (component.types.indexOf("sublocality") >= 0) {
27116 result.district = component.short_name;
27117 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27118 result.stateOrProvince = component.short_name;
27119 } else if (component.types.indexOf("country") >= 0) {
27120 result.country = component.short_name;
27124 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27125 result.addressLine2 = "";
27129 setZoomLevel: function(zoom)
27131 this.gMapContext.map.setZoom(zoom);
27144 this.fireEvent('show', this);
27155 this.fireEvent('hide', this);
27160 Roo.apply(Roo.bootstrap.LocationPicker, {
27162 OverlayView : function(map, options)
27164 options = options || {};
27178 * @class Roo.bootstrap.Alert
27179 * @extends Roo.bootstrap.Component
27180 * Bootstrap Alert class
27181 * @cfg {String} title The title of alert
27182 * @cfg {String} html The content of alert
27183 * @cfg {String} weight ( success | info | warning | danger )
27184 * @cfg {String} faicon font-awesomeicon
27187 * Create a new alert
27188 * @param {Object} config The config object
27192 Roo.bootstrap.Alert = function(config){
27193 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27197 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27204 getAutoCreate : function()
27213 cls : 'roo-alert-icon'
27218 cls : 'roo-alert-title',
27223 cls : 'roo-alert-text',
27230 cfg.cn[0].cls += ' fa ' + this.faicon;
27234 cfg.cls += ' alert-' + this.weight;
27240 initEvents: function()
27242 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27245 setTitle : function(str)
27247 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27250 setText : function(str)
27252 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27255 setWeight : function(weight)
27258 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27261 this.weight = weight;
27263 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27266 setIcon : function(icon)
27269 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27272 this.faicon = icon;
27274 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27295 * @class Roo.bootstrap.UploadCropbox
27296 * @extends Roo.bootstrap.Component
27297 * Bootstrap UploadCropbox class
27298 * @cfg {String} emptyText show when image has been loaded
27299 * @cfg {String} rotateNotify show when image too small to rotate
27300 * @cfg {Number} errorTimeout default 3000
27301 * @cfg {Number} minWidth default 300
27302 * @cfg {Number} minHeight default 300
27303 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27304 * @cfg {Boolean} isDocument (true|false) default false
27305 * @cfg {String} url action url
27306 * @cfg {String} paramName default 'imageUpload'
27307 * @cfg {String} method default POST
27308 * @cfg {Boolean} loadMask (true|false) default true
27309 * @cfg {Boolean} loadingText default 'Loading...'
27312 * Create a new UploadCropbox
27313 * @param {Object} config The config object
27316 Roo.bootstrap.UploadCropbox = function(config){
27317 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27321 * @event beforeselectfile
27322 * Fire before select file
27323 * @param {Roo.bootstrap.UploadCropbox} this
27325 "beforeselectfile" : true,
27328 * Fire after initEvent
27329 * @param {Roo.bootstrap.UploadCropbox} this
27334 * Fire after initEvent
27335 * @param {Roo.bootstrap.UploadCropbox} this
27336 * @param {String} data
27341 * Fire when preparing the file data
27342 * @param {Roo.bootstrap.UploadCropbox} this
27343 * @param {Object} file
27348 * Fire when get exception
27349 * @param {Roo.bootstrap.UploadCropbox} this
27350 * @param {XMLHttpRequest} xhr
27352 "exception" : true,
27354 * @event beforeloadcanvas
27355 * Fire before load the canvas
27356 * @param {Roo.bootstrap.UploadCropbox} this
27357 * @param {String} src
27359 "beforeloadcanvas" : true,
27362 * Fire when trash image
27363 * @param {Roo.bootstrap.UploadCropbox} this
27368 * Fire when download the image
27369 * @param {Roo.bootstrap.UploadCropbox} this
27373 * @event footerbuttonclick
27374 * Fire when footerbuttonclick
27375 * @param {Roo.bootstrap.UploadCropbox} this
27376 * @param {String} type
27378 "footerbuttonclick" : true,
27382 * @param {Roo.bootstrap.UploadCropbox} this
27387 * Fire when rotate the image
27388 * @param {Roo.bootstrap.UploadCropbox} this
27389 * @param {String} pos
27394 * Fire when inspect the file
27395 * @param {Roo.bootstrap.UploadCropbox} this
27396 * @param {Object} file
27401 * Fire when xhr upload the file
27402 * @param {Roo.bootstrap.UploadCropbox} this
27403 * @param {Object} data
27408 * Fire when arrange the file data
27409 * @param {Roo.bootstrap.UploadCropbox} this
27410 * @param {Object} formData
27415 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27418 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27420 emptyText : 'Click to upload image',
27421 rotateNotify : 'Image is too small to rotate',
27422 errorTimeout : 3000,
27436 cropType : 'image/jpeg',
27438 canvasLoaded : false,
27439 isDocument : false,
27441 paramName : 'imageUpload',
27443 loadingText : 'Loading...',
27446 getAutoCreate : function()
27450 cls : 'roo-upload-cropbox',
27454 cls : 'roo-upload-cropbox-selector',
27459 cls : 'roo-upload-cropbox-body',
27460 style : 'cursor:pointer',
27464 cls : 'roo-upload-cropbox-preview'
27468 cls : 'roo-upload-cropbox-thumb'
27472 cls : 'roo-upload-cropbox-empty-notify',
27473 html : this.emptyText
27477 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27478 html : this.rotateNotify
27484 cls : 'roo-upload-cropbox-footer',
27487 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27497 onRender : function(ct, position)
27499 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27501 if (this.buttons.length) {
27503 Roo.each(this.buttons, function(bb) {
27505 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27507 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27513 this.maskEl = this.el;
27517 initEvents : function()
27519 this.urlAPI = (window.createObjectURL && window) ||
27520 (window.URL && URL.revokeObjectURL && URL) ||
27521 (window.webkitURL && webkitURL);
27523 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27524 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27526 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27527 this.selectorEl.hide();
27529 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27530 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27532 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27533 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27534 this.thumbEl.hide();
27536 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27537 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27539 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27540 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27541 this.errorEl.hide();
27543 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27544 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27545 this.footerEl.hide();
27547 this.setThumbBoxSize();
27553 this.fireEvent('initial', this);
27560 window.addEventListener("resize", function() { _this.resize(); } );
27562 this.bodyEl.on('click', this.beforeSelectFile, this);
27565 this.bodyEl.on('touchstart', this.onTouchStart, this);
27566 this.bodyEl.on('touchmove', this.onTouchMove, this);
27567 this.bodyEl.on('touchend', this.onTouchEnd, this);
27571 this.bodyEl.on('mousedown', this.onMouseDown, this);
27572 this.bodyEl.on('mousemove', this.onMouseMove, this);
27573 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27574 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27575 Roo.get(document).on('mouseup', this.onMouseUp, this);
27578 this.selectorEl.on('change', this.onFileSelected, this);
27584 this.baseScale = 1;
27586 this.baseRotate = 1;
27587 this.dragable = false;
27588 this.pinching = false;
27591 this.cropData = false;
27592 this.notifyEl.dom.innerHTML = this.emptyText;
27594 this.selectorEl.dom.value = '';
27598 resize : function()
27600 if(this.fireEvent('resize', this) != false){
27601 this.setThumbBoxPosition();
27602 this.setCanvasPosition();
27606 onFooterButtonClick : function(e, el, o, type)
27609 case 'rotate-left' :
27610 this.onRotateLeft(e);
27612 case 'rotate-right' :
27613 this.onRotateRight(e);
27616 this.beforeSelectFile(e);
27631 this.fireEvent('footerbuttonclick', this, type);
27634 beforeSelectFile : function(e)
27636 e.preventDefault();
27638 if(this.fireEvent('beforeselectfile', this) != false){
27639 this.selectorEl.dom.click();
27643 onFileSelected : function(e)
27645 e.preventDefault();
27647 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27651 var file = this.selectorEl.dom.files[0];
27653 if(this.fireEvent('inspect', this, file) != false){
27654 this.prepare(file);
27659 trash : function(e)
27661 this.fireEvent('trash', this);
27664 download : function(e)
27666 this.fireEvent('download', this);
27669 loadCanvas : function(src)
27671 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27675 this.imageEl = document.createElement('img');
27679 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27681 this.imageEl.src = src;
27685 onLoadCanvas : function()
27687 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27688 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27690 this.bodyEl.un('click', this.beforeSelectFile, this);
27692 this.notifyEl.hide();
27693 this.thumbEl.show();
27694 this.footerEl.show();
27696 this.baseRotateLevel();
27698 if(this.isDocument){
27699 this.setThumbBoxSize();
27702 this.setThumbBoxPosition();
27704 this.baseScaleLevel();
27710 this.canvasLoaded = true;
27713 this.maskEl.unmask();
27718 setCanvasPosition : function()
27720 if(!this.canvasEl){
27724 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27725 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27727 this.previewEl.setLeft(pw);
27728 this.previewEl.setTop(ph);
27732 onMouseDown : function(e)
27736 this.dragable = true;
27737 this.pinching = false;
27739 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27740 this.dragable = false;
27744 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27745 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27749 onMouseMove : function(e)
27753 if(!this.canvasLoaded){
27757 if (!this.dragable){
27761 var minX = Math.ceil(this.thumbEl.getLeft(true));
27762 var minY = Math.ceil(this.thumbEl.getTop(true));
27764 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27765 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27767 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27768 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27770 x = x - this.mouseX;
27771 y = y - this.mouseY;
27773 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27774 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27776 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27777 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27779 this.previewEl.setLeft(bgX);
27780 this.previewEl.setTop(bgY);
27782 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27783 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27786 onMouseUp : function(e)
27790 this.dragable = false;
27793 onMouseWheel : function(e)
27797 this.startScale = this.scale;
27799 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27801 if(!this.zoomable()){
27802 this.scale = this.startScale;
27811 zoomable : function()
27813 var minScale = this.thumbEl.getWidth() / this.minWidth;
27815 if(this.minWidth < this.minHeight){
27816 minScale = this.thumbEl.getHeight() / this.minHeight;
27819 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27820 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27824 (this.rotate == 0 || this.rotate == 180) &&
27826 width > this.imageEl.OriginWidth ||
27827 height > this.imageEl.OriginHeight ||
27828 (width < this.minWidth && height < this.minHeight)
27836 (this.rotate == 90 || this.rotate == 270) &&
27838 width > this.imageEl.OriginWidth ||
27839 height > this.imageEl.OriginHeight ||
27840 (width < this.minHeight && height < this.minWidth)
27847 !this.isDocument &&
27848 (this.rotate == 0 || this.rotate == 180) &&
27850 width < this.minWidth ||
27851 width > this.imageEl.OriginWidth ||
27852 height < this.minHeight ||
27853 height > this.imageEl.OriginHeight
27860 !this.isDocument &&
27861 (this.rotate == 90 || this.rotate == 270) &&
27863 width < this.minHeight ||
27864 width > this.imageEl.OriginWidth ||
27865 height < this.minWidth ||
27866 height > this.imageEl.OriginHeight
27876 onRotateLeft : function(e)
27878 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27880 var minScale = this.thumbEl.getWidth() / this.minWidth;
27882 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27883 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27885 this.startScale = this.scale;
27887 while (this.getScaleLevel() < minScale){
27889 this.scale = this.scale + 1;
27891 if(!this.zoomable()){
27896 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27897 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27902 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27909 this.scale = this.startScale;
27911 this.onRotateFail();
27916 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27918 if(this.isDocument){
27919 this.setThumbBoxSize();
27920 this.setThumbBoxPosition();
27921 this.setCanvasPosition();
27926 this.fireEvent('rotate', this, 'left');
27930 onRotateRight : function(e)
27932 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27934 var minScale = this.thumbEl.getWidth() / this.minWidth;
27936 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27937 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27939 this.startScale = this.scale;
27941 while (this.getScaleLevel() < minScale){
27943 this.scale = this.scale + 1;
27945 if(!this.zoomable()){
27950 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27951 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27956 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27963 this.scale = this.startScale;
27965 this.onRotateFail();
27970 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27972 if(this.isDocument){
27973 this.setThumbBoxSize();
27974 this.setThumbBoxPosition();
27975 this.setCanvasPosition();
27980 this.fireEvent('rotate', this, 'right');
27983 onRotateFail : function()
27985 this.errorEl.show(true);
27989 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
27994 this.previewEl.dom.innerHTML = '';
27996 var canvasEl = document.createElement("canvas");
27998 var contextEl = canvasEl.getContext("2d");
28000 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28001 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28002 var center = this.imageEl.OriginWidth / 2;
28004 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28005 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28006 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28007 center = this.imageEl.OriginHeight / 2;
28010 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28012 contextEl.translate(center, center);
28013 contextEl.rotate(this.rotate * Math.PI / 180);
28015 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28017 this.canvasEl = document.createElement("canvas");
28019 this.contextEl = this.canvasEl.getContext("2d");
28021 switch (this.rotate) {
28024 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28025 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28027 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28032 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28033 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28035 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28036 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);
28040 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28045 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28046 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28048 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28049 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);
28053 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);
28058 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28059 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28061 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28062 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28066 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);
28073 this.previewEl.appendChild(this.canvasEl);
28075 this.setCanvasPosition();
28080 if(!this.canvasLoaded){
28084 var imageCanvas = document.createElement("canvas");
28086 var imageContext = imageCanvas.getContext("2d");
28088 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28089 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28091 var center = imageCanvas.width / 2;
28093 imageContext.translate(center, center);
28095 imageContext.rotate(this.rotate * Math.PI / 180);
28097 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28099 var canvas = document.createElement("canvas");
28101 var context = canvas.getContext("2d");
28103 canvas.width = this.minWidth;
28104 canvas.height = this.minHeight;
28106 switch (this.rotate) {
28109 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28110 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28112 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28113 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28115 var targetWidth = this.minWidth - 2 * x;
28116 var targetHeight = this.minHeight - 2 * y;
28120 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28121 scale = targetWidth / width;
28124 if(x > 0 && y == 0){
28125 scale = targetHeight / height;
28128 if(x > 0 && y > 0){
28129 scale = targetWidth / width;
28131 if(width < height){
28132 scale = targetHeight / height;
28136 context.scale(scale, scale);
28138 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28139 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28141 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28142 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28144 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28149 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28150 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28152 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28153 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28155 var targetWidth = this.minWidth - 2 * x;
28156 var targetHeight = this.minHeight - 2 * y;
28160 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28161 scale = targetWidth / width;
28164 if(x > 0 && y == 0){
28165 scale = targetHeight / height;
28168 if(x > 0 && y > 0){
28169 scale = targetWidth / width;
28171 if(width < height){
28172 scale = targetHeight / height;
28176 context.scale(scale, scale);
28178 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28179 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28181 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28182 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28184 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28186 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28191 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28192 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28194 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28195 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28197 var targetWidth = this.minWidth - 2 * x;
28198 var targetHeight = this.minHeight - 2 * y;
28202 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28203 scale = targetWidth / width;
28206 if(x > 0 && y == 0){
28207 scale = targetHeight / height;
28210 if(x > 0 && y > 0){
28211 scale = targetWidth / width;
28213 if(width < height){
28214 scale = targetHeight / height;
28218 context.scale(scale, scale);
28220 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28221 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28223 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28224 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28226 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28227 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28229 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28234 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28235 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28237 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28238 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28240 var targetWidth = this.minWidth - 2 * x;
28241 var targetHeight = this.minHeight - 2 * y;
28245 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28246 scale = targetWidth / width;
28249 if(x > 0 && y == 0){
28250 scale = targetHeight / height;
28253 if(x > 0 && y > 0){
28254 scale = targetWidth / width;
28256 if(width < height){
28257 scale = targetHeight / height;
28261 context.scale(scale, scale);
28263 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28264 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28266 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28267 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28269 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28271 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28278 this.cropData = canvas.toDataURL(this.cropType);
28280 if(this.fireEvent('crop', this, this.cropData) !== false){
28281 this.process(this.file, this.cropData);
28288 setThumbBoxSize : function()
28292 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28293 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28294 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28296 this.minWidth = width;
28297 this.minHeight = height;
28299 if(this.rotate == 90 || this.rotate == 270){
28300 this.minWidth = height;
28301 this.minHeight = width;
28306 width = Math.ceil(this.minWidth * height / this.minHeight);
28308 if(this.minWidth > this.minHeight){
28310 height = Math.ceil(this.minHeight * width / this.minWidth);
28313 this.thumbEl.setStyle({
28314 width : width + 'px',
28315 height : height + 'px'
28322 setThumbBoxPosition : function()
28324 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28325 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28327 this.thumbEl.setLeft(x);
28328 this.thumbEl.setTop(y);
28332 baseRotateLevel : function()
28334 this.baseRotate = 1;
28337 typeof(this.exif) != 'undefined' &&
28338 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28339 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28341 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28344 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28348 baseScaleLevel : function()
28352 if(this.isDocument){
28354 if(this.baseRotate == 6 || this.baseRotate == 8){
28356 height = this.thumbEl.getHeight();
28357 this.baseScale = height / this.imageEl.OriginWidth;
28359 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28360 width = this.thumbEl.getWidth();
28361 this.baseScale = width / this.imageEl.OriginHeight;
28367 height = this.thumbEl.getHeight();
28368 this.baseScale = height / this.imageEl.OriginHeight;
28370 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28371 width = this.thumbEl.getWidth();
28372 this.baseScale = width / this.imageEl.OriginWidth;
28378 if(this.baseRotate == 6 || this.baseRotate == 8){
28380 width = this.thumbEl.getHeight();
28381 this.baseScale = width / this.imageEl.OriginHeight;
28383 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28384 height = this.thumbEl.getWidth();
28385 this.baseScale = height / this.imageEl.OriginHeight;
28388 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28389 height = this.thumbEl.getWidth();
28390 this.baseScale = height / this.imageEl.OriginHeight;
28392 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28393 width = this.thumbEl.getHeight();
28394 this.baseScale = width / this.imageEl.OriginWidth;
28401 width = this.thumbEl.getWidth();
28402 this.baseScale = width / this.imageEl.OriginWidth;
28404 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28405 height = this.thumbEl.getHeight();
28406 this.baseScale = height / this.imageEl.OriginHeight;
28409 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28411 height = this.thumbEl.getHeight();
28412 this.baseScale = height / this.imageEl.OriginHeight;
28414 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28415 width = this.thumbEl.getWidth();
28416 this.baseScale = width / this.imageEl.OriginWidth;
28424 getScaleLevel : function()
28426 return this.baseScale * Math.pow(1.1, this.scale);
28429 onTouchStart : function(e)
28431 if(!this.canvasLoaded){
28432 this.beforeSelectFile(e);
28436 var touches = e.browserEvent.touches;
28442 if(touches.length == 1){
28443 this.onMouseDown(e);
28447 if(touches.length != 2){
28453 for(var i = 0, finger; finger = touches[i]; i++){
28454 coords.push(finger.pageX, finger.pageY);
28457 var x = Math.pow(coords[0] - coords[2], 2);
28458 var y = Math.pow(coords[1] - coords[3], 2);
28460 this.startDistance = Math.sqrt(x + y);
28462 this.startScale = this.scale;
28464 this.pinching = true;
28465 this.dragable = false;
28469 onTouchMove : function(e)
28471 if(!this.pinching && !this.dragable){
28475 var touches = e.browserEvent.touches;
28482 this.onMouseMove(e);
28488 for(var i = 0, finger; finger = touches[i]; i++){
28489 coords.push(finger.pageX, finger.pageY);
28492 var x = Math.pow(coords[0] - coords[2], 2);
28493 var y = Math.pow(coords[1] - coords[3], 2);
28495 this.endDistance = Math.sqrt(x + y);
28497 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28499 if(!this.zoomable()){
28500 this.scale = this.startScale;
28508 onTouchEnd : function(e)
28510 this.pinching = false;
28511 this.dragable = false;
28515 process : function(file, crop)
28518 this.maskEl.mask(this.loadingText);
28521 this.xhr = new XMLHttpRequest();
28523 file.xhr = this.xhr;
28525 this.xhr.open(this.method, this.url, true);
28528 "Accept": "application/json",
28529 "Cache-Control": "no-cache",
28530 "X-Requested-With": "XMLHttpRequest"
28533 for (var headerName in headers) {
28534 var headerValue = headers[headerName];
28536 this.xhr.setRequestHeader(headerName, headerValue);
28542 this.xhr.onload = function()
28544 _this.xhrOnLoad(_this.xhr);
28547 this.xhr.onerror = function()
28549 _this.xhrOnError(_this.xhr);
28552 var formData = new FormData();
28554 formData.append('returnHTML', 'NO');
28557 formData.append('crop', crop);
28560 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28561 formData.append(this.paramName, file, file.name);
28564 if(typeof(file.filename) != 'undefined'){
28565 formData.append('filename', file.filename);
28568 if(typeof(file.mimetype) != 'undefined'){
28569 formData.append('mimetype', file.mimetype);
28572 if(this.fireEvent('arrange', this, formData) != false){
28573 this.xhr.send(formData);
28577 xhrOnLoad : function(xhr)
28580 this.maskEl.unmask();
28583 if (xhr.readyState !== 4) {
28584 this.fireEvent('exception', this, xhr);
28588 var response = Roo.decode(xhr.responseText);
28590 if(!response.success){
28591 this.fireEvent('exception', this, xhr);
28595 var response = Roo.decode(xhr.responseText);
28597 this.fireEvent('upload', this, response);
28601 xhrOnError : function()
28604 this.maskEl.unmask();
28607 Roo.log('xhr on error');
28609 var response = Roo.decode(xhr.responseText);
28615 prepare : function(file)
28618 this.maskEl.mask(this.loadingText);
28624 if(typeof(file) === 'string'){
28625 this.loadCanvas(file);
28629 if(!file || !this.urlAPI){
28634 this.cropType = file.type;
28638 if(this.fireEvent('prepare', this, this.file) != false){
28640 var reader = new FileReader();
28642 reader.onload = function (e) {
28643 if (e.target.error) {
28644 Roo.log(e.target.error);
28648 var buffer = e.target.result,
28649 dataView = new DataView(buffer),
28651 maxOffset = dataView.byteLength - 4,
28655 if (dataView.getUint16(0) === 0xffd8) {
28656 while (offset < maxOffset) {
28657 markerBytes = dataView.getUint16(offset);
28659 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28660 markerLength = dataView.getUint16(offset + 2) + 2;
28661 if (offset + markerLength > dataView.byteLength) {
28662 Roo.log('Invalid meta data: Invalid segment size.');
28666 if(markerBytes == 0xffe1){
28667 _this.parseExifData(
28674 offset += markerLength;
28684 var url = _this.urlAPI.createObjectURL(_this.file);
28686 _this.loadCanvas(url);
28691 reader.readAsArrayBuffer(this.file);
28697 parseExifData : function(dataView, offset, length)
28699 var tiffOffset = offset + 10,
28703 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28704 // No Exif data, might be XMP data instead
28708 // Check for the ASCII code for "Exif" (0x45786966):
28709 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28710 // No Exif data, might be XMP data instead
28713 if (tiffOffset + 8 > dataView.byteLength) {
28714 Roo.log('Invalid Exif data: Invalid segment size.');
28717 // Check for the two null bytes:
28718 if (dataView.getUint16(offset + 8) !== 0x0000) {
28719 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28722 // Check the byte alignment:
28723 switch (dataView.getUint16(tiffOffset)) {
28725 littleEndian = true;
28728 littleEndian = false;
28731 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28734 // Check for the TIFF tag marker (0x002A):
28735 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28736 Roo.log('Invalid Exif data: Missing TIFF marker.');
28739 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28740 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28742 this.parseExifTags(
28745 tiffOffset + dirOffset,
28750 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28755 if (dirOffset + 6 > dataView.byteLength) {
28756 Roo.log('Invalid Exif data: Invalid directory offset.');
28759 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28760 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28761 if (dirEndOffset + 4 > dataView.byteLength) {
28762 Roo.log('Invalid Exif data: Invalid directory size.');
28765 for (i = 0; i < tagsNumber; i += 1) {
28769 dirOffset + 2 + 12 * i, // tag offset
28773 // Return the offset to the next directory:
28774 return dataView.getUint32(dirEndOffset, littleEndian);
28777 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28779 var tag = dataView.getUint16(offset, littleEndian);
28781 this.exif[tag] = this.getExifValue(
28785 dataView.getUint16(offset + 2, littleEndian), // tag type
28786 dataView.getUint32(offset + 4, littleEndian), // tag length
28791 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28793 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28802 Roo.log('Invalid Exif data: Invalid tag type.');
28806 tagSize = tagType.size * length;
28807 // Determine if the value is contained in the dataOffset bytes,
28808 // or if the value at the dataOffset is a pointer to the actual data:
28809 dataOffset = tagSize > 4 ?
28810 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28811 if (dataOffset + tagSize > dataView.byteLength) {
28812 Roo.log('Invalid Exif data: Invalid data offset.');
28815 if (length === 1) {
28816 return tagType.getValue(dataView, dataOffset, littleEndian);
28819 for (i = 0; i < length; i += 1) {
28820 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28823 if (tagType.ascii) {
28825 // Concatenate the chars:
28826 for (i = 0; i < values.length; i += 1) {
28828 // Ignore the terminating NULL byte(s):
28829 if (c === '\u0000') {
28841 Roo.apply(Roo.bootstrap.UploadCropbox, {
28843 'Orientation': 0x0112
28847 1: 0, //'top-left',
28849 3: 180, //'bottom-right',
28850 // 4: 'bottom-left',
28852 6: 90, //'right-top',
28853 // 7: 'right-bottom',
28854 8: 270 //'left-bottom'
28858 // byte, 8-bit unsigned int:
28860 getValue: function (dataView, dataOffset) {
28861 return dataView.getUint8(dataOffset);
28865 // ascii, 8-bit byte:
28867 getValue: function (dataView, dataOffset) {
28868 return String.fromCharCode(dataView.getUint8(dataOffset));
28873 // short, 16 bit int:
28875 getValue: function (dataView, dataOffset, littleEndian) {
28876 return dataView.getUint16(dataOffset, littleEndian);
28880 // long, 32 bit int:
28882 getValue: function (dataView, dataOffset, littleEndian) {
28883 return dataView.getUint32(dataOffset, littleEndian);
28887 // rational = two long values, first is numerator, second is denominator:
28889 getValue: function (dataView, dataOffset, littleEndian) {
28890 return dataView.getUint32(dataOffset, littleEndian) /
28891 dataView.getUint32(dataOffset + 4, littleEndian);
28895 // slong, 32 bit signed int:
28897 getValue: function (dataView, dataOffset, littleEndian) {
28898 return dataView.getInt32(dataOffset, littleEndian);
28902 // srational, two slongs, first is numerator, second is denominator:
28904 getValue: function (dataView, dataOffset, littleEndian) {
28905 return dataView.getInt32(dataOffset, littleEndian) /
28906 dataView.getInt32(dataOffset + 4, littleEndian);
28916 cls : 'btn-group roo-upload-cropbox-rotate-left',
28917 action : 'rotate-left',
28921 cls : 'btn btn-default',
28922 html : '<i class="fa fa-undo"></i>'
28928 cls : 'btn-group roo-upload-cropbox-picture',
28929 action : 'picture',
28933 cls : 'btn btn-default',
28934 html : '<i class="fa fa-picture-o"></i>'
28940 cls : 'btn-group roo-upload-cropbox-rotate-right',
28941 action : 'rotate-right',
28945 cls : 'btn btn-default',
28946 html : '<i class="fa fa-repeat"></i>'
28954 cls : 'btn-group roo-upload-cropbox-rotate-left',
28955 action : 'rotate-left',
28959 cls : 'btn btn-default',
28960 html : '<i class="fa fa-undo"></i>'
28966 cls : 'btn-group roo-upload-cropbox-download',
28967 action : 'download',
28971 cls : 'btn btn-default',
28972 html : '<i class="fa fa-download"></i>'
28978 cls : 'btn-group roo-upload-cropbox-crop',
28983 cls : 'btn btn-default',
28984 html : '<i class="fa fa-crop"></i>'
28990 cls : 'btn-group roo-upload-cropbox-trash',
28995 cls : 'btn btn-default',
28996 html : '<i class="fa fa-trash"></i>'
29002 cls : 'btn-group roo-upload-cropbox-rotate-right',
29003 action : 'rotate-right',
29007 cls : 'btn btn-default',
29008 html : '<i class="fa fa-repeat"></i>'
29016 cls : 'btn-group roo-upload-cropbox-rotate-left',
29017 action : 'rotate-left',
29021 cls : 'btn btn-default',
29022 html : '<i class="fa fa-undo"></i>'
29028 cls : 'btn-group roo-upload-cropbox-rotate-right',
29029 action : 'rotate-right',
29033 cls : 'btn btn-default',
29034 html : '<i class="fa fa-repeat"></i>'
29047 * @class Roo.bootstrap.DocumentManager
29048 * @extends Roo.bootstrap.Component
29049 * Bootstrap DocumentManager class
29050 * @cfg {String} paramName default 'imageUpload'
29051 * @cfg {String} toolTipName default 'filename'
29052 * @cfg {String} method default POST
29053 * @cfg {String} url action url
29054 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29055 * @cfg {Boolean} multiple multiple upload default true
29056 * @cfg {Number} thumbSize default 300
29057 * @cfg {String} fieldLabel
29058 * @cfg {Number} labelWidth default 4
29059 * @cfg {String} labelAlign (left|top) default left
29060 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29061 * @cfg {Number} labellg set the width of label (1-12)
29062 * @cfg {Number} labelmd set the width of label (1-12)
29063 * @cfg {Number} labelsm set the width of label (1-12)
29064 * @cfg {Number} labelxs set the width of label (1-12)
29067 * Create a new DocumentManager
29068 * @param {Object} config The config object
29071 Roo.bootstrap.DocumentManager = function(config){
29072 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29075 this.delegates = [];
29080 * Fire when initial the DocumentManager
29081 * @param {Roo.bootstrap.DocumentManager} this
29086 * inspect selected file
29087 * @param {Roo.bootstrap.DocumentManager} this
29088 * @param {File} file
29093 * Fire when xhr load exception
29094 * @param {Roo.bootstrap.DocumentManager} this
29095 * @param {XMLHttpRequest} xhr
29097 "exception" : true,
29099 * @event afterupload
29100 * Fire when xhr load exception
29101 * @param {Roo.bootstrap.DocumentManager} this
29102 * @param {XMLHttpRequest} xhr
29104 "afterupload" : true,
29107 * prepare the form data
29108 * @param {Roo.bootstrap.DocumentManager} this
29109 * @param {Object} formData
29114 * Fire when remove the file
29115 * @param {Roo.bootstrap.DocumentManager} this
29116 * @param {Object} file
29121 * Fire after refresh the file
29122 * @param {Roo.bootstrap.DocumentManager} this
29127 * Fire after click the image
29128 * @param {Roo.bootstrap.DocumentManager} this
29129 * @param {Object} file
29134 * Fire when upload a image and editable set to true
29135 * @param {Roo.bootstrap.DocumentManager} this
29136 * @param {Object} file
29140 * @event beforeselectfile
29141 * Fire before select file
29142 * @param {Roo.bootstrap.DocumentManager} this
29144 "beforeselectfile" : true,
29147 * Fire before process file
29148 * @param {Roo.bootstrap.DocumentManager} this
29149 * @param {Object} file
29153 * @event previewrendered
29154 * Fire when preview rendered
29155 * @param {Roo.bootstrap.DocumentManager} this
29156 * @param {Object} file
29158 "previewrendered" : true,
29161 "previewResize" : true
29166 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29175 paramName : 'imageUpload',
29176 toolTipName : 'filename',
29179 labelAlign : 'left',
29189 getAutoCreate : function()
29191 var managerWidget = {
29193 cls : 'roo-document-manager',
29197 cls : 'roo-document-manager-selector',
29202 cls : 'roo-document-manager-uploader',
29206 cls : 'roo-document-manager-upload-btn',
29207 html : '<i class="fa fa-plus"></i>'
29218 cls : 'column col-md-12',
29223 if(this.fieldLabel.length){
29228 cls : 'column col-md-12',
29229 html : this.fieldLabel
29233 cls : 'column col-md-12',
29238 if(this.labelAlign == 'left'){
29243 html : this.fieldLabel
29252 if(this.labelWidth > 12){
29253 content[0].style = "width: " + this.labelWidth + 'px';
29256 if(this.labelWidth < 13 && this.labelmd == 0){
29257 this.labelmd = this.labelWidth;
29260 if(this.labellg > 0){
29261 content[0].cls += ' col-lg-' + this.labellg;
29262 content[1].cls += ' col-lg-' + (12 - this.labellg);
29265 if(this.labelmd > 0){
29266 content[0].cls += ' col-md-' + this.labelmd;
29267 content[1].cls += ' col-md-' + (12 - this.labelmd);
29270 if(this.labelsm > 0){
29271 content[0].cls += ' col-sm-' + this.labelsm;
29272 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29275 if(this.labelxs > 0){
29276 content[0].cls += ' col-xs-' + this.labelxs;
29277 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29285 cls : 'row clearfix',
29293 initEvents : function()
29295 this.managerEl = this.el.select('.roo-document-manager', true).first();
29296 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29298 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29299 this.selectorEl.hide();
29302 this.selectorEl.attr('multiple', 'multiple');
29305 this.selectorEl.on('change', this.onFileSelected, this);
29307 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29308 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29310 this.uploader.on('click', this.onUploaderClick, this);
29312 this.renderProgressDialog();
29316 window.addEventListener("resize", function() { _this.refresh(); } );
29318 this.fireEvent('initial', this);
29321 renderProgressDialog : function()
29325 this.progressDialog = new Roo.bootstrap.Modal({
29326 cls : 'roo-document-manager-progress-dialog',
29327 allow_close : false,
29338 btnclick : function() {
29339 _this.uploadCancel();
29345 this.progressDialog.render(Roo.get(document.body));
29347 this.progress = new Roo.bootstrap.Progress({
29348 cls : 'roo-document-manager-progress',
29353 this.progress.render(this.progressDialog.getChildContainer());
29355 this.progressBar = new Roo.bootstrap.ProgressBar({
29356 cls : 'roo-document-manager-progress-bar',
29359 aria_valuemax : 12,
29363 this.progressBar.render(this.progress.getChildContainer());
29366 onUploaderClick : function(e)
29368 e.preventDefault();
29370 if(this.fireEvent('beforeselectfile', this) != false){
29371 this.selectorEl.dom.click();
29376 onFileSelected : function(e)
29378 e.preventDefault();
29380 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29384 Roo.each(this.selectorEl.dom.files, function(file){
29385 if(this.fireEvent('inspect', this, file) != false){
29386 this.files.push(file);
29396 this.selectorEl.dom.value = '';
29398 if(!this.files || !this.files.length){
29402 if(this.boxes > 0 && this.files.length > this.boxes){
29403 this.files = this.files.slice(0, this.boxes);
29406 this.uploader.show();
29408 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29409 this.uploader.hide();
29418 Roo.each(this.files, function(file){
29420 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29421 var f = this.renderPreview(file);
29426 if(file.type.indexOf('image') != -1){
29427 this.delegates.push(
29429 _this.process(file);
29430 }).createDelegate(this)
29438 _this.process(file);
29439 }).createDelegate(this)
29444 this.files = files;
29446 this.delegates = this.delegates.concat(docs);
29448 if(!this.delegates.length){
29453 this.progressBar.aria_valuemax = this.delegates.length;
29460 arrange : function()
29462 if(!this.delegates.length){
29463 this.progressDialog.hide();
29468 var delegate = this.delegates.shift();
29470 this.progressDialog.show();
29472 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29474 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29479 refresh : function()
29481 this.uploader.show();
29483 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29484 this.uploader.hide();
29487 Roo.isTouch ? this.closable(false) : this.closable(true);
29489 this.fireEvent('refresh', this);
29492 onRemove : function(e, el, o)
29494 e.preventDefault();
29496 this.fireEvent('remove', this, o);
29500 remove : function(o)
29504 Roo.each(this.files, function(file){
29505 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29514 this.files = files;
29521 Roo.each(this.files, function(file){
29526 file.target.remove();
29535 onClick : function(e, el, o)
29537 e.preventDefault();
29539 this.fireEvent('click', this, o);
29543 closable : function(closable)
29545 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29547 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29559 xhrOnLoad : function(xhr)
29561 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29565 if (xhr.readyState !== 4) {
29567 this.fireEvent('exception', this, xhr);
29571 var response = Roo.decode(xhr.responseText);
29573 if(!response.success){
29575 this.fireEvent('exception', this, xhr);
29579 var file = this.renderPreview(response.data);
29581 this.files.push(file);
29585 this.fireEvent('afterupload', this, xhr);
29589 xhrOnError : function(xhr)
29591 Roo.log('xhr on error');
29593 var response = Roo.decode(xhr.responseText);
29600 process : function(file)
29602 if(this.fireEvent('process', this, file) !== false){
29603 if(this.editable && file.type.indexOf('image') != -1){
29604 this.fireEvent('edit', this, file);
29608 this.uploadStart(file, false);
29615 uploadStart : function(file, crop)
29617 this.xhr = new XMLHttpRequest();
29619 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29624 file.xhr = this.xhr;
29626 this.managerEl.createChild({
29628 cls : 'roo-document-manager-loading',
29632 tooltip : file.name,
29633 cls : 'roo-document-manager-thumb',
29634 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29640 this.xhr.open(this.method, this.url, true);
29643 "Accept": "application/json",
29644 "Cache-Control": "no-cache",
29645 "X-Requested-With": "XMLHttpRequest"
29648 for (var headerName in headers) {
29649 var headerValue = headers[headerName];
29651 this.xhr.setRequestHeader(headerName, headerValue);
29657 this.xhr.onload = function()
29659 _this.xhrOnLoad(_this.xhr);
29662 this.xhr.onerror = function()
29664 _this.xhrOnError(_this.xhr);
29667 var formData = new FormData();
29669 formData.append('returnHTML', 'NO');
29672 formData.append('crop', crop);
29675 formData.append(this.paramName, file, file.name);
29682 if(this.fireEvent('prepare', this, formData, options) != false){
29684 if(options.manually){
29688 this.xhr.send(formData);
29692 this.uploadCancel();
29695 uploadCancel : function()
29701 this.delegates = [];
29703 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29710 renderPreview : function(file)
29712 if(typeof(file.target) != 'undefined' && file.target){
29716 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29718 var previewEl = this.managerEl.createChild({
29720 cls : 'roo-document-manager-preview',
29724 tooltip : file[this.toolTipName],
29725 cls : 'roo-document-manager-thumb',
29726 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29731 html : '<i class="fa fa-times-circle"></i>'
29736 var close = previewEl.select('button.close', true).first();
29738 close.on('click', this.onRemove, this, file);
29740 file.target = previewEl;
29742 var image = previewEl.select('img', true).first();
29746 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29748 image.on('click', this.onClick, this, file);
29750 this.fireEvent('previewrendered', this, file);
29756 onPreviewLoad : function(file, image)
29758 if(typeof(file.target) == 'undefined' || !file.target){
29762 var width = image.dom.naturalWidth || image.dom.width;
29763 var height = image.dom.naturalHeight || image.dom.height;
29765 if(!this.previewResize) {
29769 if(width > height){
29770 file.target.addClass('wide');
29774 file.target.addClass('tall');
29779 uploadFromSource : function(file, crop)
29781 this.xhr = new XMLHttpRequest();
29783 this.managerEl.createChild({
29785 cls : 'roo-document-manager-loading',
29789 tooltip : file.name,
29790 cls : 'roo-document-manager-thumb',
29791 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29797 this.xhr.open(this.method, this.url, true);
29800 "Accept": "application/json",
29801 "Cache-Control": "no-cache",
29802 "X-Requested-With": "XMLHttpRequest"
29805 for (var headerName in headers) {
29806 var headerValue = headers[headerName];
29808 this.xhr.setRequestHeader(headerName, headerValue);
29814 this.xhr.onload = function()
29816 _this.xhrOnLoad(_this.xhr);
29819 this.xhr.onerror = function()
29821 _this.xhrOnError(_this.xhr);
29824 var formData = new FormData();
29826 formData.append('returnHTML', 'NO');
29828 formData.append('crop', crop);
29830 if(typeof(file.filename) != 'undefined'){
29831 formData.append('filename', file.filename);
29834 if(typeof(file.mimetype) != 'undefined'){
29835 formData.append('mimetype', file.mimetype);
29840 if(this.fireEvent('prepare', this, formData) != false){
29841 this.xhr.send(formData);
29851 * @class Roo.bootstrap.DocumentViewer
29852 * @extends Roo.bootstrap.Component
29853 * Bootstrap DocumentViewer class
29854 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29855 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29858 * Create a new DocumentViewer
29859 * @param {Object} config The config object
29862 Roo.bootstrap.DocumentViewer = function(config){
29863 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29868 * Fire after initEvent
29869 * @param {Roo.bootstrap.DocumentViewer} this
29875 * @param {Roo.bootstrap.DocumentViewer} this
29880 * Fire after download button
29881 * @param {Roo.bootstrap.DocumentViewer} this
29886 * Fire after trash button
29887 * @param {Roo.bootstrap.DocumentViewer} this
29894 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29896 showDownload : true,
29900 getAutoCreate : function()
29904 cls : 'roo-document-viewer',
29908 cls : 'roo-document-viewer-body',
29912 cls : 'roo-document-viewer-thumb',
29916 cls : 'roo-document-viewer-image'
29924 cls : 'roo-document-viewer-footer',
29927 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29931 cls : 'btn-group roo-document-viewer-download',
29935 cls : 'btn btn-default',
29936 html : '<i class="fa fa-download"></i>'
29942 cls : 'btn-group roo-document-viewer-trash',
29946 cls : 'btn btn-default',
29947 html : '<i class="fa fa-trash"></i>'
29960 initEvents : function()
29962 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29963 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29965 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29966 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
29968 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
29969 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
29971 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
29972 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
29974 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
29975 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
29977 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
29978 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
29980 this.bodyEl.on('click', this.onClick, this);
29981 this.downloadBtn.on('click', this.onDownload, this);
29982 this.trashBtn.on('click', this.onTrash, this);
29984 this.downloadBtn.hide();
29985 this.trashBtn.hide();
29987 if(this.showDownload){
29988 this.downloadBtn.show();
29991 if(this.showTrash){
29992 this.trashBtn.show();
29995 if(!this.showDownload && !this.showTrash) {
29996 this.footerEl.hide();
30001 initial : function()
30003 this.fireEvent('initial', this);
30007 onClick : function(e)
30009 e.preventDefault();
30011 this.fireEvent('click', this);
30014 onDownload : function(e)
30016 e.preventDefault();
30018 this.fireEvent('download', this);
30021 onTrash : function(e)
30023 e.preventDefault();
30025 this.fireEvent('trash', this);
30037 * @class Roo.bootstrap.NavProgressBar
30038 * @extends Roo.bootstrap.Component
30039 * Bootstrap NavProgressBar class
30042 * Create a new nav progress bar
30043 * @param {Object} config The config object
30046 Roo.bootstrap.NavProgressBar = function(config){
30047 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30049 this.bullets = this.bullets || [];
30051 // Roo.bootstrap.NavProgressBar.register(this);
30055 * Fires when the active item changes
30056 * @param {Roo.bootstrap.NavProgressBar} this
30057 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30058 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30065 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30070 getAutoCreate : function()
30072 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30076 cls : 'roo-navigation-bar-group',
30080 cls : 'roo-navigation-top-bar'
30084 cls : 'roo-navigation-bullets-bar',
30088 cls : 'roo-navigation-bar'
30095 cls : 'roo-navigation-bottom-bar'
30105 initEvents: function()
30110 onRender : function(ct, position)
30112 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30114 if(this.bullets.length){
30115 Roo.each(this.bullets, function(b){
30124 addItem : function(cfg)
30126 var item = new Roo.bootstrap.NavProgressItem(cfg);
30128 item.parentId = this.id;
30129 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30132 var top = new Roo.bootstrap.Element({
30134 cls : 'roo-navigation-bar-text'
30137 var bottom = new Roo.bootstrap.Element({
30139 cls : 'roo-navigation-bar-text'
30142 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30143 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30145 var topText = new Roo.bootstrap.Element({
30147 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30150 var bottomText = new Roo.bootstrap.Element({
30152 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30155 topText.onRender(top.el, null);
30156 bottomText.onRender(bottom.el, null);
30159 item.bottomEl = bottom;
30162 this.barItems.push(item);
30167 getActive : function()
30169 var active = false;
30171 Roo.each(this.barItems, function(v){
30173 if (!v.isActive()) {
30185 setActiveItem : function(item)
30189 Roo.each(this.barItems, function(v){
30190 if (v.rid == item.rid) {
30194 if (v.isActive()) {
30195 v.setActive(false);
30200 item.setActive(true);
30202 this.fireEvent('changed', this, item, prev);
30205 getBarItem: function(rid)
30209 Roo.each(this.barItems, function(e) {
30210 if (e.rid != rid) {
30221 indexOfItem : function(item)
30225 Roo.each(this.barItems, function(v, i){
30227 if (v.rid != item.rid) {
30238 setActiveNext : function()
30240 var i = this.indexOfItem(this.getActive());
30242 if (i > this.barItems.length) {
30246 this.setActiveItem(this.barItems[i+1]);
30249 setActivePrev : function()
30251 var i = this.indexOfItem(this.getActive());
30257 this.setActiveItem(this.barItems[i-1]);
30260 format : function()
30262 if(!this.barItems.length){
30266 var width = 100 / this.barItems.length;
30268 Roo.each(this.barItems, function(i){
30269 i.el.setStyle('width', width + '%');
30270 i.topEl.el.setStyle('width', width + '%');
30271 i.bottomEl.el.setStyle('width', width + '%');
30280 * Nav Progress Item
30285 * @class Roo.bootstrap.NavProgressItem
30286 * @extends Roo.bootstrap.Component
30287 * Bootstrap NavProgressItem class
30288 * @cfg {String} rid the reference id
30289 * @cfg {Boolean} active (true|false) Is item active default false
30290 * @cfg {Boolean} disabled (true|false) Is item active default false
30291 * @cfg {String} html
30292 * @cfg {String} position (top|bottom) text position default bottom
30293 * @cfg {String} icon show icon instead of number
30296 * Create a new NavProgressItem
30297 * @param {Object} config The config object
30299 Roo.bootstrap.NavProgressItem = function(config){
30300 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30305 * The raw click event for the entire grid.
30306 * @param {Roo.bootstrap.NavProgressItem} this
30307 * @param {Roo.EventObject} e
30314 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30320 position : 'bottom',
30323 getAutoCreate : function()
30325 var iconCls = 'roo-navigation-bar-item-icon';
30327 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30331 cls: 'roo-navigation-bar-item',
30341 cfg.cls += ' active';
30344 cfg.cls += ' disabled';
30350 disable : function()
30352 this.setDisabled(true);
30355 enable : function()
30357 this.setDisabled(false);
30360 initEvents: function()
30362 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30364 this.iconEl.on('click', this.onClick, this);
30367 onClick : function(e)
30369 e.preventDefault();
30375 if(this.fireEvent('click', this, e) === false){
30379 this.parent().setActiveItem(this);
30382 isActive: function ()
30384 return this.active;
30387 setActive : function(state)
30389 if(this.active == state){
30393 this.active = state;
30396 this.el.addClass('active');
30400 this.el.removeClass('active');
30405 setDisabled : function(state)
30407 if(this.disabled == state){
30411 this.disabled = state;
30414 this.el.addClass('disabled');
30418 this.el.removeClass('disabled');
30421 tooltipEl : function()
30423 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30436 * @class Roo.bootstrap.FieldLabel
30437 * @extends Roo.bootstrap.Component
30438 * Bootstrap FieldLabel class
30439 * @cfg {String} html contents of the element
30440 * @cfg {String} tag tag of the element default label
30441 * @cfg {String} cls class of the element
30442 * @cfg {String} target label target
30443 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30444 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30445 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30446 * @cfg {String} iconTooltip default "This field is required"
30447 * @cfg {String} indicatorpos (left|right) default left
30450 * Create a new FieldLabel
30451 * @param {Object} config The config object
30454 Roo.bootstrap.FieldLabel = function(config){
30455 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30460 * Fires after the field has been marked as invalid.
30461 * @param {Roo.form.FieldLabel} this
30462 * @param {String} msg The validation message
30467 * Fires after the field has been validated with no errors.
30468 * @param {Roo.form.FieldLabel} this
30474 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30481 invalidClass : 'has-warning',
30482 validClass : 'has-success',
30483 iconTooltip : 'This field is required',
30484 indicatorpos : 'left',
30486 getAutoCreate : function(){
30489 if (!this.allowBlank) {
30495 cls : 'roo-bootstrap-field-label ' + this.cls,
30500 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30501 tooltip : this.iconTooltip
30510 if(this.indicatorpos == 'right'){
30513 cls : 'roo-bootstrap-field-label ' + this.cls,
30522 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30523 tooltip : this.iconTooltip
30532 initEvents: function()
30534 Roo.bootstrap.Element.superclass.initEvents.call(this);
30536 this.indicator = this.indicatorEl();
30538 if(this.indicator){
30539 this.indicator.removeClass('visible');
30540 this.indicator.addClass('invisible');
30543 Roo.bootstrap.FieldLabel.register(this);
30546 indicatorEl : function()
30548 var indicator = this.el.select('i.roo-required-indicator',true).first();
30559 * Mark this field as valid
30561 markValid : function()
30563 if(this.indicator){
30564 this.indicator.removeClass('visible');
30565 this.indicator.addClass('invisible');
30567 if (Roo.bootstrap.version == 3) {
30568 this.el.removeClass(this.invalidClass);
30569 this.el.addClass(this.validClass);
30571 this.el.removeClass('is-invalid');
30572 this.el.addClass('is-valid');
30576 this.fireEvent('valid', this);
30580 * Mark this field as invalid
30581 * @param {String} msg The validation message
30583 markInvalid : function(msg)
30585 if(this.indicator){
30586 this.indicator.removeClass('invisible');
30587 this.indicator.addClass('visible');
30589 if (Roo.bootstrap.version == 3) {
30590 this.el.removeClass(this.validClass);
30591 this.el.addClass(this.invalidClass);
30593 this.el.removeClass('is-valid');
30594 this.el.addClass('is-invalid');
30598 this.fireEvent('invalid', this, msg);
30604 Roo.apply(Roo.bootstrap.FieldLabel, {
30609 * register a FieldLabel Group
30610 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30612 register : function(label)
30614 if(this.groups.hasOwnProperty(label.target)){
30618 this.groups[label.target] = label;
30622 * fetch a FieldLabel Group based on the target
30623 * @param {string} target
30624 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30626 get: function(target) {
30627 if (typeof(this.groups[target]) == 'undefined') {
30631 return this.groups[target] ;
30640 * page DateSplitField.
30646 * @class Roo.bootstrap.DateSplitField
30647 * @extends Roo.bootstrap.Component
30648 * Bootstrap DateSplitField class
30649 * @cfg {string} fieldLabel - the label associated
30650 * @cfg {Number} labelWidth set the width of label (0-12)
30651 * @cfg {String} labelAlign (top|left)
30652 * @cfg {Boolean} dayAllowBlank (true|false) default false
30653 * @cfg {Boolean} monthAllowBlank (true|false) default false
30654 * @cfg {Boolean} yearAllowBlank (true|false) default false
30655 * @cfg {string} dayPlaceholder
30656 * @cfg {string} monthPlaceholder
30657 * @cfg {string} yearPlaceholder
30658 * @cfg {string} dayFormat default 'd'
30659 * @cfg {string} monthFormat default 'm'
30660 * @cfg {string} yearFormat default 'Y'
30661 * @cfg {Number} labellg set the width of label (1-12)
30662 * @cfg {Number} labelmd set the width of label (1-12)
30663 * @cfg {Number} labelsm set the width of label (1-12)
30664 * @cfg {Number} labelxs set the width of label (1-12)
30668 * Create a new DateSplitField
30669 * @param {Object} config The config object
30672 Roo.bootstrap.DateSplitField = function(config){
30673 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30679 * getting the data of years
30680 * @param {Roo.bootstrap.DateSplitField} this
30681 * @param {Object} years
30686 * getting the data of days
30687 * @param {Roo.bootstrap.DateSplitField} this
30688 * @param {Object} days
30693 * Fires after the field has been marked as invalid.
30694 * @param {Roo.form.Field} this
30695 * @param {String} msg The validation message
30700 * Fires after the field has been validated with no errors.
30701 * @param {Roo.form.Field} this
30707 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30710 labelAlign : 'top',
30712 dayAllowBlank : false,
30713 monthAllowBlank : false,
30714 yearAllowBlank : false,
30715 dayPlaceholder : '',
30716 monthPlaceholder : '',
30717 yearPlaceholder : '',
30721 isFormField : true,
30727 getAutoCreate : function()
30731 cls : 'row roo-date-split-field-group',
30736 cls : 'form-hidden-field roo-date-split-field-group-value',
30742 var labelCls = 'col-md-12';
30743 var contentCls = 'col-md-4';
30745 if(this.fieldLabel){
30749 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30753 html : this.fieldLabel
30758 if(this.labelAlign == 'left'){
30760 if(this.labelWidth > 12){
30761 label.style = "width: " + this.labelWidth + 'px';
30764 if(this.labelWidth < 13 && this.labelmd == 0){
30765 this.labelmd = this.labelWidth;
30768 if(this.labellg > 0){
30769 labelCls = ' col-lg-' + this.labellg;
30770 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30773 if(this.labelmd > 0){
30774 labelCls = ' col-md-' + this.labelmd;
30775 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30778 if(this.labelsm > 0){
30779 labelCls = ' col-sm-' + this.labelsm;
30780 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30783 if(this.labelxs > 0){
30784 labelCls = ' col-xs-' + this.labelxs;
30785 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30789 label.cls += ' ' + labelCls;
30791 cfg.cn.push(label);
30794 Roo.each(['day', 'month', 'year'], function(t){
30797 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30804 inputEl: function ()
30806 return this.el.select('.roo-date-split-field-group-value', true).first();
30809 onRender : function(ct, position)
30813 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30815 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30817 this.dayField = new Roo.bootstrap.ComboBox({
30818 allowBlank : this.dayAllowBlank,
30819 alwaysQuery : true,
30820 displayField : 'value',
30823 forceSelection : true,
30825 placeholder : this.dayPlaceholder,
30826 selectOnFocus : true,
30827 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30828 triggerAction : 'all',
30830 valueField : 'value',
30831 store : new Roo.data.SimpleStore({
30832 data : (function() {
30834 _this.fireEvent('days', _this, days);
30837 fields : [ 'value' ]
30840 select : function (_self, record, index)
30842 _this.setValue(_this.getValue());
30847 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30849 this.monthField = new Roo.bootstrap.MonthField({
30850 after : '<i class=\"fa fa-calendar\"></i>',
30851 allowBlank : this.monthAllowBlank,
30852 placeholder : this.monthPlaceholder,
30855 render : function (_self)
30857 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30858 e.preventDefault();
30862 select : function (_self, oldvalue, newvalue)
30864 _this.setValue(_this.getValue());
30869 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30871 this.yearField = new Roo.bootstrap.ComboBox({
30872 allowBlank : this.yearAllowBlank,
30873 alwaysQuery : true,
30874 displayField : 'value',
30877 forceSelection : true,
30879 placeholder : this.yearPlaceholder,
30880 selectOnFocus : true,
30881 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30882 triggerAction : 'all',
30884 valueField : 'value',
30885 store : new Roo.data.SimpleStore({
30886 data : (function() {
30888 _this.fireEvent('years', _this, years);
30891 fields : [ 'value' ]
30894 select : function (_self, record, index)
30896 _this.setValue(_this.getValue());
30901 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30904 setValue : function(v, format)
30906 this.inputEl.dom.value = v;
30908 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30910 var d = Date.parseDate(v, f);
30917 this.setDay(d.format(this.dayFormat));
30918 this.setMonth(d.format(this.monthFormat));
30919 this.setYear(d.format(this.yearFormat));
30926 setDay : function(v)
30928 this.dayField.setValue(v);
30929 this.inputEl.dom.value = this.getValue();
30934 setMonth : function(v)
30936 this.monthField.setValue(v, true);
30937 this.inputEl.dom.value = this.getValue();
30942 setYear : function(v)
30944 this.yearField.setValue(v);
30945 this.inputEl.dom.value = this.getValue();
30950 getDay : function()
30952 return this.dayField.getValue();
30955 getMonth : function()
30957 return this.monthField.getValue();
30960 getYear : function()
30962 return this.yearField.getValue();
30965 getValue : function()
30967 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
30969 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
30979 this.inputEl.dom.value = '';
30984 validate : function()
30986 var d = this.dayField.validate();
30987 var m = this.monthField.validate();
30988 var y = this.yearField.validate();
30993 (!this.dayAllowBlank && !d) ||
30994 (!this.monthAllowBlank && !m) ||
30995 (!this.yearAllowBlank && !y)
31000 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31009 this.markInvalid();
31014 markValid : function()
31017 var label = this.el.select('label', true).first();
31018 var icon = this.el.select('i.fa-star', true).first();
31024 this.fireEvent('valid', this);
31028 * Mark this field as invalid
31029 * @param {String} msg The validation message
31031 markInvalid : function(msg)
31034 var label = this.el.select('label', true).first();
31035 var icon = this.el.select('i.fa-star', true).first();
31037 if(label && !icon){
31038 this.el.select('.roo-date-split-field-label', true).createChild({
31040 cls : 'text-danger fa fa-lg fa-star',
31041 tooltip : 'This field is required',
31042 style : 'margin-right:5px;'
31046 this.fireEvent('invalid', this, msg);
31049 clearInvalid : function()
31051 var label = this.el.select('label', true).first();
31052 var icon = this.el.select('i.fa-star', true).first();
31058 this.fireEvent('valid', this);
31061 getName: function()
31071 * http://masonry.desandro.com
31073 * The idea is to render all the bricks based on vertical width...
31075 * The original code extends 'outlayer' - we might need to use that....
31081 * @class Roo.bootstrap.LayoutMasonry
31082 * @extends Roo.bootstrap.Component
31083 * Bootstrap Layout Masonry class
31086 * Create a new Element
31087 * @param {Object} config The config object
31090 Roo.bootstrap.LayoutMasonry = function(config){
31092 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31096 Roo.bootstrap.LayoutMasonry.register(this);
31102 * Fire after layout the items
31103 * @param {Roo.bootstrap.LayoutMasonry} this
31104 * @param {Roo.EventObject} e
31111 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31114 * @cfg {Boolean} isLayoutInstant = no animation?
31116 isLayoutInstant : false, // needed?
31119 * @cfg {Number} boxWidth width of the columns
31124 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31129 * @cfg {Number} padWidth padding below box..
31134 * @cfg {Number} gutter gutter width..
31139 * @cfg {Number} maxCols maximum number of columns
31145 * @cfg {Boolean} isAutoInitial defalut true
31147 isAutoInitial : true,
31152 * @cfg {Boolean} isHorizontal defalut false
31154 isHorizontal : false,
31156 currentSize : null,
31162 bricks: null, //CompositeElement
31166 _isLayoutInited : false,
31168 // isAlternative : false, // only use for vertical layout...
31171 * @cfg {Number} alternativePadWidth padding below box..
31173 alternativePadWidth : 50,
31175 selectedBrick : [],
31177 getAutoCreate : function(){
31179 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31183 cls: 'blog-masonary-wrapper ' + this.cls,
31185 cls : 'mas-boxes masonary'
31192 getChildContainer: function( )
31194 if (this.boxesEl) {
31195 return this.boxesEl;
31198 this.boxesEl = this.el.select('.mas-boxes').first();
31200 return this.boxesEl;
31204 initEvents : function()
31208 if(this.isAutoInitial){
31209 Roo.log('hook children rendered');
31210 this.on('childrenrendered', function() {
31211 Roo.log('children rendered');
31217 initial : function()
31219 this.selectedBrick = [];
31221 this.currentSize = this.el.getBox(true);
31223 Roo.EventManager.onWindowResize(this.resize, this);
31225 if(!this.isAutoInitial){
31233 //this.layout.defer(500,this);
31237 resize : function()
31239 var cs = this.el.getBox(true);
31242 this.currentSize.width == cs.width &&
31243 this.currentSize.x == cs.x &&
31244 this.currentSize.height == cs.height &&
31245 this.currentSize.y == cs.y
31247 Roo.log("no change in with or X or Y");
31251 this.currentSize = cs;
31257 layout : function()
31259 this._resetLayout();
31261 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31263 this.layoutItems( isInstant );
31265 this._isLayoutInited = true;
31267 this.fireEvent('layout', this);
31271 _resetLayout : function()
31273 if(this.isHorizontal){
31274 this.horizontalMeasureColumns();
31278 this.verticalMeasureColumns();
31282 verticalMeasureColumns : function()
31284 this.getContainerWidth();
31286 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31287 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31291 var boxWidth = this.boxWidth + this.padWidth;
31293 if(this.containerWidth < this.boxWidth){
31294 boxWidth = this.containerWidth
31297 var containerWidth = this.containerWidth;
31299 var cols = Math.floor(containerWidth / boxWidth);
31301 this.cols = Math.max( cols, 1 );
31303 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31305 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31307 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31309 this.colWidth = boxWidth + avail - this.padWidth;
31311 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31312 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31315 horizontalMeasureColumns : function()
31317 this.getContainerWidth();
31319 var boxWidth = this.boxWidth;
31321 if(this.containerWidth < boxWidth){
31322 boxWidth = this.containerWidth;
31325 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31327 this.el.setHeight(boxWidth);
31331 getContainerWidth : function()
31333 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31336 layoutItems : function( isInstant )
31338 Roo.log(this.bricks);
31340 var items = Roo.apply([], this.bricks);
31342 if(this.isHorizontal){
31343 this._horizontalLayoutItems( items , isInstant );
31347 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31348 // this._verticalAlternativeLayoutItems( items , isInstant );
31352 this._verticalLayoutItems( items , isInstant );
31356 _verticalLayoutItems : function ( items , isInstant)
31358 if ( !items || !items.length ) {
31363 ['xs', 'xs', 'xs', 'tall'],
31364 ['xs', 'xs', 'tall'],
31365 ['xs', 'xs', 'sm'],
31366 ['xs', 'xs', 'xs'],
31372 ['sm', 'xs', 'xs'],
31376 ['tall', 'xs', 'xs', 'xs'],
31377 ['tall', 'xs', 'xs'],
31389 Roo.each(items, function(item, k){
31391 switch (item.size) {
31392 // these layouts take up a full box,
31403 boxes.push([item]);
31426 var filterPattern = function(box, length)
31434 var pattern = box.slice(0, length);
31438 Roo.each(pattern, function(i){
31439 format.push(i.size);
31442 Roo.each(standard, function(s){
31444 if(String(s) != String(format)){
31453 if(!match && length == 1){
31458 filterPattern(box, length - 1);
31462 queue.push(pattern);
31464 box = box.slice(length, box.length);
31466 filterPattern(box, 4);
31472 Roo.each(boxes, function(box, k){
31478 if(box.length == 1){
31483 filterPattern(box, 4);
31487 this._processVerticalLayoutQueue( queue, isInstant );
31491 // _verticalAlternativeLayoutItems : function( items , isInstant )
31493 // if ( !items || !items.length ) {
31497 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31501 _horizontalLayoutItems : function ( items , isInstant)
31503 if ( !items || !items.length || items.length < 3) {
31509 var eItems = items.slice(0, 3);
31511 items = items.slice(3, items.length);
31514 ['xs', 'xs', 'xs', 'wide'],
31515 ['xs', 'xs', 'wide'],
31516 ['xs', 'xs', 'sm'],
31517 ['xs', 'xs', 'xs'],
31523 ['sm', 'xs', 'xs'],
31527 ['wide', 'xs', 'xs', 'xs'],
31528 ['wide', 'xs', 'xs'],
31541 Roo.each(items, function(item, k){
31543 switch (item.size) {
31554 boxes.push([item]);
31578 var filterPattern = function(box, length)
31586 var pattern = box.slice(0, length);
31590 Roo.each(pattern, function(i){
31591 format.push(i.size);
31594 Roo.each(standard, function(s){
31596 if(String(s) != String(format)){
31605 if(!match && length == 1){
31610 filterPattern(box, length - 1);
31614 queue.push(pattern);
31616 box = box.slice(length, box.length);
31618 filterPattern(box, 4);
31624 Roo.each(boxes, function(box, k){
31630 if(box.length == 1){
31635 filterPattern(box, 4);
31642 var pos = this.el.getBox(true);
31646 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31648 var hit_end = false;
31650 Roo.each(queue, function(box){
31654 Roo.each(box, function(b){
31656 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31666 Roo.each(box, function(b){
31668 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31671 mx = Math.max(mx, b.x);
31675 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31679 Roo.each(box, function(b){
31681 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31695 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31698 /** Sets position of item in DOM
31699 * @param {Element} item
31700 * @param {Number} x - horizontal position
31701 * @param {Number} y - vertical position
31702 * @param {Boolean} isInstant - disables transitions
31704 _processVerticalLayoutQueue : function( queue, isInstant )
31706 var pos = this.el.getBox(true);
31711 for (var i = 0; i < this.cols; i++){
31715 Roo.each(queue, function(box, k){
31717 var col = k % this.cols;
31719 Roo.each(box, function(b,kk){
31721 b.el.position('absolute');
31723 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31724 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31726 if(b.size == 'md-left' || b.size == 'md-right'){
31727 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31728 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31731 b.el.setWidth(width);
31732 b.el.setHeight(height);
31734 b.el.select('iframe',true).setSize(width,height);
31738 for (var i = 0; i < this.cols; i++){
31740 if(maxY[i] < maxY[col]){
31745 col = Math.min(col, i);
31749 x = pos.x + col * (this.colWidth + this.padWidth);
31753 var positions = [];
31755 switch (box.length){
31757 positions = this.getVerticalOneBoxColPositions(x, y, box);
31760 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31763 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31766 positions = this.getVerticalFourBoxColPositions(x, y, box);
31772 Roo.each(box, function(b,kk){
31774 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31776 var sz = b.el.getSize();
31778 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31786 for (var i = 0; i < this.cols; i++){
31787 mY = Math.max(mY, maxY[i]);
31790 this.el.setHeight(mY - pos.y);
31794 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31796 // var pos = this.el.getBox(true);
31799 // var maxX = pos.right;
31801 // var maxHeight = 0;
31803 // Roo.each(items, function(item, k){
31807 // item.el.position('absolute');
31809 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31811 // item.el.setWidth(width);
31813 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31815 // item.el.setHeight(height);
31818 // item.el.setXY([x, y], isInstant ? false : true);
31820 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31823 // y = y + height + this.alternativePadWidth;
31825 // maxHeight = maxHeight + height + this.alternativePadWidth;
31829 // this.el.setHeight(maxHeight);
31833 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31835 var pos = this.el.getBox(true);
31840 var maxX = pos.right;
31842 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31844 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31846 Roo.each(queue, function(box, k){
31848 Roo.each(box, function(b, kk){
31850 b.el.position('absolute');
31852 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31853 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31855 if(b.size == 'md-left' || b.size == 'md-right'){
31856 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31857 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31860 b.el.setWidth(width);
31861 b.el.setHeight(height);
31869 var positions = [];
31871 switch (box.length){
31873 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31876 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31879 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31882 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31888 Roo.each(box, function(b,kk){
31890 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31892 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31900 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31902 Roo.each(eItems, function(b,k){
31904 b.size = (k == 0) ? 'sm' : 'xs';
31905 b.x = (k == 0) ? 2 : 1;
31906 b.y = (k == 0) ? 2 : 1;
31908 b.el.position('absolute');
31910 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31912 b.el.setWidth(width);
31914 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31916 b.el.setHeight(height);
31920 var positions = [];
31923 x : maxX - this.unitWidth * 2 - this.gutter,
31928 x : maxX - this.unitWidth,
31929 y : minY + (this.unitWidth + this.gutter) * 2
31933 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31937 Roo.each(eItems, function(b,k){
31939 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31945 getVerticalOneBoxColPositions : function(x, y, box)
31949 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31951 if(box[0].size == 'md-left'){
31955 if(box[0].size == 'md-right'){
31960 x : x + (this.unitWidth + this.gutter) * rand,
31967 getVerticalTwoBoxColPositions : function(x, y, box)
31971 if(box[0].size == 'xs'){
31975 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
31979 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
31993 x : x + (this.unitWidth + this.gutter) * 2,
31994 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32001 getVerticalThreeBoxColPositions : function(x, y, box)
32005 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32013 x : x + (this.unitWidth + this.gutter) * 1,
32018 x : x + (this.unitWidth + this.gutter) * 2,
32026 if(box[0].size == 'xs' && box[1].size == 'xs'){
32035 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32039 x : x + (this.unitWidth + this.gutter) * 1,
32053 x : x + (this.unitWidth + this.gutter) * 2,
32058 x : x + (this.unitWidth + this.gutter) * 2,
32059 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32066 getVerticalFourBoxColPositions : function(x, y, box)
32070 if(box[0].size == 'xs'){
32079 y : y + (this.unitHeight + this.gutter) * 1
32084 y : y + (this.unitHeight + this.gutter) * 2
32088 x : x + (this.unitWidth + this.gutter) * 1,
32102 x : x + (this.unitWidth + this.gutter) * 2,
32107 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32108 y : y + (this.unitHeight + this.gutter) * 1
32112 x : x + (this.unitWidth + this.gutter) * 2,
32113 y : y + (this.unitWidth + this.gutter) * 2
32120 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32124 if(box[0].size == 'md-left'){
32126 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32133 if(box[0].size == 'md-right'){
32135 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32136 y : minY + (this.unitWidth + this.gutter) * 1
32142 var rand = Math.floor(Math.random() * (4 - box[0].y));
32145 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32146 y : minY + (this.unitWidth + this.gutter) * rand
32153 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32157 if(box[0].size == 'xs'){
32160 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32165 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32166 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32174 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32179 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32180 y : minY + (this.unitWidth + this.gutter) * 2
32187 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32191 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32194 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32199 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32200 y : minY + (this.unitWidth + this.gutter) * 1
32204 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32205 y : minY + (this.unitWidth + this.gutter) * 2
32212 if(box[0].size == 'xs' && box[1].size == 'xs'){
32215 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32220 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32225 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32226 y : minY + (this.unitWidth + this.gutter) * 1
32234 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32239 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32240 y : minY + (this.unitWidth + this.gutter) * 2
32244 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32245 y : minY + (this.unitWidth + this.gutter) * 2
32252 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32256 if(box[0].size == 'xs'){
32259 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32264 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32269 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),
32274 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32275 y : minY + (this.unitWidth + this.gutter) * 1
32283 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32288 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32289 y : minY + (this.unitWidth + this.gutter) * 2
32293 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32294 y : minY + (this.unitWidth + this.gutter) * 2
32298 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),
32299 y : minY + (this.unitWidth + this.gutter) * 2
32307 * remove a Masonry Brick
32308 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32310 removeBrick : function(brick_id)
32316 for (var i = 0; i<this.bricks.length; i++) {
32317 if (this.bricks[i].id == brick_id) {
32318 this.bricks.splice(i,1);
32319 this.el.dom.removeChild(Roo.get(brick_id).dom);
32326 * adds a Masonry Brick
32327 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32329 addBrick : function(cfg)
32331 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32332 //this.register(cn);
32333 cn.parentId = this.id;
32334 cn.render(this.el);
32339 * register a Masonry Brick
32340 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32343 register : function(brick)
32345 this.bricks.push(brick);
32346 brick.masonryId = this.id;
32350 * clear all the Masonry Brick
32352 clearAll : function()
32355 //this.getChildContainer().dom.innerHTML = "";
32356 this.el.dom.innerHTML = '';
32359 getSelected : function()
32361 if (!this.selectedBrick) {
32365 return this.selectedBrick;
32369 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32373 * register a Masonry Layout
32374 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32377 register : function(layout)
32379 this.groups[layout.id] = layout;
32382 * fetch a Masonry Layout based on the masonry layout ID
32383 * @param {string} the masonry layout to add
32384 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32387 get: function(layout_id) {
32388 if (typeof(this.groups[layout_id]) == 'undefined') {
32391 return this.groups[layout_id] ;
32403 * http://masonry.desandro.com
32405 * The idea is to render all the bricks based on vertical width...
32407 * The original code extends 'outlayer' - we might need to use that....
32413 * @class Roo.bootstrap.LayoutMasonryAuto
32414 * @extends Roo.bootstrap.Component
32415 * Bootstrap Layout Masonry class
32418 * Create a new Element
32419 * @param {Object} config The config object
32422 Roo.bootstrap.LayoutMasonryAuto = function(config){
32423 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32426 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32429 * @cfg {Boolean} isFitWidth - resize the width..
32431 isFitWidth : false, // options..
32433 * @cfg {Boolean} isOriginLeft = left align?
32435 isOriginLeft : true,
32437 * @cfg {Boolean} isOriginTop = top align?
32439 isOriginTop : false,
32441 * @cfg {Boolean} isLayoutInstant = no animation?
32443 isLayoutInstant : false, // needed?
32445 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32447 isResizingContainer : true,
32449 * @cfg {Number} columnWidth width of the columns
32455 * @cfg {Number} maxCols maximum number of columns
32460 * @cfg {Number} padHeight padding below box..
32466 * @cfg {Boolean} isAutoInitial defalut true
32469 isAutoInitial : true,
32475 initialColumnWidth : 0,
32476 currentSize : null,
32478 colYs : null, // array.
32485 bricks: null, //CompositeElement
32486 cols : 0, // array?
32487 // element : null, // wrapped now this.el
32488 _isLayoutInited : null,
32491 getAutoCreate : function(){
32495 cls: 'blog-masonary-wrapper ' + this.cls,
32497 cls : 'mas-boxes masonary'
32504 getChildContainer: function( )
32506 if (this.boxesEl) {
32507 return this.boxesEl;
32510 this.boxesEl = this.el.select('.mas-boxes').first();
32512 return this.boxesEl;
32516 initEvents : function()
32520 if(this.isAutoInitial){
32521 Roo.log('hook children rendered');
32522 this.on('childrenrendered', function() {
32523 Roo.log('children rendered');
32530 initial : function()
32532 this.reloadItems();
32534 this.currentSize = this.el.getBox(true);
32536 /// was window resize... - let's see if this works..
32537 Roo.EventManager.onWindowResize(this.resize, this);
32539 if(!this.isAutoInitial){
32544 this.layout.defer(500,this);
32547 reloadItems: function()
32549 this.bricks = this.el.select('.masonry-brick', true);
32551 this.bricks.each(function(b) {
32552 //Roo.log(b.getSize());
32553 if (!b.attr('originalwidth')) {
32554 b.attr('originalwidth', b.getSize().width);
32559 Roo.log(this.bricks.elements.length);
32562 resize : function()
32565 var cs = this.el.getBox(true);
32567 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32568 Roo.log("no change in with or X");
32571 this.currentSize = cs;
32575 layout : function()
32578 this._resetLayout();
32579 //this._manageStamps();
32581 // don't animate first layout
32582 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32583 this.layoutItems( isInstant );
32585 // flag for initalized
32586 this._isLayoutInited = true;
32589 layoutItems : function( isInstant )
32591 //var items = this._getItemsForLayout( this.items );
32592 // original code supports filtering layout items.. we just ignore it..
32594 this._layoutItems( this.bricks , isInstant );
32596 this._postLayout();
32598 _layoutItems : function ( items , isInstant)
32600 //this.fireEvent( 'layout', this, items );
32603 if ( !items || !items.elements.length ) {
32604 // no items, emit event with empty array
32609 items.each(function(item) {
32610 Roo.log("layout item");
32612 // get x/y object from method
32613 var position = this._getItemLayoutPosition( item );
32615 position.item = item;
32616 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32617 queue.push( position );
32620 this._processLayoutQueue( queue );
32622 /** Sets position of item in DOM
32623 * @param {Element} item
32624 * @param {Number} x - horizontal position
32625 * @param {Number} y - vertical position
32626 * @param {Boolean} isInstant - disables transitions
32628 _processLayoutQueue : function( queue )
32630 for ( var i=0, len = queue.length; i < len; i++ ) {
32631 var obj = queue[i];
32632 obj.item.position('absolute');
32633 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32639 * Any logic you want to do after each layout,
32640 * i.e. size the container
32642 _postLayout : function()
32644 this.resizeContainer();
32647 resizeContainer : function()
32649 if ( !this.isResizingContainer ) {
32652 var size = this._getContainerSize();
32654 this.el.setSize(size.width,size.height);
32655 this.boxesEl.setSize(size.width,size.height);
32661 _resetLayout : function()
32663 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32664 this.colWidth = this.el.getWidth();
32665 //this.gutter = this.el.getWidth();
32667 this.measureColumns();
32673 this.colYs.push( 0 );
32679 measureColumns : function()
32681 this.getContainerWidth();
32682 // if columnWidth is 0, default to outerWidth of first item
32683 if ( !this.columnWidth ) {
32684 var firstItem = this.bricks.first();
32685 Roo.log(firstItem);
32686 this.columnWidth = this.containerWidth;
32687 if (firstItem && firstItem.attr('originalwidth') ) {
32688 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32690 // columnWidth fall back to item of first element
32691 Roo.log("set column width?");
32692 this.initialColumnWidth = this.columnWidth ;
32694 // if first elem has no width, default to size of container
32699 if (this.initialColumnWidth) {
32700 this.columnWidth = this.initialColumnWidth;
32705 // column width is fixed at the top - however if container width get's smaller we should
32708 // this bit calcs how man columns..
32710 var columnWidth = this.columnWidth += this.gutter;
32712 // calculate columns
32713 var containerWidth = this.containerWidth + this.gutter;
32715 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32716 // fix rounding errors, typically with gutters
32717 var excess = columnWidth - containerWidth % columnWidth;
32720 // if overshoot is less than a pixel, round up, otherwise floor it
32721 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32722 cols = Math[ mathMethod ]( cols );
32723 this.cols = Math.max( cols, 1 );
32724 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32726 // padding positioning..
32727 var totalColWidth = this.cols * this.columnWidth;
32728 var padavail = this.containerWidth - totalColWidth;
32729 // so for 2 columns - we need 3 'pads'
32731 var padNeeded = (1+this.cols) * this.padWidth;
32733 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32735 this.columnWidth += padExtra
32736 //this.padWidth = Math.floor(padavail / ( this.cols));
32738 // adjust colum width so that padding is fixed??
32740 // we have 3 columns ... total = width * 3
32741 // we have X left over... that should be used by
32743 //if (this.expandC) {
32751 getContainerWidth : function()
32753 /* // container is parent if fit width
32754 var container = this.isFitWidth ? this.element.parentNode : this.element;
32755 // check that this.size and size are there
32756 // IE8 triggers resize on body size change, so they might not be
32758 var size = getSize( container ); //FIXME
32759 this.containerWidth = size && size.innerWidth; //FIXME
32762 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32766 _getItemLayoutPosition : function( item ) // what is item?
32768 // we resize the item to our columnWidth..
32770 item.setWidth(this.columnWidth);
32771 item.autoBoxAdjust = false;
32773 var sz = item.getSize();
32775 // how many columns does this brick span
32776 var remainder = this.containerWidth % this.columnWidth;
32778 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32779 // round if off by 1 pixel, otherwise use ceil
32780 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32781 colSpan = Math.min( colSpan, this.cols );
32783 // normally this should be '1' as we dont' currently allow multi width columns..
32785 var colGroup = this._getColGroup( colSpan );
32786 // get the minimum Y value from the columns
32787 var minimumY = Math.min.apply( Math, colGroup );
32788 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32790 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32792 // position the brick
32794 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32795 y: this.currentSize.y + minimumY + this.padHeight
32799 // apply setHeight to necessary columns
32800 var setHeight = minimumY + sz.height + this.padHeight;
32801 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32803 var setSpan = this.cols + 1 - colGroup.length;
32804 for ( var i = 0; i < setSpan; i++ ) {
32805 this.colYs[ shortColIndex + i ] = setHeight ;
32812 * @param {Number} colSpan - number of columns the element spans
32813 * @returns {Array} colGroup
32815 _getColGroup : function( colSpan )
32817 if ( colSpan < 2 ) {
32818 // if brick spans only one column, use all the column Ys
32823 // how many different places could this brick fit horizontally
32824 var groupCount = this.cols + 1 - colSpan;
32825 // for each group potential horizontal position
32826 for ( var i = 0; i < groupCount; i++ ) {
32827 // make an array of colY values for that one group
32828 var groupColYs = this.colYs.slice( i, i + colSpan );
32829 // and get the max value of the array
32830 colGroup[i] = Math.max.apply( Math, groupColYs );
32835 _manageStamp : function( stamp )
32837 var stampSize = stamp.getSize();
32838 var offset = stamp.getBox();
32839 // get the columns that this stamp affects
32840 var firstX = this.isOriginLeft ? offset.x : offset.right;
32841 var lastX = firstX + stampSize.width;
32842 var firstCol = Math.floor( firstX / this.columnWidth );
32843 firstCol = Math.max( 0, firstCol );
32845 var lastCol = Math.floor( lastX / this.columnWidth );
32846 // lastCol should not go over if multiple of columnWidth #425
32847 lastCol -= lastX % this.columnWidth ? 0 : 1;
32848 lastCol = Math.min( this.cols - 1, lastCol );
32850 // set colYs to bottom of the stamp
32851 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32854 for ( var i = firstCol; i <= lastCol; i++ ) {
32855 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32860 _getContainerSize : function()
32862 this.maxY = Math.max.apply( Math, this.colYs );
32867 if ( this.isFitWidth ) {
32868 size.width = this._getContainerFitWidth();
32874 _getContainerFitWidth : function()
32876 var unusedCols = 0;
32877 // count unused columns
32880 if ( this.colYs[i] !== 0 ) {
32885 // fit container to columns that have been used
32886 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32889 needsResizeLayout : function()
32891 var previousWidth = this.containerWidth;
32892 this.getContainerWidth();
32893 return previousWidth !== this.containerWidth;
32908 * @class Roo.bootstrap.MasonryBrick
32909 * @extends Roo.bootstrap.Component
32910 * Bootstrap MasonryBrick class
32913 * Create a new MasonryBrick
32914 * @param {Object} config The config object
32917 Roo.bootstrap.MasonryBrick = function(config){
32919 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32921 Roo.bootstrap.MasonryBrick.register(this);
32927 * When a MasonryBrick is clcik
32928 * @param {Roo.bootstrap.MasonryBrick} this
32929 * @param {Roo.EventObject} e
32935 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32938 * @cfg {String} title
32942 * @cfg {String} html
32946 * @cfg {String} bgimage
32950 * @cfg {String} videourl
32954 * @cfg {String} cls
32958 * @cfg {String} href
32962 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
32967 * @cfg {String} placetitle (center|bottom)
32972 * @cfg {Boolean} isFitContainer defalut true
32974 isFitContainer : true,
32977 * @cfg {Boolean} preventDefault defalut false
32979 preventDefault : false,
32982 * @cfg {Boolean} inverse defalut false
32984 maskInverse : false,
32986 getAutoCreate : function()
32988 if(!this.isFitContainer){
32989 return this.getSplitAutoCreate();
32992 var cls = 'masonry-brick masonry-brick-full';
32994 if(this.href.length){
32995 cls += ' masonry-brick-link';
32998 if(this.bgimage.length){
32999 cls += ' masonry-brick-image';
33002 if(this.maskInverse){
33003 cls += ' mask-inverse';
33006 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33007 cls += ' enable-mask';
33011 cls += ' masonry-' + this.size + '-brick';
33014 if(this.placetitle.length){
33016 switch (this.placetitle) {
33018 cls += ' masonry-center-title';
33021 cls += ' masonry-bottom-title';
33028 if(!this.html.length && !this.bgimage.length){
33029 cls += ' masonry-center-title';
33032 if(!this.html.length && this.bgimage.length){
33033 cls += ' masonry-bottom-title';
33038 cls += ' ' + this.cls;
33042 tag: (this.href.length) ? 'a' : 'div',
33047 cls: 'masonry-brick-mask'
33051 cls: 'masonry-brick-paragraph',
33057 if(this.href.length){
33058 cfg.href = this.href;
33061 var cn = cfg.cn[1].cn;
33063 if(this.title.length){
33066 cls: 'masonry-brick-title',
33071 if(this.html.length){
33074 cls: 'masonry-brick-text',
33079 if (!this.title.length && !this.html.length) {
33080 cfg.cn[1].cls += ' hide';
33083 if(this.bgimage.length){
33086 cls: 'masonry-brick-image-view',
33091 if(this.videourl.length){
33092 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33093 // youtube support only?
33096 cls: 'masonry-brick-image-view',
33099 allowfullscreen : true
33107 getSplitAutoCreate : function()
33109 var cls = 'masonry-brick masonry-brick-split';
33111 if(this.href.length){
33112 cls += ' masonry-brick-link';
33115 if(this.bgimage.length){
33116 cls += ' masonry-brick-image';
33120 cls += ' masonry-' + this.size + '-brick';
33123 switch (this.placetitle) {
33125 cls += ' masonry-center-title';
33128 cls += ' masonry-bottom-title';
33131 if(!this.bgimage.length){
33132 cls += ' masonry-center-title';
33135 if(this.bgimage.length){
33136 cls += ' masonry-bottom-title';
33142 cls += ' ' + this.cls;
33146 tag: (this.href.length) ? 'a' : 'div',
33151 cls: 'masonry-brick-split-head',
33155 cls: 'masonry-brick-paragraph',
33162 cls: 'masonry-brick-split-body',
33168 if(this.href.length){
33169 cfg.href = this.href;
33172 if(this.title.length){
33173 cfg.cn[0].cn[0].cn.push({
33175 cls: 'masonry-brick-title',
33180 if(this.html.length){
33181 cfg.cn[1].cn.push({
33183 cls: 'masonry-brick-text',
33188 if(this.bgimage.length){
33189 cfg.cn[0].cn.push({
33191 cls: 'masonry-brick-image-view',
33196 if(this.videourl.length){
33197 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33198 // youtube support only?
33199 cfg.cn[0].cn.cn.push({
33201 cls: 'masonry-brick-image-view',
33204 allowfullscreen : true
33211 initEvents: function()
33213 switch (this.size) {
33246 this.el.on('touchstart', this.onTouchStart, this);
33247 this.el.on('touchmove', this.onTouchMove, this);
33248 this.el.on('touchend', this.onTouchEnd, this);
33249 this.el.on('contextmenu', this.onContextMenu, this);
33251 this.el.on('mouseenter' ,this.enter, this);
33252 this.el.on('mouseleave', this.leave, this);
33253 this.el.on('click', this.onClick, this);
33256 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33257 this.parent().bricks.push(this);
33262 onClick: function(e, el)
33264 var time = this.endTimer - this.startTimer;
33265 // Roo.log(e.preventDefault());
33268 e.preventDefault();
33273 if(!this.preventDefault){
33277 e.preventDefault();
33279 if (this.activeClass != '') {
33280 this.selectBrick();
33283 this.fireEvent('click', this, e);
33286 enter: function(e, el)
33288 e.preventDefault();
33290 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33294 if(this.bgimage.length && this.html.length){
33295 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33299 leave: function(e, el)
33301 e.preventDefault();
33303 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33307 if(this.bgimage.length && this.html.length){
33308 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33312 onTouchStart: function(e, el)
33314 // e.preventDefault();
33316 this.touchmoved = false;
33318 if(!this.isFitContainer){
33322 if(!this.bgimage.length || !this.html.length){
33326 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33328 this.timer = new Date().getTime();
33332 onTouchMove: function(e, el)
33334 this.touchmoved = true;
33337 onContextMenu : function(e,el)
33339 e.preventDefault();
33340 e.stopPropagation();
33344 onTouchEnd: function(e, el)
33346 // e.preventDefault();
33348 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33355 if(!this.bgimage.length || !this.html.length){
33357 if(this.href.length){
33358 window.location.href = this.href;
33364 if(!this.isFitContainer){
33368 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33370 window.location.href = this.href;
33373 //selection on single brick only
33374 selectBrick : function() {
33376 if (!this.parentId) {
33380 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33381 var index = m.selectedBrick.indexOf(this.id);
33384 m.selectedBrick.splice(index,1);
33385 this.el.removeClass(this.activeClass);
33389 for(var i = 0; i < m.selectedBrick.length; i++) {
33390 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33391 b.el.removeClass(b.activeClass);
33394 m.selectedBrick = [];
33396 m.selectedBrick.push(this.id);
33397 this.el.addClass(this.activeClass);
33401 isSelected : function(){
33402 return this.el.hasClass(this.activeClass);
33407 Roo.apply(Roo.bootstrap.MasonryBrick, {
33410 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33412 * register a Masonry Brick
33413 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33416 register : function(brick)
33418 //this.groups[brick.id] = brick;
33419 this.groups.add(brick.id, brick);
33422 * fetch a masonry brick based on the masonry brick ID
33423 * @param {string} the masonry brick to add
33424 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33427 get: function(brick_id)
33429 // if (typeof(this.groups[brick_id]) == 'undefined') {
33432 // return this.groups[brick_id] ;
33434 if(this.groups.key(brick_id)) {
33435 return this.groups.key(brick_id);
33453 * @class Roo.bootstrap.Brick
33454 * @extends Roo.bootstrap.Component
33455 * Bootstrap Brick class
33458 * Create a new Brick
33459 * @param {Object} config The config object
33462 Roo.bootstrap.Brick = function(config){
33463 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33469 * When a Brick is click
33470 * @param {Roo.bootstrap.Brick} this
33471 * @param {Roo.EventObject} e
33477 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33480 * @cfg {String} title
33484 * @cfg {String} html
33488 * @cfg {String} bgimage
33492 * @cfg {String} cls
33496 * @cfg {String} href
33500 * @cfg {String} video
33504 * @cfg {Boolean} square
33508 getAutoCreate : function()
33510 var cls = 'roo-brick';
33512 if(this.href.length){
33513 cls += ' roo-brick-link';
33516 if(this.bgimage.length){
33517 cls += ' roo-brick-image';
33520 if(!this.html.length && !this.bgimage.length){
33521 cls += ' roo-brick-center-title';
33524 if(!this.html.length && this.bgimage.length){
33525 cls += ' roo-brick-bottom-title';
33529 cls += ' ' + this.cls;
33533 tag: (this.href.length) ? 'a' : 'div',
33538 cls: 'roo-brick-paragraph',
33544 if(this.href.length){
33545 cfg.href = this.href;
33548 var cn = cfg.cn[0].cn;
33550 if(this.title.length){
33553 cls: 'roo-brick-title',
33558 if(this.html.length){
33561 cls: 'roo-brick-text',
33568 if(this.bgimage.length){
33571 cls: 'roo-brick-image-view',
33579 initEvents: function()
33581 if(this.title.length || this.html.length){
33582 this.el.on('mouseenter' ,this.enter, this);
33583 this.el.on('mouseleave', this.leave, this);
33586 Roo.EventManager.onWindowResize(this.resize, this);
33588 if(this.bgimage.length){
33589 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33590 this.imageEl.on('load', this.onImageLoad, this);
33597 onImageLoad : function()
33602 resize : function()
33604 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33606 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33608 if(this.bgimage.length){
33609 var image = this.el.select('.roo-brick-image-view', true).first();
33611 image.setWidth(paragraph.getWidth());
33614 image.setHeight(paragraph.getWidth());
33617 this.el.setHeight(image.getHeight());
33618 paragraph.setHeight(image.getHeight());
33624 enter: function(e, el)
33626 e.preventDefault();
33628 if(this.bgimage.length){
33629 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33630 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33634 leave: function(e, el)
33636 e.preventDefault();
33638 if(this.bgimage.length){
33639 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33640 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33655 * @class Roo.bootstrap.NumberField
33656 * @extends Roo.bootstrap.Input
33657 * Bootstrap NumberField class
33663 * Create a new NumberField
33664 * @param {Object} config The config object
33667 Roo.bootstrap.NumberField = function(config){
33668 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33671 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33674 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33676 allowDecimals : true,
33678 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33680 decimalSeparator : ".",
33682 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33684 decimalPrecision : 2,
33686 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33688 allowNegative : true,
33691 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33695 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33697 minValue : Number.NEGATIVE_INFINITY,
33699 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33701 maxValue : Number.MAX_VALUE,
33703 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33705 minText : "The minimum value for this field is {0}",
33707 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33709 maxText : "The maximum value for this field is {0}",
33711 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33712 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33714 nanText : "{0} is not a valid number",
33716 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33718 thousandsDelimiter : false,
33720 * @cfg {String} valueAlign alignment of value
33722 valueAlign : "left",
33724 getAutoCreate : function()
33726 var hiddenInput = {
33730 cls: 'hidden-number-input'
33734 hiddenInput.name = this.name;
33739 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33741 this.name = hiddenInput.name;
33743 if(cfg.cn.length > 0) {
33744 cfg.cn.push(hiddenInput);
33751 initEvents : function()
33753 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33755 var allowed = "0123456789";
33757 if(this.allowDecimals){
33758 allowed += this.decimalSeparator;
33761 if(this.allowNegative){
33765 if(this.thousandsDelimiter) {
33769 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33771 var keyPress = function(e){
33773 var k = e.getKey();
33775 var c = e.getCharCode();
33778 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33779 allowed.indexOf(String.fromCharCode(c)) === -1
33785 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33789 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33794 this.el.on("keypress", keyPress, this);
33797 validateValue : function(value)
33800 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33804 var num = this.parseValue(value);
33807 this.markInvalid(String.format(this.nanText, value));
33811 if(num < this.minValue){
33812 this.markInvalid(String.format(this.minText, this.minValue));
33816 if(num > this.maxValue){
33817 this.markInvalid(String.format(this.maxText, this.maxValue));
33824 getValue : function()
33826 var v = this.hiddenEl().getValue();
33828 return this.fixPrecision(this.parseValue(v));
33831 parseValue : function(value)
33833 if(this.thousandsDelimiter) {
33835 r = new RegExp(",", "g");
33836 value = value.replace(r, "");
33839 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33840 return isNaN(value) ? '' : value;
33843 fixPrecision : function(value)
33845 if(this.thousandsDelimiter) {
33847 r = new RegExp(",", "g");
33848 value = value.replace(r, "");
33851 var nan = isNaN(value);
33853 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33854 return nan ? '' : value;
33856 return parseFloat(value).toFixed(this.decimalPrecision);
33859 setValue : function(v)
33861 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33867 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33869 this.inputEl().dom.value = (v == '') ? '' :
33870 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33872 if(!this.allowZero && v === '0') {
33873 this.hiddenEl().dom.value = '';
33874 this.inputEl().dom.value = '';
33881 decimalPrecisionFcn : function(v)
33883 return Math.floor(v);
33886 beforeBlur : function()
33888 var v = this.parseValue(this.getRawValue());
33890 if(v || v === 0 || v === ''){
33895 hiddenEl : function()
33897 return this.el.select('input.hidden-number-input',true).first();
33909 * @class Roo.bootstrap.DocumentSlider
33910 * @extends Roo.bootstrap.Component
33911 * Bootstrap DocumentSlider class
33914 * Create a new DocumentViewer
33915 * @param {Object} config The config object
33918 Roo.bootstrap.DocumentSlider = function(config){
33919 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33926 * Fire after initEvent
33927 * @param {Roo.bootstrap.DocumentSlider} this
33932 * Fire after update
33933 * @param {Roo.bootstrap.DocumentSlider} this
33939 * @param {Roo.bootstrap.DocumentSlider} this
33945 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33951 getAutoCreate : function()
33955 cls : 'roo-document-slider',
33959 cls : 'roo-document-slider-header',
33963 cls : 'roo-document-slider-header-title'
33969 cls : 'roo-document-slider-body',
33973 cls : 'roo-document-slider-prev',
33977 cls : 'fa fa-chevron-left'
33983 cls : 'roo-document-slider-thumb',
33987 cls : 'roo-document-slider-image'
33993 cls : 'roo-document-slider-next',
33997 cls : 'fa fa-chevron-right'
34009 initEvents : function()
34011 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34012 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34014 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34015 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34017 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34018 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34020 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34021 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34023 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34024 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34026 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34027 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34029 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34030 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34032 this.thumbEl.on('click', this.onClick, this);
34034 this.prevIndicator.on('click', this.prev, this);
34036 this.nextIndicator.on('click', this.next, this);
34040 initial : function()
34042 if(this.files.length){
34043 this.indicator = 1;
34047 this.fireEvent('initial', this);
34050 update : function()
34052 this.imageEl.attr('src', this.files[this.indicator - 1]);
34054 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34056 this.prevIndicator.show();
34058 if(this.indicator == 1){
34059 this.prevIndicator.hide();
34062 this.nextIndicator.show();
34064 if(this.indicator == this.files.length){
34065 this.nextIndicator.hide();
34068 this.thumbEl.scrollTo('top');
34070 this.fireEvent('update', this);
34073 onClick : function(e)
34075 e.preventDefault();
34077 this.fireEvent('click', this);
34082 e.preventDefault();
34084 this.indicator = Math.max(1, this.indicator - 1);
34091 e.preventDefault();
34093 this.indicator = Math.min(this.files.length, this.indicator + 1);
34107 * @class Roo.bootstrap.RadioSet
34108 * @extends Roo.bootstrap.Input
34109 * Bootstrap RadioSet class
34110 * @cfg {String} indicatorpos (left|right) default left
34111 * @cfg {Boolean} inline (true|false) inline the element (default true)
34112 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34114 * Create a new RadioSet
34115 * @param {Object} config The config object
34118 Roo.bootstrap.RadioSet = function(config){
34120 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34124 Roo.bootstrap.RadioSet.register(this);
34129 * Fires when the element is checked or unchecked.
34130 * @param {Roo.bootstrap.RadioSet} this This radio
34131 * @param {Roo.bootstrap.Radio} item The checked item
34136 * Fires when the element is click.
34137 * @param {Roo.bootstrap.RadioSet} this This radio set
34138 * @param {Roo.bootstrap.Radio} item The checked item
34139 * @param {Roo.EventObject} e The event object
34146 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34154 indicatorpos : 'left',
34156 getAutoCreate : function()
34160 cls : 'roo-radio-set-label',
34164 html : this.fieldLabel
34168 if (Roo.bootstrap.version == 3) {
34171 if(this.indicatorpos == 'left'){
34174 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34175 tooltip : 'This field is required'
34180 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34181 tooltip : 'This field is required'
34187 cls : 'roo-radio-set-items'
34190 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34192 if (align === 'left' && this.fieldLabel.length) {
34195 cls : "roo-radio-set-right",
34201 if(this.labelWidth > 12){
34202 label.style = "width: " + this.labelWidth + 'px';
34205 if(this.labelWidth < 13 && this.labelmd == 0){
34206 this.labelmd = this.labelWidth;
34209 if(this.labellg > 0){
34210 label.cls += ' col-lg-' + this.labellg;
34211 items.cls += ' col-lg-' + (12 - this.labellg);
34214 if(this.labelmd > 0){
34215 label.cls += ' col-md-' + this.labelmd;
34216 items.cls += ' col-md-' + (12 - this.labelmd);
34219 if(this.labelsm > 0){
34220 label.cls += ' col-sm-' + this.labelsm;
34221 items.cls += ' col-sm-' + (12 - this.labelsm);
34224 if(this.labelxs > 0){
34225 label.cls += ' col-xs-' + this.labelxs;
34226 items.cls += ' col-xs-' + (12 - this.labelxs);
34232 cls : 'roo-radio-set',
34236 cls : 'roo-radio-set-input',
34239 value : this.value ? this.value : ''
34246 if(this.weight.length){
34247 cfg.cls += ' roo-radio-' + this.weight;
34251 cfg.cls += ' roo-radio-set-inline';
34255 ['xs','sm','md','lg'].map(function(size){
34256 if (settings[size]) {
34257 cfg.cls += ' col-' + size + '-' + settings[size];
34265 initEvents : function()
34267 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34268 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34270 if(!this.fieldLabel.length){
34271 this.labelEl.hide();
34274 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34275 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34277 this.indicator = this.indicatorEl();
34279 if(this.indicator){
34280 this.indicator.addClass('invisible');
34283 this.originalValue = this.getValue();
34287 inputEl: function ()
34289 return this.el.select('.roo-radio-set-input', true).first();
34292 getChildContainer : function()
34294 return this.itemsEl;
34297 register : function(item)
34299 this.radioes.push(item);
34303 validate : function()
34305 if(this.getVisibilityEl().hasClass('hidden')){
34311 Roo.each(this.radioes, function(i){
34320 if(this.allowBlank) {
34324 if(this.disabled || valid){
34329 this.markInvalid();
34334 markValid : function()
34336 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34337 this.indicatorEl().removeClass('visible');
34338 this.indicatorEl().addClass('invisible');
34342 if (Roo.bootstrap.version == 3) {
34343 this.el.removeClass([this.invalidClass, this.validClass]);
34344 this.el.addClass(this.validClass);
34346 this.el.removeClass(['is-invalid','is-valid']);
34347 this.el.addClass(['is-valid']);
34349 this.fireEvent('valid', this);
34352 markInvalid : function(msg)
34354 if(this.allowBlank || this.disabled){
34358 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34359 this.indicatorEl().removeClass('invisible');
34360 this.indicatorEl().addClass('visible');
34362 if (Roo.bootstrap.version == 3) {
34363 this.el.removeClass([this.invalidClass, this.validClass]);
34364 this.el.addClass(this.invalidClass);
34366 this.el.removeClass(['is-invalid','is-valid']);
34367 this.el.addClass(['is-invalid']);
34370 this.fireEvent('invalid', this, msg);
34374 setValue : function(v, suppressEvent)
34376 if(this.value === v){
34383 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34386 Roo.each(this.radioes, function(i){
34388 i.el.removeClass('checked');
34391 Roo.each(this.radioes, function(i){
34393 if(i.value === v || i.value.toString() === v.toString()){
34395 i.el.addClass('checked');
34397 if(suppressEvent !== true){
34398 this.fireEvent('check', this, i);
34409 clearInvalid : function(){
34411 if(!this.el || this.preventMark){
34415 this.el.removeClass([this.invalidClass]);
34417 this.fireEvent('valid', this);
34422 Roo.apply(Roo.bootstrap.RadioSet, {
34426 register : function(set)
34428 this.groups[set.name] = set;
34431 get: function(name)
34433 if (typeof(this.groups[name]) == 'undefined') {
34437 return this.groups[name] ;
34443 * Ext JS Library 1.1.1
34444 * Copyright(c) 2006-2007, Ext JS, LLC.
34446 * Originally Released Under LGPL - original licence link has changed is not relivant.
34449 * <script type="text/javascript">
34454 * @class Roo.bootstrap.SplitBar
34455 * @extends Roo.util.Observable
34456 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34460 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34461 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34462 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34463 split.minSize = 100;
34464 split.maxSize = 600;
34465 split.animate = true;
34466 split.on('moved', splitterMoved);
34469 * Create a new SplitBar
34470 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34471 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34472 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34473 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34474 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34475 position of the SplitBar).
34477 Roo.bootstrap.SplitBar = function(cfg){
34482 // dragElement : elm
34483 // resizingElement: el,
34485 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34486 // placement : Roo.bootstrap.SplitBar.LEFT ,
34487 // existingProxy ???
34490 this.el = Roo.get(cfg.dragElement, true);
34491 this.el.dom.unselectable = "on";
34493 this.resizingEl = Roo.get(cfg.resizingElement, true);
34497 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34498 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34501 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34504 * The minimum size of the resizing element. (Defaults to 0)
34510 * The maximum size of the resizing element. (Defaults to 2000)
34513 this.maxSize = 2000;
34516 * Whether to animate the transition to the new size
34519 this.animate = false;
34522 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34525 this.useShim = false;
34530 if(!cfg.existingProxy){
34532 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34534 this.proxy = Roo.get(cfg.existingProxy).dom;
34537 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34540 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34543 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34546 this.dragSpecs = {};
34549 * @private The adapter to use to positon and resize elements
34551 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34552 this.adapter.init(this);
34554 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34556 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34557 this.el.addClass("roo-splitbar-h");
34560 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34561 this.el.addClass("roo-splitbar-v");
34567 * Fires when the splitter is moved (alias for {@link #event-moved})
34568 * @param {Roo.bootstrap.SplitBar} this
34569 * @param {Number} newSize the new width or height
34574 * Fires when the splitter is moved
34575 * @param {Roo.bootstrap.SplitBar} this
34576 * @param {Number} newSize the new width or height
34580 * @event beforeresize
34581 * Fires before the splitter is dragged
34582 * @param {Roo.bootstrap.SplitBar} this
34584 "beforeresize" : true,
34586 "beforeapply" : true
34589 Roo.util.Observable.call(this);
34592 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34593 onStartProxyDrag : function(x, y){
34594 this.fireEvent("beforeresize", this);
34596 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34598 o.enableDisplayMode("block");
34599 // all splitbars share the same overlay
34600 Roo.bootstrap.SplitBar.prototype.overlay = o;
34602 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34603 this.overlay.show();
34604 Roo.get(this.proxy).setDisplayed("block");
34605 var size = this.adapter.getElementSize(this);
34606 this.activeMinSize = this.getMinimumSize();;
34607 this.activeMaxSize = this.getMaximumSize();;
34608 var c1 = size - this.activeMinSize;
34609 var c2 = Math.max(this.activeMaxSize - size, 0);
34610 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34611 this.dd.resetConstraints();
34612 this.dd.setXConstraint(
34613 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34614 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34616 this.dd.setYConstraint(0, 0);
34618 this.dd.resetConstraints();
34619 this.dd.setXConstraint(0, 0);
34620 this.dd.setYConstraint(
34621 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34622 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34625 this.dragSpecs.startSize = size;
34626 this.dragSpecs.startPoint = [x, y];
34627 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34631 * @private Called after the drag operation by the DDProxy
34633 onEndProxyDrag : function(e){
34634 Roo.get(this.proxy).setDisplayed(false);
34635 var endPoint = Roo.lib.Event.getXY(e);
34637 this.overlay.hide();
34640 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34641 newSize = this.dragSpecs.startSize +
34642 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34643 endPoint[0] - this.dragSpecs.startPoint[0] :
34644 this.dragSpecs.startPoint[0] - endPoint[0]
34647 newSize = this.dragSpecs.startSize +
34648 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34649 endPoint[1] - this.dragSpecs.startPoint[1] :
34650 this.dragSpecs.startPoint[1] - endPoint[1]
34653 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34654 if(newSize != this.dragSpecs.startSize){
34655 if(this.fireEvent('beforeapply', this, newSize) !== false){
34656 this.adapter.setElementSize(this, newSize);
34657 this.fireEvent("moved", this, newSize);
34658 this.fireEvent("resize", this, newSize);
34664 * Get the adapter this SplitBar uses
34665 * @return The adapter object
34667 getAdapter : function(){
34668 return this.adapter;
34672 * Set the adapter this SplitBar uses
34673 * @param {Object} adapter A SplitBar adapter object
34675 setAdapter : function(adapter){
34676 this.adapter = adapter;
34677 this.adapter.init(this);
34681 * Gets the minimum size for the resizing element
34682 * @return {Number} The minimum size
34684 getMinimumSize : function(){
34685 return this.minSize;
34689 * Sets the minimum size for the resizing element
34690 * @param {Number} minSize The minimum size
34692 setMinimumSize : function(minSize){
34693 this.minSize = minSize;
34697 * Gets the maximum size for the resizing element
34698 * @return {Number} The maximum size
34700 getMaximumSize : function(){
34701 return this.maxSize;
34705 * Sets the maximum size for the resizing element
34706 * @param {Number} maxSize The maximum size
34708 setMaximumSize : function(maxSize){
34709 this.maxSize = maxSize;
34713 * Sets the initialize size for the resizing element
34714 * @param {Number} size The initial size
34716 setCurrentSize : function(size){
34717 var oldAnimate = this.animate;
34718 this.animate = false;
34719 this.adapter.setElementSize(this, size);
34720 this.animate = oldAnimate;
34724 * Destroy this splitbar.
34725 * @param {Boolean} removeEl True to remove the element
34727 destroy : function(removeEl){
34729 this.shim.remove();
34732 this.proxy.parentNode.removeChild(this.proxy);
34740 * @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.
34742 Roo.bootstrap.SplitBar.createProxy = function(dir){
34743 var proxy = new Roo.Element(document.createElement("div"));
34744 proxy.unselectable();
34745 var cls = 'roo-splitbar-proxy';
34746 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34747 document.body.appendChild(proxy.dom);
34752 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34753 * Default Adapter. It assumes the splitter and resizing element are not positioned
34754 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34756 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34759 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34760 // do nothing for now
34761 init : function(s){
34765 * Called before drag operations to get the current size of the resizing element.
34766 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34768 getElementSize : function(s){
34769 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34770 return s.resizingEl.getWidth();
34772 return s.resizingEl.getHeight();
34777 * Called after drag operations to set the size of the resizing element.
34778 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34779 * @param {Number} newSize The new size to set
34780 * @param {Function} onComplete A function to be invoked when resizing is complete
34782 setElementSize : function(s, newSize, onComplete){
34783 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34785 s.resizingEl.setWidth(newSize);
34787 onComplete(s, newSize);
34790 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34795 s.resizingEl.setHeight(newSize);
34797 onComplete(s, newSize);
34800 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34807 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34808 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34809 * Adapter that moves the splitter element to align with the resized sizing element.
34810 * Used with an absolute positioned SplitBar.
34811 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34812 * document.body, make sure you assign an id to the body element.
34814 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34815 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34816 this.container = Roo.get(container);
34819 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34820 init : function(s){
34821 this.basic.init(s);
34824 getElementSize : function(s){
34825 return this.basic.getElementSize(s);
34828 setElementSize : function(s, newSize, onComplete){
34829 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34832 moveSplitter : function(s){
34833 var yes = Roo.bootstrap.SplitBar;
34834 switch(s.placement){
34836 s.el.setX(s.resizingEl.getRight());
34839 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34842 s.el.setY(s.resizingEl.getBottom());
34845 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34852 * Orientation constant - Create a vertical SplitBar
34856 Roo.bootstrap.SplitBar.VERTICAL = 1;
34859 * Orientation constant - Create a horizontal SplitBar
34863 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34866 * Placement constant - The resizing element is to the left of the splitter element
34870 Roo.bootstrap.SplitBar.LEFT = 1;
34873 * Placement constant - The resizing element is to the right of the splitter element
34877 Roo.bootstrap.SplitBar.RIGHT = 2;
34880 * Placement constant - The resizing element is positioned above the splitter element
34884 Roo.bootstrap.SplitBar.TOP = 3;
34887 * Placement constant - The resizing element is positioned under splitter element
34891 Roo.bootstrap.SplitBar.BOTTOM = 4;
34892 Roo.namespace("Roo.bootstrap.layout");/*
34894 * Ext JS Library 1.1.1
34895 * Copyright(c) 2006-2007, Ext JS, LLC.
34897 * Originally Released Under LGPL - original licence link has changed is not relivant.
34900 * <script type="text/javascript">
34904 * @class Roo.bootstrap.layout.Manager
34905 * @extends Roo.bootstrap.Component
34906 * Base class for layout managers.
34908 Roo.bootstrap.layout.Manager = function(config)
34910 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34916 /** false to disable window resize monitoring @type Boolean */
34917 this.monitorWindowResize = true;
34922 * Fires when a layout is performed.
34923 * @param {Roo.LayoutManager} this
34927 * @event regionresized
34928 * Fires when the user resizes a region.
34929 * @param {Roo.LayoutRegion} region The resized region
34930 * @param {Number} newSize The new size (width for east/west, height for north/south)
34932 "regionresized" : true,
34934 * @event regioncollapsed
34935 * Fires when a region is collapsed.
34936 * @param {Roo.LayoutRegion} region The collapsed region
34938 "regioncollapsed" : true,
34940 * @event regionexpanded
34941 * Fires when a region is expanded.
34942 * @param {Roo.LayoutRegion} region The expanded region
34944 "regionexpanded" : true
34946 this.updating = false;
34949 this.el = Roo.get(config.el);
34955 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34960 monitorWindowResize : true,
34966 onRender : function(ct, position)
34969 this.el = Roo.get(ct);
34972 //this.fireEvent('render',this);
34976 initEvents: function()
34980 // ie scrollbar fix
34981 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
34982 document.body.scroll = "no";
34983 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
34984 this.el.position('relative');
34986 this.id = this.el.id;
34987 this.el.addClass("roo-layout-container");
34988 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34989 if(this.el.dom != document.body ) {
34990 this.el.on('resize', this.layout,this);
34991 this.el.on('show', this.layout,this);
34997 * Returns true if this layout is currently being updated
34998 * @return {Boolean}
35000 isUpdating : function(){
35001 return this.updating;
35005 * Suspend the LayoutManager from doing auto-layouts while
35006 * making multiple add or remove calls
35008 beginUpdate : function(){
35009 this.updating = true;
35013 * Restore auto-layouts and optionally disable the manager from performing a layout
35014 * @param {Boolean} noLayout true to disable a layout update
35016 endUpdate : function(noLayout){
35017 this.updating = false;
35023 layout: function(){
35027 onRegionResized : function(region, newSize){
35028 this.fireEvent("regionresized", region, newSize);
35032 onRegionCollapsed : function(region){
35033 this.fireEvent("regioncollapsed", region);
35036 onRegionExpanded : function(region){
35037 this.fireEvent("regionexpanded", region);
35041 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35042 * performs box-model adjustments.
35043 * @return {Object} The size as an object {width: (the width), height: (the height)}
35045 getViewSize : function()
35048 if(this.el.dom != document.body){
35049 size = this.el.getSize();
35051 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35053 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35054 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35059 * Returns the Element this layout is bound to.
35060 * @return {Roo.Element}
35062 getEl : function(){
35067 * Returns the specified region.
35068 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35069 * @return {Roo.LayoutRegion}
35071 getRegion : function(target){
35072 return this.regions[target.toLowerCase()];
35075 onWindowResize : function(){
35076 if(this.monitorWindowResize){
35083 * Ext JS Library 1.1.1
35084 * Copyright(c) 2006-2007, Ext JS, LLC.
35086 * Originally Released Under LGPL - original licence link has changed is not relivant.
35089 * <script type="text/javascript">
35092 * @class Roo.bootstrap.layout.Border
35093 * @extends Roo.bootstrap.layout.Manager
35094 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35095 * please see: examples/bootstrap/nested.html<br><br>
35097 <b>The container the layout is rendered into can be either the body element or any other element.
35098 If it is not the body element, the container needs to either be an absolute positioned element,
35099 or you will need to add "position:relative" to the css of the container. You will also need to specify
35100 the container size if it is not the body element.</b>
35103 * Create a new Border
35104 * @param {Object} config Configuration options
35106 Roo.bootstrap.layout.Border = function(config){
35107 config = config || {};
35108 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35112 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35113 if(config[region]){
35114 config[region].region = region;
35115 this.addRegion(config[region]);
35121 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35123 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35125 parent : false, // this might point to a 'nest' or a ???
35128 * Creates and adds a new region if it doesn't already exist.
35129 * @param {String} target The target region key (north, south, east, west or center).
35130 * @param {Object} config The regions config object
35131 * @return {BorderLayoutRegion} The new region
35133 addRegion : function(config)
35135 if(!this.regions[config.region]){
35136 var r = this.factory(config);
35137 this.bindRegion(r);
35139 return this.regions[config.region];
35143 bindRegion : function(r){
35144 this.regions[r.config.region] = r;
35146 r.on("visibilitychange", this.layout, this);
35147 r.on("paneladded", this.layout, this);
35148 r.on("panelremoved", this.layout, this);
35149 r.on("invalidated", this.layout, this);
35150 r.on("resized", this.onRegionResized, this);
35151 r.on("collapsed", this.onRegionCollapsed, this);
35152 r.on("expanded", this.onRegionExpanded, this);
35156 * Performs a layout update.
35158 layout : function()
35160 if(this.updating) {
35164 // render all the rebions if they have not been done alreayd?
35165 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35166 if(this.regions[region] && !this.regions[region].bodyEl){
35167 this.regions[region].onRender(this.el)
35171 var size = this.getViewSize();
35172 var w = size.width;
35173 var h = size.height;
35178 //var x = 0, y = 0;
35180 var rs = this.regions;
35181 var north = rs["north"];
35182 var south = rs["south"];
35183 var west = rs["west"];
35184 var east = rs["east"];
35185 var center = rs["center"];
35186 //if(this.hideOnLayout){ // not supported anymore
35187 //c.el.setStyle("display", "none");
35189 if(north && north.isVisible()){
35190 var b = north.getBox();
35191 var m = north.getMargins();
35192 b.width = w - (m.left+m.right);
35195 centerY = b.height + b.y + m.bottom;
35196 centerH -= centerY;
35197 north.updateBox(this.safeBox(b));
35199 if(south && south.isVisible()){
35200 var b = south.getBox();
35201 var m = south.getMargins();
35202 b.width = w - (m.left+m.right);
35204 var totalHeight = (b.height + m.top + m.bottom);
35205 b.y = h - totalHeight + m.top;
35206 centerH -= totalHeight;
35207 south.updateBox(this.safeBox(b));
35209 if(west && west.isVisible()){
35210 var b = west.getBox();
35211 var m = west.getMargins();
35212 b.height = centerH - (m.top+m.bottom);
35214 b.y = centerY + m.top;
35215 var totalWidth = (b.width + m.left + m.right);
35216 centerX += totalWidth;
35217 centerW -= totalWidth;
35218 west.updateBox(this.safeBox(b));
35220 if(east && east.isVisible()){
35221 var b = east.getBox();
35222 var m = east.getMargins();
35223 b.height = centerH - (m.top+m.bottom);
35224 var totalWidth = (b.width + m.left + m.right);
35225 b.x = w - totalWidth + m.left;
35226 b.y = centerY + m.top;
35227 centerW -= totalWidth;
35228 east.updateBox(this.safeBox(b));
35231 var m = center.getMargins();
35233 x: centerX + m.left,
35234 y: centerY + m.top,
35235 width: centerW - (m.left+m.right),
35236 height: centerH - (m.top+m.bottom)
35238 //if(this.hideOnLayout){
35239 //center.el.setStyle("display", "block");
35241 center.updateBox(this.safeBox(centerBox));
35244 this.fireEvent("layout", this);
35248 safeBox : function(box){
35249 box.width = Math.max(0, box.width);
35250 box.height = Math.max(0, box.height);
35255 * Adds a ContentPanel (or subclass) to this layout.
35256 * @param {String} target The target region key (north, south, east, west or center).
35257 * @param {Roo.ContentPanel} panel The panel to add
35258 * @return {Roo.ContentPanel} The added panel
35260 add : function(target, panel){
35262 target = target.toLowerCase();
35263 return this.regions[target].add(panel);
35267 * Remove a ContentPanel (or subclass) to this layout.
35268 * @param {String} target The target region key (north, south, east, west or center).
35269 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35270 * @return {Roo.ContentPanel} The removed panel
35272 remove : function(target, panel){
35273 target = target.toLowerCase();
35274 return this.regions[target].remove(panel);
35278 * Searches all regions for a panel with the specified id
35279 * @param {String} panelId
35280 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35282 findPanel : function(panelId){
35283 var rs = this.regions;
35284 for(var target in rs){
35285 if(typeof rs[target] != "function"){
35286 var p = rs[target].getPanel(panelId);
35296 * Searches all regions for a panel with the specified id and activates (shows) it.
35297 * @param {String/ContentPanel} panelId The panels id or the panel itself
35298 * @return {Roo.ContentPanel} The shown panel or null
35300 showPanel : function(panelId) {
35301 var rs = this.regions;
35302 for(var target in rs){
35303 var r = rs[target];
35304 if(typeof r != "function"){
35305 if(r.hasPanel(panelId)){
35306 return r.showPanel(panelId);
35314 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35315 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35318 restoreState : function(provider){
35320 provider = Roo.state.Manager;
35322 var sm = new Roo.LayoutStateManager();
35323 sm.init(this, provider);
35329 * Adds a xtype elements to the layout.
35333 xtype : 'ContentPanel',
35340 xtype : 'NestedLayoutPanel',
35346 items : [ ... list of content panels or nested layout panels.. ]
35350 * @param {Object} cfg Xtype definition of item to add.
35352 addxtype : function(cfg)
35354 // basically accepts a pannel...
35355 // can accept a layout region..!?!?
35356 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35359 // theory? children can only be panels??
35361 //if (!cfg.xtype.match(/Panel$/)) {
35366 if (typeof(cfg.region) == 'undefined') {
35367 Roo.log("Failed to add Panel, region was not set");
35371 var region = cfg.region;
35377 xitems = cfg.items;
35382 if ( region == 'center') {
35383 Roo.log("Center: " + cfg.title);
35389 case 'Content': // ContentPanel (el, cfg)
35390 case 'Scroll': // ContentPanel (el, cfg)
35392 cfg.autoCreate = cfg.autoCreate || true;
35393 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35395 // var el = this.el.createChild();
35396 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35399 this.add(region, ret);
35403 case 'TreePanel': // our new panel!
35404 cfg.el = this.el.createChild();
35405 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35406 this.add(region, ret);
35411 // create a new Layout (which is a Border Layout...
35413 var clayout = cfg.layout;
35414 clayout.el = this.el.createChild();
35415 clayout.items = clayout.items || [];
35419 // replace this exitems with the clayout ones..
35420 xitems = clayout.items;
35422 // force background off if it's in center...
35423 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35424 cfg.background = false;
35426 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35429 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35430 //console.log('adding nested layout panel ' + cfg.toSource());
35431 this.add(region, ret);
35432 nb = {}; /// find first...
35437 // needs grid and region
35439 //var el = this.getRegion(region).el.createChild();
35441 *var el = this.el.createChild();
35442 // create the grid first...
35443 cfg.grid.container = el;
35444 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35447 if (region == 'center' && this.active ) {
35448 cfg.background = false;
35451 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35453 this.add(region, ret);
35455 if (cfg.background) {
35456 // render grid on panel activation (if panel background)
35457 ret.on('activate', function(gp) {
35458 if (!gp.grid.rendered) {
35459 // gp.grid.render(el);
35463 // cfg.grid.render(el);
35469 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35470 // it was the old xcomponent building that caused this before.
35471 // espeically if border is the top element in the tree.
35481 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35483 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35484 this.add(region, ret);
35488 throw "Can not add '" + cfg.xtype + "' to Border";
35494 this.beginUpdate();
35498 Roo.each(xitems, function(i) {
35499 region = nb && i.region ? i.region : false;
35501 var add = ret.addxtype(i);
35504 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35505 if (!i.background) {
35506 abn[region] = nb[region] ;
35513 // make the last non-background panel active..
35514 //if (nb) { Roo.log(abn); }
35517 for(var r in abn) {
35518 region = this.getRegion(r);
35520 // tried using nb[r], but it does not work..
35522 region.showPanel(abn[r]);
35533 factory : function(cfg)
35536 var validRegions = Roo.bootstrap.layout.Border.regions;
35538 var target = cfg.region;
35541 var r = Roo.bootstrap.layout;
35545 return new r.North(cfg);
35547 return new r.South(cfg);
35549 return new r.East(cfg);
35551 return new r.West(cfg);
35553 return new r.Center(cfg);
35555 throw 'Layout region "'+target+'" not supported.';
35562 * Ext JS Library 1.1.1
35563 * Copyright(c) 2006-2007, Ext JS, LLC.
35565 * Originally Released Under LGPL - original licence link has changed is not relivant.
35568 * <script type="text/javascript">
35572 * @class Roo.bootstrap.layout.Basic
35573 * @extends Roo.util.Observable
35574 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35575 * and does not have a titlebar, tabs or any other features. All it does is size and position
35576 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35577 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35578 * @cfg {string} region the region that it inhabits..
35579 * @cfg {bool} skipConfig skip config?
35583 Roo.bootstrap.layout.Basic = function(config){
35585 this.mgr = config.mgr;
35587 this.position = config.region;
35589 var skipConfig = config.skipConfig;
35593 * @scope Roo.BasicLayoutRegion
35597 * @event beforeremove
35598 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35599 * @param {Roo.LayoutRegion} this
35600 * @param {Roo.ContentPanel} panel The panel
35601 * @param {Object} e The cancel event object
35603 "beforeremove" : true,
35605 * @event invalidated
35606 * Fires when the layout for this region is changed.
35607 * @param {Roo.LayoutRegion} this
35609 "invalidated" : true,
35611 * @event visibilitychange
35612 * Fires when this region is shown or hidden
35613 * @param {Roo.LayoutRegion} this
35614 * @param {Boolean} visibility true or false
35616 "visibilitychange" : true,
35618 * @event paneladded
35619 * Fires when a panel is added.
35620 * @param {Roo.LayoutRegion} this
35621 * @param {Roo.ContentPanel} panel The panel
35623 "paneladded" : true,
35625 * @event panelremoved
35626 * Fires when a panel is removed.
35627 * @param {Roo.LayoutRegion} this
35628 * @param {Roo.ContentPanel} panel The panel
35630 "panelremoved" : true,
35632 * @event beforecollapse
35633 * Fires when this region before collapse.
35634 * @param {Roo.LayoutRegion} this
35636 "beforecollapse" : true,
35639 * Fires when this region is collapsed.
35640 * @param {Roo.LayoutRegion} this
35642 "collapsed" : true,
35645 * Fires when this region is expanded.
35646 * @param {Roo.LayoutRegion} this
35651 * Fires when this region is slid into view.
35652 * @param {Roo.LayoutRegion} this
35654 "slideshow" : true,
35657 * Fires when this region slides out of view.
35658 * @param {Roo.LayoutRegion} this
35660 "slidehide" : true,
35662 * @event panelactivated
35663 * Fires when a panel is activated.
35664 * @param {Roo.LayoutRegion} this
35665 * @param {Roo.ContentPanel} panel The activated panel
35667 "panelactivated" : true,
35670 * Fires when the user resizes this region.
35671 * @param {Roo.LayoutRegion} this
35672 * @param {Number} newSize The new size (width for east/west, height for north/south)
35676 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35677 this.panels = new Roo.util.MixedCollection();
35678 this.panels.getKey = this.getPanelId.createDelegate(this);
35680 this.activePanel = null;
35681 // ensure listeners are added...
35683 if (config.listeners || config.events) {
35684 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35685 listeners : config.listeners || {},
35686 events : config.events || {}
35690 if(skipConfig !== true){
35691 this.applyConfig(config);
35695 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35697 getPanelId : function(p){
35701 applyConfig : function(config){
35702 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35703 this.config = config;
35708 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35709 * the width, for horizontal (north, south) the height.
35710 * @param {Number} newSize The new width or height
35712 resizeTo : function(newSize){
35713 var el = this.el ? this.el :
35714 (this.activePanel ? this.activePanel.getEl() : null);
35716 switch(this.position){
35719 el.setWidth(newSize);
35720 this.fireEvent("resized", this, newSize);
35724 el.setHeight(newSize);
35725 this.fireEvent("resized", this, newSize);
35731 getBox : function(){
35732 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35735 getMargins : function(){
35736 return this.margins;
35739 updateBox : function(box){
35741 var el = this.activePanel.getEl();
35742 el.dom.style.left = box.x + "px";
35743 el.dom.style.top = box.y + "px";
35744 this.activePanel.setSize(box.width, box.height);
35748 * Returns the container element for this region.
35749 * @return {Roo.Element}
35751 getEl : function(){
35752 return this.activePanel;
35756 * Returns true if this region is currently visible.
35757 * @return {Boolean}
35759 isVisible : function(){
35760 return this.activePanel ? true : false;
35763 setActivePanel : function(panel){
35764 panel = this.getPanel(panel);
35765 if(this.activePanel && this.activePanel != panel){
35766 this.activePanel.setActiveState(false);
35767 this.activePanel.getEl().setLeftTop(-10000,-10000);
35769 this.activePanel = panel;
35770 panel.setActiveState(true);
35772 panel.setSize(this.box.width, this.box.height);
35774 this.fireEvent("panelactivated", this, panel);
35775 this.fireEvent("invalidated");
35779 * Show the specified panel.
35780 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35781 * @return {Roo.ContentPanel} The shown panel or null
35783 showPanel : function(panel){
35784 panel = this.getPanel(panel);
35786 this.setActivePanel(panel);
35792 * Get the active panel for this region.
35793 * @return {Roo.ContentPanel} The active panel or null
35795 getActivePanel : function(){
35796 return this.activePanel;
35800 * Add the passed ContentPanel(s)
35801 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35802 * @return {Roo.ContentPanel} The panel added (if only one was added)
35804 add : function(panel){
35805 if(arguments.length > 1){
35806 for(var i = 0, len = arguments.length; i < len; i++) {
35807 this.add(arguments[i]);
35811 if(this.hasPanel(panel)){
35812 this.showPanel(panel);
35815 var el = panel.getEl();
35816 if(el.dom.parentNode != this.mgr.el.dom){
35817 this.mgr.el.dom.appendChild(el.dom);
35819 if(panel.setRegion){
35820 panel.setRegion(this);
35822 this.panels.add(panel);
35823 el.setStyle("position", "absolute");
35824 if(!panel.background){
35825 this.setActivePanel(panel);
35826 if(this.config.initialSize && this.panels.getCount()==1){
35827 this.resizeTo(this.config.initialSize);
35830 this.fireEvent("paneladded", this, panel);
35835 * Returns true if the panel is in this region.
35836 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35837 * @return {Boolean}
35839 hasPanel : function(panel){
35840 if(typeof panel == "object"){ // must be panel obj
35841 panel = panel.getId();
35843 return this.getPanel(panel) ? true : false;
35847 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35848 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35849 * @param {Boolean} preservePanel Overrides the config preservePanel option
35850 * @return {Roo.ContentPanel} The panel that was removed
35852 remove : function(panel, preservePanel){
35853 panel = this.getPanel(panel);
35858 this.fireEvent("beforeremove", this, panel, e);
35859 if(e.cancel === true){
35862 var panelId = panel.getId();
35863 this.panels.removeKey(panelId);
35868 * Returns the panel specified or null if it's not in this region.
35869 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35870 * @return {Roo.ContentPanel}
35872 getPanel : function(id){
35873 if(typeof id == "object"){ // must be panel obj
35876 return this.panels.get(id);
35880 * Returns this regions position (north/south/east/west/center).
35883 getPosition: function(){
35884 return this.position;
35888 * Ext JS Library 1.1.1
35889 * Copyright(c) 2006-2007, Ext JS, LLC.
35891 * Originally Released Under LGPL - original licence link has changed is not relivant.
35894 * <script type="text/javascript">
35898 * @class Roo.bootstrap.layout.Region
35899 * @extends Roo.bootstrap.layout.Basic
35900 * This class represents a region in a layout manager.
35902 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35903 * @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})
35904 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35905 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35906 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35907 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35908 * @cfg {String} title The title for the region (overrides panel titles)
35909 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35910 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35911 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35912 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35913 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35914 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35915 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35916 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35917 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35918 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35920 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35921 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35922 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35923 * @cfg {Number} width For East/West panels
35924 * @cfg {Number} height For North/South panels
35925 * @cfg {Boolean} split To show the splitter
35926 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35928 * @cfg {string} cls Extra CSS classes to add to region
35930 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35931 * @cfg {string} region the region that it inhabits..
35934 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35935 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35937 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35938 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35939 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35941 Roo.bootstrap.layout.Region = function(config)
35943 this.applyConfig(config);
35945 var mgr = config.mgr;
35946 var pos = config.region;
35947 config.skipConfig = true;
35948 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35951 this.onRender(mgr.el);
35954 this.visible = true;
35955 this.collapsed = false;
35956 this.unrendered_panels = [];
35959 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35961 position: '', // set by wrapper (eg. north/south etc..)
35962 unrendered_panels : null, // unrendered panels.
35964 tabPosition : false,
35966 mgr: false, // points to 'Border'
35969 createBody : function(){
35970 /** This region's body element
35971 * @type Roo.Element */
35972 this.bodyEl = this.el.createChild({
35974 cls: "roo-layout-panel-body tab-content" // bootstrap added...
35978 onRender: function(ctr, pos)
35980 var dh = Roo.DomHelper;
35981 /** This region's container element
35982 * @type Roo.Element */
35983 this.el = dh.append(ctr.dom, {
35985 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
35987 /** This region's title element
35988 * @type Roo.Element */
35990 this.titleEl = dh.append(this.el.dom, {
35992 unselectable: "on",
35993 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
35995 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
35996 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36000 this.titleEl.enableDisplayMode();
36001 /** This region's title text element
36002 * @type HTMLElement */
36003 this.titleTextEl = this.titleEl.dom.firstChild;
36004 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36006 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36007 this.closeBtn.enableDisplayMode();
36008 this.closeBtn.on("click", this.closeClicked, this);
36009 this.closeBtn.hide();
36011 this.createBody(this.config);
36012 if(this.config.hideWhenEmpty){
36014 this.on("paneladded", this.validateVisibility, this);
36015 this.on("panelremoved", this.validateVisibility, this);
36017 if(this.autoScroll){
36018 this.bodyEl.setStyle("overflow", "auto");
36020 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36022 //if(c.titlebar !== false){
36023 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36024 this.titleEl.hide();
36026 this.titleEl.show();
36027 if(this.config.title){
36028 this.titleTextEl.innerHTML = this.config.title;
36032 if(this.config.collapsed){
36033 this.collapse(true);
36035 if(this.config.hidden){
36039 if (this.unrendered_panels && this.unrendered_panels.length) {
36040 for (var i =0;i< this.unrendered_panels.length; i++) {
36041 this.add(this.unrendered_panels[i]);
36043 this.unrendered_panels = null;
36049 applyConfig : function(c)
36052 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36053 var dh = Roo.DomHelper;
36054 if(c.titlebar !== false){
36055 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36056 this.collapseBtn.on("click", this.collapse, this);
36057 this.collapseBtn.enableDisplayMode();
36059 if(c.showPin === true || this.showPin){
36060 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36061 this.stickBtn.enableDisplayMode();
36062 this.stickBtn.on("click", this.expand, this);
36063 this.stickBtn.hide();
36068 /** This region's collapsed element
36069 * @type Roo.Element */
36072 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36073 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36076 if(c.floatable !== false){
36077 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36078 this.collapsedEl.on("click", this.collapseClick, this);
36081 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36082 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36083 id: "message", unselectable: "on", style:{"float":"left"}});
36084 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36086 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36087 this.expandBtn.on("click", this.expand, this);
36091 if(this.collapseBtn){
36092 this.collapseBtn.setVisible(c.collapsible == true);
36095 this.cmargins = c.cmargins || this.cmargins ||
36096 (this.position == "west" || this.position == "east" ?
36097 {top: 0, left: 2, right:2, bottom: 0} :
36098 {top: 2, left: 0, right:0, bottom: 2});
36100 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36103 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36105 this.autoScroll = c.autoScroll || false;
36110 this.duration = c.duration || .30;
36111 this.slideDuration = c.slideDuration || .45;
36116 * Returns true if this region is currently visible.
36117 * @return {Boolean}
36119 isVisible : function(){
36120 return this.visible;
36124 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36125 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36127 //setCollapsedTitle : function(title){
36128 // title = title || " ";
36129 // if(this.collapsedTitleTextEl){
36130 // this.collapsedTitleTextEl.innerHTML = title;
36134 getBox : function(){
36136 // if(!this.collapsed){
36137 b = this.el.getBox(false, true);
36139 // b = this.collapsedEl.getBox(false, true);
36144 getMargins : function(){
36145 return this.margins;
36146 //return this.collapsed ? this.cmargins : this.margins;
36149 highlight : function(){
36150 this.el.addClass("x-layout-panel-dragover");
36153 unhighlight : function(){
36154 this.el.removeClass("x-layout-panel-dragover");
36157 updateBox : function(box)
36159 if (!this.bodyEl) {
36160 return; // not rendered yet..
36164 if(!this.collapsed){
36165 this.el.dom.style.left = box.x + "px";
36166 this.el.dom.style.top = box.y + "px";
36167 this.updateBody(box.width, box.height);
36169 this.collapsedEl.dom.style.left = box.x + "px";
36170 this.collapsedEl.dom.style.top = box.y + "px";
36171 this.collapsedEl.setSize(box.width, box.height);
36174 this.tabs.autoSizeTabs();
36178 updateBody : function(w, h)
36181 this.el.setWidth(w);
36182 w -= this.el.getBorderWidth("rl");
36183 if(this.config.adjustments){
36184 w += this.config.adjustments[0];
36187 if(h !== null && h > 0){
36188 this.el.setHeight(h);
36189 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36190 h -= this.el.getBorderWidth("tb");
36191 if(this.config.adjustments){
36192 h += this.config.adjustments[1];
36194 this.bodyEl.setHeight(h);
36196 h = this.tabs.syncHeight(h);
36199 if(this.panelSize){
36200 w = w !== null ? w : this.panelSize.width;
36201 h = h !== null ? h : this.panelSize.height;
36203 if(this.activePanel){
36204 var el = this.activePanel.getEl();
36205 w = w !== null ? w : el.getWidth();
36206 h = h !== null ? h : el.getHeight();
36207 this.panelSize = {width: w, height: h};
36208 this.activePanel.setSize(w, h);
36210 if(Roo.isIE && this.tabs){
36211 this.tabs.el.repaint();
36216 * Returns the container element for this region.
36217 * @return {Roo.Element}
36219 getEl : function(){
36224 * Hides this region.
36227 //if(!this.collapsed){
36228 this.el.dom.style.left = "-2000px";
36231 // this.collapsedEl.dom.style.left = "-2000px";
36232 // this.collapsedEl.hide();
36234 this.visible = false;
36235 this.fireEvent("visibilitychange", this, false);
36239 * Shows this region if it was previously hidden.
36242 //if(!this.collapsed){
36245 // this.collapsedEl.show();
36247 this.visible = true;
36248 this.fireEvent("visibilitychange", this, true);
36251 closeClicked : function(){
36252 if(this.activePanel){
36253 this.remove(this.activePanel);
36257 collapseClick : function(e){
36259 e.stopPropagation();
36262 e.stopPropagation();
36268 * Collapses this region.
36269 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36272 collapse : function(skipAnim, skipCheck = false){
36273 if(this.collapsed) {
36277 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36279 this.collapsed = true;
36281 this.split.el.hide();
36283 if(this.config.animate && skipAnim !== true){
36284 this.fireEvent("invalidated", this);
36285 this.animateCollapse();
36287 this.el.setLocation(-20000,-20000);
36289 this.collapsedEl.show();
36290 this.fireEvent("collapsed", this);
36291 this.fireEvent("invalidated", this);
36297 animateCollapse : function(){
36302 * Expands this region if it was previously collapsed.
36303 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36304 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36307 expand : function(e, skipAnim){
36309 e.stopPropagation();
36311 if(!this.collapsed || this.el.hasActiveFx()) {
36315 this.afterSlideIn();
36318 this.collapsed = false;
36319 if(this.config.animate && skipAnim !== true){
36320 this.animateExpand();
36324 this.split.el.show();
36326 this.collapsedEl.setLocation(-2000,-2000);
36327 this.collapsedEl.hide();
36328 this.fireEvent("invalidated", this);
36329 this.fireEvent("expanded", this);
36333 animateExpand : function(){
36337 initTabs : function()
36339 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36341 var ts = new Roo.bootstrap.panel.Tabs({
36342 el: this.bodyEl.dom,
36344 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36345 disableTooltips: this.config.disableTabTips,
36346 toolbar : this.config.toolbar
36349 if(this.config.hideTabs){
36350 ts.stripWrap.setDisplayed(false);
36353 ts.resizeTabs = this.config.resizeTabs === true;
36354 ts.minTabWidth = this.config.minTabWidth || 40;
36355 ts.maxTabWidth = this.config.maxTabWidth || 250;
36356 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36357 ts.monitorResize = false;
36358 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36359 ts.bodyEl.addClass('roo-layout-tabs-body');
36360 this.panels.each(this.initPanelAsTab, this);
36363 initPanelAsTab : function(panel){
36364 var ti = this.tabs.addTab(
36368 this.config.closeOnTab && panel.isClosable(),
36371 if(panel.tabTip !== undefined){
36372 ti.setTooltip(panel.tabTip);
36374 ti.on("activate", function(){
36375 this.setActivePanel(panel);
36378 if(this.config.closeOnTab){
36379 ti.on("beforeclose", function(t, e){
36381 this.remove(panel);
36385 panel.tabItem = ti;
36390 updatePanelTitle : function(panel, title)
36392 if(this.activePanel == panel){
36393 this.updateTitle(title);
36396 var ti = this.tabs.getTab(panel.getEl().id);
36398 if(panel.tabTip !== undefined){
36399 ti.setTooltip(panel.tabTip);
36404 updateTitle : function(title){
36405 if(this.titleTextEl && !this.config.title){
36406 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36410 setActivePanel : function(panel)
36412 panel = this.getPanel(panel);
36413 if(this.activePanel && this.activePanel != panel){
36414 if(this.activePanel.setActiveState(false) === false){
36418 this.activePanel = panel;
36419 panel.setActiveState(true);
36420 if(this.panelSize){
36421 panel.setSize(this.panelSize.width, this.panelSize.height);
36424 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36426 this.updateTitle(panel.getTitle());
36428 this.fireEvent("invalidated", this);
36430 this.fireEvent("panelactivated", this, panel);
36434 * Shows the specified panel.
36435 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36436 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36438 showPanel : function(panel)
36440 panel = this.getPanel(panel);
36443 var tab = this.tabs.getTab(panel.getEl().id);
36444 if(tab.isHidden()){
36445 this.tabs.unhideTab(tab.id);
36449 this.setActivePanel(panel);
36456 * Get the active panel for this region.
36457 * @return {Roo.ContentPanel} The active panel or null
36459 getActivePanel : function(){
36460 return this.activePanel;
36463 validateVisibility : function(){
36464 if(this.panels.getCount() < 1){
36465 this.updateTitle(" ");
36466 this.closeBtn.hide();
36469 if(!this.isVisible()){
36476 * Adds the passed ContentPanel(s) to this region.
36477 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36478 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36480 add : function(panel)
36482 if(arguments.length > 1){
36483 for(var i = 0, len = arguments.length; i < len; i++) {
36484 this.add(arguments[i]);
36489 // if we have not been rendered yet, then we can not really do much of this..
36490 if (!this.bodyEl) {
36491 this.unrendered_panels.push(panel);
36498 if(this.hasPanel(panel)){
36499 this.showPanel(panel);
36502 panel.setRegion(this);
36503 this.panels.add(panel);
36504 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36505 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36506 // and hide them... ???
36507 this.bodyEl.dom.appendChild(panel.getEl().dom);
36508 if(panel.background !== true){
36509 this.setActivePanel(panel);
36511 this.fireEvent("paneladded", this, panel);
36518 this.initPanelAsTab(panel);
36522 if(panel.background !== true){
36523 this.tabs.activate(panel.getEl().id);
36525 this.fireEvent("paneladded", this, panel);
36530 * Hides the tab for the specified panel.
36531 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36533 hidePanel : function(panel){
36534 if(this.tabs && (panel = this.getPanel(panel))){
36535 this.tabs.hideTab(panel.getEl().id);
36540 * Unhides the tab for a previously hidden panel.
36541 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36543 unhidePanel : function(panel){
36544 if(this.tabs && (panel = this.getPanel(panel))){
36545 this.tabs.unhideTab(panel.getEl().id);
36549 clearPanels : function(){
36550 while(this.panels.getCount() > 0){
36551 this.remove(this.panels.first());
36556 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36557 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36558 * @param {Boolean} preservePanel Overrides the config preservePanel option
36559 * @return {Roo.ContentPanel} The panel that was removed
36561 remove : function(panel, preservePanel)
36563 panel = this.getPanel(panel);
36568 this.fireEvent("beforeremove", this, panel, e);
36569 if(e.cancel === true){
36572 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36573 var panelId = panel.getId();
36574 this.panels.removeKey(panelId);
36576 document.body.appendChild(panel.getEl().dom);
36579 this.tabs.removeTab(panel.getEl().id);
36580 }else if (!preservePanel){
36581 this.bodyEl.dom.removeChild(panel.getEl().dom);
36583 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36584 var p = this.panels.first();
36585 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36586 tempEl.appendChild(p.getEl().dom);
36587 this.bodyEl.update("");
36588 this.bodyEl.dom.appendChild(p.getEl().dom);
36590 this.updateTitle(p.getTitle());
36592 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36593 this.setActivePanel(p);
36595 panel.setRegion(null);
36596 if(this.activePanel == panel){
36597 this.activePanel = null;
36599 if(this.config.autoDestroy !== false && preservePanel !== true){
36600 try{panel.destroy();}catch(e){}
36602 this.fireEvent("panelremoved", this, panel);
36607 * Returns the TabPanel component used by this region
36608 * @return {Roo.TabPanel}
36610 getTabs : function(){
36614 createTool : function(parentEl, className){
36615 var btn = Roo.DomHelper.append(parentEl, {
36617 cls: "x-layout-tools-button",
36620 cls: "roo-layout-tools-button-inner " + className,
36624 btn.addClassOnOver("roo-layout-tools-button-over");
36629 * Ext JS Library 1.1.1
36630 * Copyright(c) 2006-2007, Ext JS, LLC.
36632 * Originally Released Under LGPL - original licence link has changed is not relivant.
36635 * <script type="text/javascript">
36641 * @class Roo.SplitLayoutRegion
36642 * @extends Roo.LayoutRegion
36643 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36645 Roo.bootstrap.layout.Split = function(config){
36646 this.cursor = config.cursor;
36647 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36650 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36652 splitTip : "Drag to resize.",
36653 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36654 useSplitTips : false,
36656 applyConfig : function(config){
36657 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36660 onRender : function(ctr,pos) {
36662 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36663 if(!this.config.split){
36668 var splitEl = Roo.DomHelper.append(ctr.dom, {
36670 id: this.el.id + "-split",
36671 cls: "roo-layout-split roo-layout-split-"+this.position,
36674 /** The SplitBar for this region
36675 * @type Roo.SplitBar */
36676 // does not exist yet...
36677 Roo.log([this.position, this.orientation]);
36679 this.split = new Roo.bootstrap.SplitBar({
36680 dragElement : splitEl,
36681 resizingElement: this.el,
36682 orientation : this.orientation
36685 this.split.on("moved", this.onSplitMove, this);
36686 this.split.useShim = this.config.useShim === true;
36687 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36688 if(this.useSplitTips){
36689 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36691 //if(config.collapsible){
36692 // this.split.el.on("dblclick", this.collapse, this);
36695 if(typeof this.config.minSize != "undefined"){
36696 this.split.minSize = this.config.minSize;
36698 if(typeof this.config.maxSize != "undefined"){
36699 this.split.maxSize = this.config.maxSize;
36701 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36702 this.hideSplitter();
36707 getHMaxSize : function(){
36708 var cmax = this.config.maxSize || 10000;
36709 var center = this.mgr.getRegion("center");
36710 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36713 getVMaxSize : function(){
36714 var cmax = this.config.maxSize || 10000;
36715 var center = this.mgr.getRegion("center");
36716 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36719 onSplitMove : function(split, newSize){
36720 this.fireEvent("resized", this, newSize);
36724 * Returns the {@link Roo.SplitBar} for this region.
36725 * @return {Roo.SplitBar}
36727 getSplitBar : function(){
36732 this.hideSplitter();
36733 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36736 hideSplitter : function(){
36738 this.split.el.setLocation(-2000,-2000);
36739 this.split.el.hide();
36745 this.split.el.show();
36747 Roo.bootstrap.layout.Split.superclass.show.call(this);
36750 beforeSlide: function(){
36751 if(Roo.isGecko){// firefox overflow auto bug workaround
36752 this.bodyEl.clip();
36754 this.tabs.bodyEl.clip();
36756 if(this.activePanel){
36757 this.activePanel.getEl().clip();
36759 if(this.activePanel.beforeSlide){
36760 this.activePanel.beforeSlide();
36766 afterSlide : function(){
36767 if(Roo.isGecko){// firefox overflow auto bug workaround
36768 this.bodyEl.unclip();
36770 this.tabs.bodyEl.unclip();
36772 if(this.activePanel){
36773 this.activePanel.getEl().unclip();
36774 if(this.activePanel.afterSlide){
36775 this.activePanel.afterSlide();
36781 initAutoHide : function(){
36782 if(this.autoHide !== false){
36783 if(!this.autoHideHd){
36784 var st = new Roo.util.DelayedTask(this.slideIn, this);
36785 this.autoHideHd = {
36786 "mouseout": function(e){
36787 if(!e.within(this.el, true)){
36791 "mouseover" : function(e){
36797 this.el.on(this.autoHideHd);
36801 clearAutoHide : function(){
36802 if(this.autoHide !== false){
36803 this.el.un("mouseout", this.autoHideHd.mouseout);
36804 this.el.un("mouseover", this.autoHideHd.mouseover);
36808 clearMonitor : function(){
36809 Roo.get(document).un("click", this.slideInIf, this);
36812 // these names are backwards but not changed for compat
36813 slideOut : function(){
36814 if(this.isSlid || this.el.hasActiveFx()){
36817 this.isSlid = true;
36818 if(this.collapseBtn){
36819 this.collapseBtn.hide();
36821 this.closeBtnState = this.closeBtn.getStyle('display');
36822 this.closeBtn.hide();
36824 this.stickBtn.show();
36827 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36828 this.beforeSlide();
36829 this.el.setStyle("z-index", 10001);
36830 this.el.slideIn(this.getSlideAnchor(), {
36831 callback: function(){
36833 this.initAutoHide();
36834 Roo.get(document).on("click", this.slideInIf, this);
36835 this.fireEvent("slideshow", this);
36842 afterSlideIn : function(){
36843 this.clearAutoHide();
36844 this.isSlid = false;
36845 this.clearMonitor();
36846 this.el.setStyle("z-index", "");
36847 if(this.collapseBtn){
36848 this.collapseBtn.show();
36850 this.closeBtn.setStyle('display', this.closeBtnState);
36852 this.stickBtn.hide();
36854 this.fireEvent("slidehide", this);
36857 slideIn : function(cb){
36858 if(!this.isSlid || this.el.hasActiveFx()){
36862 this.isSlid = false;
36863 this.beforeSlide();
36864 this.el.slideOut(this.getSlideAnchor(), {
36865 callback: function(){
36866 this.el.setLeftTop(-10000, -10000);
36868 this.afterSlideIn();
36876 slideInIf : function(e){
36877 if(!e.within(this.el)){
36882 animateCollapse : function(){
36883 this.beforeSlide();
36884 this.el.setStyle("z-index", 20000);
36885 var anchor = this.getSlideAnchor();
36886 this.el.slideOut(anchor, {
36887 callback : function(){
36888 this.el.setStyle("z-index", "");
36889 this.collapsedEl.slideIn(anchor, {duration:.3});
36891 this.el.setLocation(-10000,-10000);
36893 this.fireEvent("collapsed", this);
36900 animateExpand : function(){
36901 this.beforeSlide();
36902 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36903 this.el.setStyle("z-index", 20000);
36904 this.collapsedEl.hide({
36907 this.el.slideIn(this.getSlideAnchor(), {
36908 callback : function(){
36909 this.el.setStyle("z-index", "");
36912 this.split.el.show();
36914 this.fireEvent("invalidated", this);
36915 this.fireEvent("expanded", this);
36943 getAnchor : function(){
36944 return this.anchors[this.position];
36947 getCollapseAnchor : function(){
36948 return this.canchors[this.position];
36951 getSlideAnchor : function(){
36952 return this.sanchors[this.position];
36955 getAlignAdj : function(){
36956 var cm = this.cmargins;
36957 switch(this.position){
36973 getExpandAdj : function(){
36974 var c = this.collapsedEl, cm = this.cmargins;
36975 switch(this.position){
36977 return [-(cm.right+c.getWidth()+cm.left), 0];
36980 return [cm.right+c.getWidth()+cm.left, 0];
36983 return [0, -(cm.top+cm.bottom+c.getHeight())];
36986 return [0, cm.top+cm.bottom+c.getHeight()];
36992 * Ext JS Library 1.1.1
36993 * Copyright(c) 2006-2007, Ext JS, LLC.
36995 * Originally Released Under LGPL - original licence link has changed is not relivant.
36998 * <script type="text/javascript">
37001 * These classes are private internal classes
37003 Roo.bootstrap.layout.Center = function(config){
37004 config.region = "center";
37005 Roo.bootstrap.layout.Region.call(this, config);
37006 this.visible = true;
37007 this.minWidth = config.minWidth || 20;
37008 this.minHeight = config.minHeight || 20;
37011 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37013 // center panel can't be hidden
37017 // center panel can't be hidden
37020 getMinWidth: function(){
37021 return this.minWidth;
37024 getMinHeight: function(){
37025 return this.minHeight;
37039 Roo.bootstrap.layout.North = function(config)
37041 config.region = 'north';
37042 config.cursor = 'n-resize';
37044 Roo.bootstrap.layout.Split.call(this, config);
37048 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37049 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37050 this.split.el.addClass("roo-layout-split-v");
37052 var size = config.initialSize || config.height;
37053 if(typeof size != "undefined"){
37054 this.el.setHeight(size);
37057 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37059 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37063 getBox : function(){
37064 if(this.collapsed){
37065 return this.collapsedEl.getBox();
37067 var box = this.el.getBox();
37069 box.height += this.split.el.getHeight();
37074 updateBox : function(box){
37075 if(this.split && !this.collapsed){
37076 box.height -= this.split.el.getHeight();
37077 this.split.el.setLeft(box.x);
37078 this.split.el.setTop(box.y+box.height);
37079 this.split.el.setWidth(box.width);
37081 if(this.collapsed){
37082 this.updateBody(box.width, null);
37084 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37092 Roo.bootstrap.layout.South = function(config){
37093 config.region = 'south';
37094 config.cursor = 's-resize';
37095 Roo.bootstrap.layout.Split.call(this, config);
37097 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37098 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37099 this.split.el.addClass("roo-layout-split-v");
37101 var size = config.initialSize || config.height;
37102 if(typeof size != "undefined"){
37103 this.el.setHeight(size);
37107 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37108 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37109 getBox : function(){
37110 if(this.collapsed){
37111 return this.collapsedEl.getBox();
37113 var box = this.el.getBox();
37115 var sh = this.split.el.getHeight();
37122 updateBox : function(box){
37123 if(this.split && !this.collapsed){
37124 var sh = this.split.el.getHeight();
37127 this.split.el.setLeft(box.x);
37128 this.split.el.setTop(box.y-sh);
37129 this.split.el.setWidth(box.width);
37131 if(this.collapsed){
37132 this.updateBody(box.width, null);
37134 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37138 Roo.bootstrap.layout.East = function(config){
37139 config.region = "east";
37140 config.cursor = "e-resize";
37141 Roo.bootstrap.layout.Split.call(this, config);
37143 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37144 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37145 this.split.el.addClass("roo-layout-split-h");
37147 var size = config.initialSize || config.width;
37148 if(typeof size != "undefined"){
37149 this.el.setWidth(size);
37152 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37153 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37154 getBox : function(){
37155 if(this.collapsed){
37156 return this.collapsedEl.getBox();
37158 var box = this.el.getBox();
37160 var sw = this.split.el.getWidth();
37167 updateBox : function(box){
37168 if(this.split && !this.collapsed){
37169 var sw = this.split.el.getWidth();
37171 this.split.el.setLeft(box.x);
37172 this.split.el.setTop(box.y);
37173 this.split.el.setHeight(box.height);
37176 if(this.collapsed){
37177 this.updateBody(null, box.height);
37179 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37183 Roo.bootstrap.layout.West = function(config){
37184 config.region = "west";
37185 config.cursor = "w-resize";
37187 Roo.bootstrap.layout.Split.call(this, config);
37189 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37190 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37191 this.split.el.addClass("roo-layout-split-h");
37195 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37196 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37198 onRender: function(ctr, pos)
37200 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37201 var size = this.config.initialSize || this.config.width;
37202 if(typeof size != "undefined"){
37203 this.el.setWidth(size);
37207 getBox : function(){
37208 if(this.collapsed){
37209 return this.collapsedEl.getBox();
37211 var box = this.el.getBox();
37213 box.width += this.split.el.getWidth();
37218 updateBox : function(box){
37219 if(this.split && !this.collapsed){
37220 var sw = this.split.el.getWidth();
37222 this.split.el.setLeft(box.x+box.width);
37223 this.split.el.setTop(box.y);
37224 this.split.el.setHeight(box.height);
37226 if(this.collapsed){
37227 this.updateBody(null, box.height);
37229 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37231 });Roo.namespace("Roo.bootstrap.panel");/*
37233 * Ext JS Library 1.1.1
37234 * Copyright(c) 2006-2007, Ext JS, LLC.
37236 * Originally Released Under LGPL - original licence link has changed is not relivant.
37239 * <script type="text/javascript">
37242 * @class Roo.ContentPanel
37243 * @extends Roo.util.Observable
37244 * A basic ContentPanel element.
37245 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37246 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37247 * @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
37248 * @cfg {Boolean} closable True if the panel can be closed/removed
37249 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37250 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37251 * @cfg {Toolbar} toolbar A toolbar for this panel
37252 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37253 * @cfg {String} title The title for this panel
37254 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37255 * @cfg {String} url Calls {@link #setUrl} with this value
37256 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37257 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37258 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37259 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37260 * @cfg {Boolean} badges render the badges
37263 * Create a new ContentPanel.
37264 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37265 * @param {String/Object} config A string to set only the title or a config object
37266 * @param {String} content (optional) Set the HTML content for this panel
37267 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37269 Roo.bootstrap.panel.Content = function( config){
37271 this.tpl = config.tpl || false;
37273 var el = config.el;
37274 var content = config.content;
37276 if(config.autoCreate){ // xtype is available if this is called from factory
37279 this.el = Roo.get(el);
37280 if(!this.el && config && config.autoCreate){
37281 if(typeof config.autoCreate == "object"){
37282 if(!config.autoCreate.id){
37283 config.autoCreate.id = config.id||el;
37285 this.el = Roo.DomHelper.append(document.body,
37286 config.autoCreate, true);
37288 var elcfg = { tag: "div",
37289 cls: "roo-layout-inactive-content",
37293 elcfg.html = config.html;
37297 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37300 this.closable = false;
37301 this.loaded = false;
37302 this.active = false;
37305 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37307 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37309 this.wrapEl = this.el; //this.el.wrap();
37311 if (config.toolbar.items) {
37312 ti = config.toolbar.items ;
37313 delete config.toolbar.items ;
37317 this.toolbar.render(this.wrapEl, 'before');
37318 for(var i =0;i < ti.length;i++) {
37319 // Roo.log(['add child', items[i]]);
37320 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37322 this.toolbar.items = nitems;
37323 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37324 delete config.toolbar;
37328 // xtype created footer. - not sure if will work as we normally have to render first..
37329 if (this.footer && !this.footer.el && this.footer.xtype) {
37330 if (!this.wrapEl) {
37331 this.wrapEl = this.el.wrap();
37334 this.footer.container = this.wrapEl.createChild();
37336 this.footer = Roo.factory(this.footer, Roo);
37341 if(typeof config == "string"){
37342 this.title = config;
37344 Roo.apply(this, config);
37348 this.resizeEl = Roo.get(this.resizeEl, true);
37350 this.resizeEl = this.el;
37352 // handle view.xtype
37360 * Fires when this panel is activated.
37361 * @param {Roo.ContentPanel} this
37365 * @event deactivate
37366 * Fires when this panel is activated.
37367 * @param {Roo.ContentPanel} this
37369 "deactivate" : true,
37373 * Fires when this panel is resized if fitToFrame is true.
37374 * @param {Roo.ContentPanel} this
37375 * @param {Number} width The width after any component adjustments
37376 * @param {Number} height The height after any component adjustments
37382 * Fires when this tab is created
37383 * @param {Roo.ContentPanel} this
37394 if(this.autoScroll){
37395 this.resizeEl.setStyle("overflow", "auto");
37397 // fix randome scrolling
37398 //this.el.on('scroll', function() {
37399 // Roo.log('fix random scolling');
37400 // this.scrollTo('top',0);
37403 content = content || this.content;
37405 this.setContent(content);
37407 if(config && config.url){
37408 this.setUrl(this.url, this.params, this.loadOnce);
37413 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37415 if (this.view && typeof(this.view.xtype) != 'undefined') {
37416 this.view.el = this.el.appendChild(document.createElement("div"));
37417 this.view = Roo.factory(this.view);
37418 this.view.render && this.view.render(false, '');
37422 this.fireEvent('render', this);
37425 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37429 setRegion : function(region){
37430 this.region = region;
37431 this.setActiveClass(region && !this.background);
37435 setActiveClass: function(state)
37438 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37439 this.el.setStyle('position','relative');
37441 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37442 this.el.setStyle('position', 'absolute');
37447 * Returns the toolbar for this Panel if one was configured.
37448 * @return {Roo.Toolbar}
37450 getToolbar : function(){
37451 return this.toolbar;
37454 setActiveState : function(active)
37456 this.active = active;
37457 this.setActiveClass(active);
37459 if(this.fireEvent("deactivate", this) === false){
37464 this.fireEvent("activate", this);
37468 * Updates this panel's element
37469 * @param {String} content The new content
37470 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37472 setContent : function(content, loadScripts){
37473 this.el.update(content, loadScripts);
37476 ignoreResize : function(w, h){
37477 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37480 this.lastSize = {width: w, height: h};
37485 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37486 * @return {Roo.UpdateManager} The UpdateManager
37488 getUpdateManager : function(){
37489 return this.el.getUpdateManager();
37492 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37493 * @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:
37496 url: "your-url.php",
37497 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37498 callback: yourFunction,
37499 scope: yourObject, //(optional scope)
37502 text: "Loading...",
37507 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37508 * 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.
37509 * @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}
37510 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37511 * @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.
37512 * @return {Roo.ContentPanel} this
37515 var um = this.el.getUpdateManager();
37516 um.update.apply(um, arguments);
37522 * 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.
37523 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37524 * @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)
37525 * @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)
37526 * @return {Roo.UpdateManager} The UpdateManager
37528 setUrl : function(url, params, loadOnce){
37529 if(this.refreshDelegate){
37530 this.removeListener("activate", this.refreshDelegate);
37532 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37533 this.on("activate", this.refreshDelegate);
37534 return this.el.getUpdateManager();
37537 _handleRefresh : function(url, params, loadOnce){
37538 if(!loadOnce || !this.loaded){
37539 var updater = this.el.getUpdateManager();
37540 updater.update(url, params, this._setLoaded.createDelegate(this));
37544 _setLoaded : function(){
37545 this.loaded = true;
37549 * Returns this panel's id
37552 getId : function(){
37557 * Returns this panel's element - used by regiosn to add.
37558 * @return {Roo.Element}
37560 getEl : function(){
37561 return this.wrapEl || this.el;
37566 adjustForComponents : function(width, height)
37568 //Roo.log('adjustForComponents ');
37569 if(this.resizeEl != this.el){
37570 width -= this.el.getFrameWidth('lr');
37571 height -= this.el.getFrameWidth('tb');
37574 var te = this.toolbar.getEl();
37575 te.setWidth(width);
37576 height -= te.getHeight();
37579 var te = this.footer.getEl();
37580 te.setWidth(width);
37581 height -= te.getHeight();
37585 if(this.adjustments){
37586 width += this.adjustments[0];
37587 height += this.adjustments[1];
37589 return {"width": width, "height": height};
37592 setSize : function(width, height){
37593 if(this.fitToFrame && !this.ignoreResize(width, height)){
37594 if(this.fitContainer && this.resizeEl != this.el){
37595 this.el.setSize(width, height);
37597 var size = this.adjustForComponents(width, height);
37598 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37599 this.fireEvent('resize', this, size.width, size.height);
37604 * Returns this panel's title
37607 getTitle : function(){
37609 if (typeof(this.title) != 'object') {
37614 for (var k in this.title) {
37615 if (!this.title.hasOwnProperty(k)) {
37619 if (k.indexOf('-') >= 0) {
37620 var s = k.split('-');
37621 for (var i = 0; i<s.length; i++) {
37622 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37625 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37632 * Set this panel's title
37633 * @param {String} title
37635 setTitle : function(title){
37636 this.title = title;
37638 this.region.updatePanelTitle(this, title);
37643 * Returns true is this panel was configured to be closable
37644 * @return {Boolean}
37646 isClosable : function(){
37647 return this.closable;
37650 beforeSlide : function(){
37652 this.resizeEl.clip();
37655 afterSlide : function(){
37657 this.resizeEl.unclip();
37661 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37662 * Will fail silently if the {@link #setUrl} method has not been called.
37663 * This does not activate the panel, just updates its content.
37665 refresh : function(){
37666 if(this.refreshDelegate){
37667 this.loaded = false;
37668 this.refreshDelegate();
37673 * Destroys this panel
37675 destroy : function(){
37676 this.el.removeAllListeners();
37677 var tempEl = document.createElement("span");
37678 tempEl.appendChild(this.el.dom);
37679 tempEl.innerHTML = "";
37685 * form - if the content panel contains a form - this is a reference to it.
37686 * @type {Roo.form.Form}
37690 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37691 * This contains a reference to it.
37697 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37707 * @param {Object} cfg Xtype definition of item to add.
37711 getChildContainer: function () {
37712 return this.getEl();
37717 var ret = new Roo.factory(cfg);
37722 if (cfg.xtype.match(/^Form$/)) {
37725 //if (this.footer) {
37726 // el = this.footer.container.insertSibling(false, 'before');
37728 el = this.el.createChild();
37731 this.form = new Roo.form.Form(cfg);
37734 if ( this.form.allItems.length) {
37735 this.form.render(el.dom);
37739 // should only have one of theses..
37740 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37741 // views.. should not be just added - used named prop 'view''
37743 cfg.el = this.el.appendChild(document.createElement("div"));
37746 var ret = new Roo.factory(cfg);
37748 ret.render && ret.render(false, ''); // render blank..
37758 * @class Roo.bootstrap.panel.Grid
37759 * @extends Roo.bootstrap.panel.Content
37761 * Create a new GridPanel.
37762 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37763 * @param {Object} config A the config object
37769 Roo.bootstrap.panel.Grid = function(config)
37773 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37774 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37776 config.el = this.wrapper;
37777 //this.el = this.wrapper;
37779 if (config.container) {
37780 // ctor'ed from a Border/panel.grid
37783 this.wrapper.setStyle("overflow", "hidden");
37784 this.wrapper.addClass('roo-grid-container');
37789 if(config.toolbar){
37790 var tool_el = this.wrapper.createChild();
37791 this.toolbar = Roo.factory(config.toolbar);
37793 if (config.toolbar.items) {
37794 ti = config.toolbar.items ;
37795 delete config.toolbar.items ;
37799 this.toolbar.render(tool_el);
37800 for(var i =0;i < ti.length;i++) {
37801 // Roo.log(['add child', items[i]]);
37802 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37804 this.toolbar.items = nitems;
37806 delete config.toolbar;
37809 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37810 config.grid.scrollBody = true;;
37811 config.grid.monitorWindowResize = false; // turn off autosizing
37812 config.grid.autoHeight = false;
37813 config.grid.autoWidth = false;
37815 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37817 if (config.background) {
37818 // render grid on panel activation (if panel background)
37819 this.on('activate', function(gp) {
37820 if (!gp.grid.rendered) {
37821 gp.grid.render(this.wrapper);
37822 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37827 this.grid.render(this.wrapper);
37828 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37831 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37832 // ??? needed ??? config.el = this.wrapper;
37837 // xtype created footer. - not sure if will work as we normally have to render first..
37838 if (this.footer && !this.footer.el && this.footer.xtype) {
37840 var ctr = this.grid.getView().getFooterPanel(true);
37841 this.footer.dataSource = this.grid.dataSource;
37842 this.footer = Roo.factory(this.footer, Roo);
37843 this.footer.render(ctr);
37853 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37854 getId : function(){
37855 return this.grid.id;
37859 * Returns the grid for this panel
37860 * @return {Roo.bootstrap.Table}
37862 getGrid : function(){
37866 setSize : function(width, height){
37867 if(!this.ignoreResize(width, height)){
37868 var grid = this.grid;
37869 var size = this.adjustForComponents(width, height);
37870 var gridel = grid.getGridEl();
37871 gridel.setSize(size.width, size.height);
37873 var thd = grid.getGridEl().select('thead',true).first();
37874 var tbd = grid.getGridEl().select('tbody', true).first();
37876 tbd.setSize(width, height - thd.getHeight());
37885 beforeSlide : function(){
37886 this.grid.getView().scroller.clip();
37889 afterSlide : function(){
37890 this.grid.getView().scroller.unclip();
37893 destroy : function(){
37894 this.grid.destroy();
37896 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37901 * @class Roo.bootstrap.panel.Nest
37902 * @extends Roo.bootstrap.panel.Content
37904 * Create a new Panel, that can contain a layout.Border.
37907 * @param {Roo.BorderLayout} layout The layout for this panel
37908 * @param {String/Object} config A string to set only the title or a config object
37910 Roo.bootstrap.panel.Nest = function(config)
37912 // construct with only one argument..
37913 /* FIXME - implement nicer consturctors
37914 if (layout.layout) {
37916 layout = config.layout;
37917 delete config.layout;
37919 if (layout.xtype && !layout.getEl) {
37920 // then layout needs constructing..
37921 layout = Roo.factory(layout, Roo);
37925 config.el = config.layout.getEl();
37927 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37929 config.layout.monitorWindowResize = false; // turn off autosizing
37930 this.layout = config.layout;
37931 this.layout.getEl().addClass("roo-layout-nested-layout");
37932 this.layout.parent = this;
37939 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37941 setSize : function(width, height){
37942 if(!this.ignoreResize(width, height)){
37943 var size = this.adjustForComponents(width, height);
37944 var el = this.layout.getEl();
37945 if (size.height < 1) {
37946 el.setWidth(size.width);
37948 el.setSize(size.width, size.height);
37950 var touch = el.dom.offsetWidth;
37951 this.layout.layout();
37952 // ie requires a double layout on the first pass
37953 if(Roo.isIE && !this.initialized){
37954 this.initialized = true;
37955 this.layout.layout();
37960 // activate all subpanels if not currently active..
37962 setActiveState : function(active){
37963 this.active = active;
37964 this.setActiveClass(active);
37967 this.fireEvent("deactivate", this);
37971 this.fireEvent("activate", this);
37972 // not sure if this should happen before or after..
37973 if (!this.layout) {
37974 return; // should not happen..
37977 for (var r in this.layout.regions) {
37978 reg = this.layout.getRegion(r);
37979 if (reg.getActivePanel()) {
37980 //reg.showPanel(reg.getActivePanel()); // force it to activate..
37981 reg.setActivePanel(reg.getActivePanel());
37984 if (!reg.panels.length) {
37987 reg.showPanel(reg.getPanel(0));
37996 * Returns the nested BorderLayout for this panel
37997 * @return {Roo.BorderLayout}
37999 getLayout : function(){
38000 return this.layout;
38004 * Adds a xtype elements to the layout of the nested panel
38008 xtype : 'ContentPanel',
38015 xtype : 'NestedLayoutPanel',
38021 items : [ ... list of content panels or nested layout panels.. ]
38025 * @param {Object} cfg Xtype definition of item to add.
38027 addxtype : function(cfg) {
38028 return this.layout.addxtype(cfg);
38033 * Ext JS Library 1.1.1
38034 * Copyright(c) 2006-2007, Ext JS, LLC.
38036 * Originally Released Under LGPL - original licence link has changed is not relivant.
38039 * <script type="text/javascript">
38042 * @class Roo.TabPanel
38043 * @extends Roo.util.Observable
38044 * A lightweight tab container.
38048 // basic tabs 1, built from existing content
38049 var tabs = new Roo.TabPanel("tabs1");
38050 tabs.addTab("script", "View Script");
38051 tabs.addTab("markup", "View Markup");
38052 tabs.activate("script");
38054 // more advanced tabs, built from javascript
38055 var jtabs = new Roo.TabPanel("jtabs");
38056 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38058 // set up the UpdateManager
38059 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38060 var updater = tab2.getUpdateManager();
38061 updater.setDefaultUrl("ajax1.htm");
38062 tab2.on('activate', updater.refresh, updater, true);
38064 // Use setUrl for Ajax loading
38065 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38066 tab3.setUrl("ajax2.htm", null, true);
38069 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38072 jtabs.activate("jtabs-1");
38075 * Create a new TabPanel.
38076 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38077 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38079 Roo.bootstrap.panel.Tabs = function(config){
38081 * The container element for this TabPanel.
38082 * @type Roo.Element
38084 this.el = Roo.get(config.el);
38087 if(typeof config == "boolean"){
38088 this.tabPosition = config ? "bottom" : "top";
38090 Roo.apply(this, config);
38094 if(this.tabPosition == "bottom"){
38095 // if tabs are at the bottom = create the body first.
38096 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38097 this.el.addClass("roo-tabs-bottom");
38099 // next create the tabs holders
38101 if (this.tabPosition == "west"){
38103 var reg = this.region; // fake it..
38105 if (!reg.mgr.parent) {
38108 reg = reg.mgr.parent.region;
38110 Roo.log("got nest?");
38112 if (reg.mgr.getRegion('west')) {
38113 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38114 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38115 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38116 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38117 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38125 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38126 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38127 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38128 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38133 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38136 // finally - if tabs are at the top, then create the body last..
38137 if(this.tabPosition != "bottom"){
38138 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38139 * @type Roo.Element
38141 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38142 this.el.addClass("roo-tabs-top");
38146 this.bodyEl.setStyle("position", "relative");
38148 this.active = null;
38149 this.activateDelegate = this.activate.createDelegate(this);
38154 * Fires when the active tab changes
38155 * @param {Roo.TabPanel} this
38156 * @param {Roo.TabPanelItem} activePanel The new active tab
38160 * @event beforetabchange
38161 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38162 * @param {Roo.TabPanel} this
38163 * @param {Object} e Set cancel to true on this object to cancel the tab change
38164 * @param {Roo.TabPanelItem} tab The tab being changed to
38166 "beforetabchange" : true
38169 Roo.EventManager.onWindowResize(this.onResize, this);
38170 this.cpad = this.el.getPadding("lr");
38171 this.hiddenCount = 0;
38174 // toolbar on the tabbar support...
38175 if (this.toolbar) {
38176 alert("no toolbar support yet");
38177 this.toolbar = false;
38179 var tcfg = this.toolbar;
38180 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38181 this.toolbar = new Roo.Toolbar(tcfg);
38182 if (Roo.isSafari) {
38183 var tbl = tcfg.container.child('table', true);
38184 tbl.setAttribute('width', '100%');
38192 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38195 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38197 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38199 tabPosition : "top",
38201 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38203 currentTabWidth : 0,
38205 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38209 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38213 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38215 preferredTabWidth : 175,
38217 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38219 resizeTabs : false,
38221 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38223 monitorResize : true,
38225 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38227 toolbar : false, // set by caller..
38229 region : false, /// set by caller
38231 disableTooltips : true, // not used yet...
38234 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38235 * @param {String} id The id of the div to use <b>or create</b>
38236 * @param {String} text The text for the tab
38237 * @param {String} content (optional) Content to put in the TabPanelItem body
38238 * @param {Boolean} closable (optional) True to create a close icon on the tab
38239 * @return {Roo.TabPanelItem} The created TabPanelItem
38241 addTab : function(id, text, content, closable, tpl)
38243 var item = new Roo.bootstrap.panel.TabItem({
38247 closable : closable,
38250 this.addTabItem(item);
38252 item.setContent(content);
38258 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38259 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38260 * @return {Roo.TabPanelItem}
38262 getTab : function(id){
38263 return this.items[id];
38267 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38268 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38270 hideTab : function(id){
38271 var t = this.items[id];
38274 this.hiddenCount++;
38275 this.autoSizeTabs();
38280 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38281 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38283 unhideTab : function(id){
38284 var t = this.items[id];
38286 t.setHidden(false);
38287 this.hiddenCount--;
38288 this.autoSizeTabs();
38293 * Adds an existing {@link Roo.TabPanelItem}.
38294 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38296 addTabItem : function(item)
38298 this.items[item.id] = item;
38299 this.items.push(item);
38300 this.autoSizeTabs();
38301 // if(this.resizeTabs){
38302 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38303 // this.autoSizeTabs();
38305 // item.autoSize();
38310 * Removes a {@link Roo.TabPanelItem}.
38311 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38313 removeTab : function(id){
38314 var items = this.items;
38315 var tab = items[id];
38316 if(!tab) { return; }
38317 var index = items.indexOf(tab);
38318 if(this.active == tab && items.length > 1){
38319 var newTab = this.getNextAvailable(index);
38324 this.stripEl.dom.removeChild(tab.pnode.dom);
38325 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38326 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38328 items.splice(index, 1);
38329 delete this.items[tab.id];
38330 tab.fireEvent("close", tab);
38331 tab.purgeListeners();
38332 this.autoSizeTabs();
38335 getNextAvailable : function(start){
38336 var items = this.items;
38338 // look for a next tab that will slide over to
38339 // replace the one being removed
38340 while(index < items.length){
38341 var item = items[++index];
38342 if(item && !item.isHidden()){
38346 // if one isn't found select the previous tab (on the left)
38349 var item = items[--index];
38350 if(item && !item.isHidden()){
38358 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38359 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38361 disableTab : function(id){
38362 var tab = this.items[id];
38363 if(tab && this.active != tab){
38369 * Enables a {@link Roo.TabPanelItem} that is disabled.
38370 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38372 enableTab : function(id){
38373 var tab = this.items[id];
38378 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38379 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38380 * @return {Roo.TabPanelItem} The TabPanelItem.
38382 activate : function(id)
38384 //Roo.log('activite:' + id);
38386 var tab = this.items[id];
38390 if(tab == this.active || tab.disabled){
38394 this.fireEvent("beforetabchange", this, e, tab);
38395 if(e.cancel !== true && !tab.disabled){
38397 this.active.hide();
38399 this.active = this.items[id];
38400 this.active.show();
38401 this.fireEvent("tabchange", this, this.active);
38407 * Gets the active {@link Roo.TabPanelItem}.
38408 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38410 getActiveTab : function(){
38411 return this.active;
38415 * Updates the tab body element to fit the height of the container element
38416 * for overflow scrolling
38417 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38419 syncHeight : function(targetHeight){
38420 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38421 var bm = this.bodyEl.getMargins();
38422 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38423 this.bodyEl.setHeight(newHeight);
38427 onResize : function(){
38428 if(this.monitorResize){
38429 this.autoSizeTabs();
38434 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38436 beginUpdate : function(){
38437 this.updating = true;
38441 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38443 endUpdate : function(){
38444 this.updating = false;
38445 this.autoSizeTabs();
38449 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38451 autoSizeTabs : function()
38453 var count = this.items.length;
38454 var vcount = count - this.hiddenCount;
38457 this.stripEl.hide();
38459 this.stripEl.show();
38462 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38467 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38468 var availWidth = Math.floor(w / vcount);
38469 var b = this.stripBody;
38470 if(b.getWidth() > w){
38471 var tabs = this.items;
38472 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38473 if(availWidth < this.minTabWidth){
38474 /*if(!this.sleft){ // incomplete scrolling code
38475 this.createScrollButtons();
38478 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38481 if(this.currentTabWidth < this.preferredTabWidth){
38482 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38488 * Returns the number of tabs in this TabPanel.
38491 getCount : function(){
38492 return this.items.length;
38496 * Resizes all the tabs to the passed width
38497 * @param {Number} The new width
38499 setTabWidth : function(width){
38500 this.currentTabWidth = width;
38501 for(var i = 0, len = this.items.length; i < len; i++) {
38502 if(!this.items[i].isHidden()) {
38503 this.items[i].setWidth(width);
38509 * Destroys this TabPanel
38510 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38512 destroy : function(removeEl){
38513 Roo.EventManager.removeResizeListener(this.onResize, this);
38514 for(var i = 0, len = this.items.length; i < len; i++){
38515 this.items[i].purgeListeners();
38517 if(removeEl === true){
38518 this.el.update("");
38523 createStrip : function(container)
38525 var strip = document.createElement("nav");
38526 strip.className = Roo.bootstrap.version == 4 ?
38527 "navbar-light bg-light" :
38528 "navbar navbar-default"; //"x-tabs-wrap";
38529 container.appendChild(strip);
38533 createStripList : function(strip)
38535 // div wrapper for retard IE
38536 // returns the "tr" element.
38537 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38538 //'<div class="x-tabs-strip-wrap">'+
38539 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38540 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38541 return strip.firstChild; //.firstChild.firstChild.firstChild;
38543 createBody : function(container)
38545 var body = document.createElement("div");
38546 Roo.id(body, "tab-body");
38547 //Roo.fly(body).addClass("x-tabs-body");
38548 Roo.fly(body).addClass("tab-content");
38549 container.appendChild(body);
38552 createItemBody :function(bodyEl, id){
38553 var body = Roo.getDom(id);
38555 body = document.createElement("div");
38558 //Roo.fly(body).addClass("x-tabs-item-body");
38559 Roo.fly(body).addClass("tab-pane");
38560 bodyEl.insertBefore(body, bodyEl.firstChild);
38564 createStripElements : function(stripEl, text, closable, tpl)
38566 var td = document.createElement("li"); // was td..
38567 td.className = 'nav-item';
38569 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38572 stripEl.appendChild(td);
38574 td.className = "x-tabs-closable";
38575 if(!this.closeTpl){
38576 this.closeTpl = new Roo.Template(
38577 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38578 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38579 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38582 var el = this.closeTpl.overwrite(td, {"text": text});
38583 var close = el.getElementsByTagName("div")[0];
38584 var inner = el.getElementsByTagName("em")[0];
38585 return {"el": el, "close": close, "inner": inner};
38588 // not sure what this is..
38589 // if(!this.tabTpl){
38590 //this.tabTpl = new Roo.Template(
38591 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38592 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38594 // this.tabTpl = new Roo.Template(
38595 // '<a href="#">' +
38596 // '<span unselectable="on"' +
38597 // (this.disableTooltips ? '' : ' title="{text}"') +
38598 // ' >{text}</span></a>'
38604 var template = tpl || this.tabTpl || false;
38607 template = new Roo.Template(
38608 Roo.bootstrap.version == 4 ?
38610 '<a class="nav-link" href="#" unselectable="on"' +
38611 (this.disableTooltips ? '' : ' title="{text}"') +
38614 '<a class="nav-link" href="#">' +
38615 '<span unselectable="on"' +
38616 (this.disableTooltips ? '' : ' title="{text}"') +
38617 ' >{text}</span></a>'
38622 switch (typeof(template)) {
38626 template = new Roo.Template(template);
38632 var el = template.overwrite(td, {"text": text});
38634 var inner = el.getElementsByTagName("span")[0];
38636 return {"el": el, "inner": inner};
38644 * @class Roo.TabPanelItem
38645 * @extends Roo.util.Observable
38646 * Represents an individual item (tab plus body) in a TabPanel.
38647 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38648 * @param {String} id The id of this TabPanelItem
38649 * @param {String} text The text for the tab of this TabPanelItem
38650 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38652 Roo.bootstrap.panel.TabItem = function(config){
38654 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38655 * @type Roo.TabPanel
38657 this.tabPanel = config.panel;
38659 * The id for this TabPanelItem
38662 this.id = config.id;
38664 this.disabled = false;
38666 this.text = config.text;
38668 this.loaded = false;
38669 this.closable = config.closable;
38672 * The body element for this TabPanelItem.
38673 * @type Roo.Element
38675 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38676 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38677 this.bodyEl.setStyle("display", "block");
38678 this.bodyEl.setStyle("zoom", "1");
38679 //this.hideAction();
38681 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38683 this.el = Roo.get(els.el);
38684 this.inner = Roo.get(els.inner, true);
38685 this.textEl = Roo.bootstrap.version == 4 ?
38686 this.el : Roo.get(this.el.dom.firstChild, true);
38688 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38689 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38692 // this.el.on("mousedown", this.onTabMouseDown, this);
38693 this.el.on("click", this.onTabClick, this);
38695 if(config.closable){
38696 var c = Roo.get(els.close, true);
38697 c.dom.title = this.closeText;
38698 c.addClassOnOver("close-over");
38699 c.on("click", this.closeClick, this);
38705 * Fires when this tab becomes the active tab.
38706 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38707 * @param {Roo.TabPanelItem} this
38711 * @event beforeclose
38712 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38713 * @param {Roo.TabPanelItem} this
38714 * @param {Object} e Set cancel to true on this object to cancel the close.
38716 "beforeclose": true,
38719 * Fires when this tab is closed.
38720 * @param {Roo.TabPanelItem} this
38724 * @event deactivate
38725 * Fires when this tab is no longer the active tab.
38726 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38727 * @param {Roo.TabPanelItem} this
38729 "deactivate" : true
38731 this.hidden = false;
38733 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38736 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38738 purgeListeners : function(){
38739 Roo.util.Observable.prototype.purgeListeners.call(this);
38740 this.el.removeAllListeners();
38743 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38746 this.status_node.addClass("active");
38749 this.tabPanel.stripWrap.repaint();
38751 this.fireEvent("activate", this.tabPanel, this);
38755 * Returns true if this tab is the active tab.
38756 * @return {Boolean}
38758 isActive : function(){
38759 return this.tabPanel.getActiveTab() == this;
38763 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38766 this.status_node.removeClass("active");
38768 this.fireEvent("deactivate", this.tabPanel, this);
38771 hideAction : function(){
38772 this.bodyEl.hide();
38773 this.bodyEl.setStyle("position", "absolute");
38774 this.bodyEl.setLeft("-20000px");
38775 this.bodyEl.setTop("-20000px");
38778 showAction : function(){
38779 this.bodyEl.setStyle("position", "relative");
38780 this.bodyEl.setTop("");
38781 this.bodyEl.setLeft("");
38782 this.bodyEl.show();
38786 * Set the tooltip for the tab.
38787 * @param {String} tooltip The tab's tooltip
38789 setTooltip : function(text){
38790 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38791 this.textEl.dom.qtip = text;
38792 this.textEl.dom.removeAttribute('title');
38794 this.textEl.dom.title = text;
38798 onTabClick : function(e){
38799 e.preventDefault();
38800 this.tabPanel.activate(this.id);
38803 onTabMouseDown : function(e){
38804 e.preventDefault();
38805 this.tabPanel.activate(this.id);
38808 getWidth : function(){
38809 return this.inner.getWidth();
38812 setWidth : function(width){
38813 var iwidth = width - this.linode.getPadding("lr");
38814 this.inner.setWidth(iwidth);
38815 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38816 this.linode.setWidth(width);
38820 * Show or hide the tab
38821 * @param {Boolean} hidden True to hide or false to show.
38823 setHidden : function(hidden){
38824 this.hidden = hidden;
38825 this.linode.setStyle("display", hidden ? "none" : "");
38829 * Returns true if this tab is "hidden"
38830 * @return {Boolean}
38832 isHidden : function(){
38833 return this.hidden;
38837 * Returns the text for this tab
38840 getText : function(){
38844 autoSize : function(){
38845 //this.el.beginMeasure();
38846 this.textEl.setWidth(1);
38848 * #2804 [new] Tabs in Roojs
38849 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38851 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38852 //this.el.endMeasure();
38856 * Sets the text for the tab (Note: this also sets the tooltip text)
38857 * @param {String} text The tab's text and tooltip
38859 setText : function(text){
38861 this.textEl.update(text);
38862 this.setTooltip(text);
38863 //if(!this.tabPanel.resizeTabs){
38864 // this.autoSize();
38868 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38870 activate : function(){
38871 this.tabPanel.activate(this.id);
38875 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38877 disable : function(){
38878 if(this.tabPanel.active != this){
38879 this.disabled = true;
38880 this.status_node.addClass("disabled");
38885 * Enables this TabPanelItem if it was previously disabled.
38887 enable : function(){
38888 this.disabled = false;
38889 this.status_node.removeClass("disabled");
38893 * Sets the content for this TabPanelItem.
38894 * @param {String} content The content
38895 * @param {Boolean} loadScripts true to look for and load scripts
38897 setContent : function(content, loadScripts){
38898 this.bodyEl.update(content, loadScripts);
38902 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38903 * @return {Roo.UpdateManager} The UpdateManager
38905 getUpdateManager : function(){
38906 return this.bodyEl.getUpdateManager();
38910 * Set a URL to be used to load the content for this TabPanelItem.
38911 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38912 * @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)
38913 * @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)
38914 * @return {Roo.UpdateManager} The UpdateManager
38916 setUrl : function(url, params, loadOnce){
38917 if(this.refreshDelegate){
38918 this.un('activate', this.refreshDelegate);
38920 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38921 this.on("activate", this.refreshDelegate);
38922 return this.bodyEl.getUpdateManager();
38926 _handleRefresh : function(url, params, loadOnce){
38927 if(!loadOnce || !this.loaded){
38928 var updater = this.bodyEl.getUpdateManager();
38929 updater.update(url, params, this._setLoaded.createDelegate(this));
38934 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38935 * Will fail silently if the setUrl method has not been called.
38936 * This does not activate the panel, just updates its content.
38938 refresh : function(){
38939 if(this.refreshDelegate){
38940 this.loaded = false;
38941 this.refreshDelegate();
38946 _setLoaded : function(){
38947 this.loaded = true;
38951 closeClick : function(e){
38954 this.fireEvent("beforeclose", this, o);
38955 if(o.cancel !== true){
38956 this.tabPanel.removeTab(this.id);
38960 * The text displayed in the tooltip for the close icon.
38963 closeText : "Close this tab"
38966 * This script refer to:
38967 * Title: International Telephone Input
38968 * Author: Jack O'Connor
38969 * Code version: v12.1.12
38970 * Availability: https://github.com/jackocnr/intl-tel-input.git
38973 Roo.bootstrap.PhoneInputData = function() {
38976 "Afghanistan (افغانستان)",
38981 "Albania (Shqipëri)",
38986 "Algeria (الجزائر)",
39011 "Antigua and Barbuda",
39021 "Armenia (Հայաստան)",
39037 "Austria (Österreich)",
39042 "Azerbaijan (Azərbaycan)",
39052 "Bahrain (البحرين)",
39057 "Bangladesh (বাংলাদেশ)",
39067 "Belarus (Беларусь)",
39072 "Belgium (België)",
39102 "Bosnia and Herzegovina (Босна и Херцеговина)",
39117 "British Indian Ocean Territory",
39122 "British Virgin Islands",
39132 "Bulgaria (България)",
39142 "Burundi (Uburundi)",
39147 "Cambodia (កម្ពុជា)",
39152 "Cameroon (Cameroun)",
39161 ["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"]
39164 "Cape Verde (Kabu Verdi)",
39169 "Caribbean Netherlands",
39180 "Central African Republic (République centrafricaine)",
39200 "Christmas Island",
39206 "Cocos (Keeling) Islands",
39217 "Comoros (جزر القمر)",
39222 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39227 "Congo (Republic) (Congo-Brazzaville)",
39247 "Croatia (Hrvatska)",
39268 "Czech Republic (Česká republika)",
39273 "Denmark (Danmark)",
39288 "Dominican Republic (República Dominicana)",
39292 ["809", "829", "849"]
39310 "Equatorial Guinea (Guinea Ecuatorial)",
39330 "Falkland Islands (Islas Malvinas)",
39335 "Faroe Islands (Føroyar)",
39356 "French Guiana (Guyane française)",
39361 "French Polynesia (Polynésie française)",
39376 "Georgia (საქართველო)",
39381 "Germany (Deutschland)",
39401 "Greenland (Kalaallit Nunaat)",
39438 "Guinea-Bissau (Guiné Bissau)",
39463 "Hungary (Magyarország)",
39468 "Iceland (Ísland)",
39488 "Iraq (العراق)",
39504 "Israel (ישראל)",
39531 "Jordan (الأردن)",
39536 "Kazakhstan (Казахстан)",
39557 "Kuwait (الكويت)",
39562 "Kyrgyzstan (Кыргызстан)",
39572 "Latvia (Latvija)",
39577 "Lebanon (لبنان)",
39592 "Libya (ليبيا)",
39602 "Lithuania (Lietuva)",
39617 "Macedonia (FYROM) (Македонија)",
39622 "Madagascar (Madagasikara)",
39652 "Marshall Islands",
39662 "Mauritania (موريتانيا)",
39667 "Mauritius (Moris)",
39688 "Moldova (Republica Moldova)",
39698 "Mongolia (Монгол)",
39703 "Montenegro (Crna Gora)",
39713 "Morocco (المغرب)",
39719 "Mozambique (Moçambique)",
39724 "Myanmar (Burma) (မြန်မာ)",
39729 "Namibia (Namibië)",
39744 "Netherlands (Nederland)",
39749 "New Caledonia (Nouvelle-Calédonie)",
39784 "North Korea (조선 민주주의 인민 공화국)",
39789 "Northern Mariana Islands",
39805 "Pakistan (پاکستان)",
39815 "Palestine (فلسطين)",
39825 "Papua New Guinea",
39867 "Réunion (La Réunion)",
39873 "Romania (România)",
39889 "Saint Barthélemy",
39900 "Saint Kitts and Nevis",
39910 "Saint Martin (Saint-Martin (partie française))",
39916 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39921 "Saint Vincent and the Grenadines",
39936 "São Tomé and Príncipe (São Tomé e Príncipe)",
39941 "Saudi Arabia (المملكة العربية السعودية)",
39946 "Senegal (Sénégal)",
39976 "Slovakia (Slovensko)",
39981 "Slovenia (Slovenija)",
39991 "Somalia (Soomaaliya)",
40001 "South Korea (대한민국)",
40006 "South Sudan (جنوب السودان)",
40016 "Sri Lanka (ශ්රී ලංකාව)",
40021 "Sudan (السودان)",
40031 "Svalbard and Jan Mayen",
40042 "Sweden (Sverige)",
40047 "Switzerland (Schweiz)",
40052 "Syria (سوريا)",
40097 "Trinidad and Tobago",
40102 "Tunisia (تونس)",
40107 "Turkey (Türkiye)",
40117 "Turks and Caicos Islands",
40127 "U.S. Virgin Islands",
40137 "Ukraine (Україна)",
40142 "United Arab Emirates (الإمارات العربية المتحدة)",
40164 "Uzbekistan (Oʻzbekiston)",
40174 "Vatican City (Città del Vaticano)",
40185 "Vietnam (Việt Nam)",
40190 "Wallis and Futuna (Wallis-et-Futuna)",
40195 "Western Sahara (الصحراء الغربية)",
40201 "Yemen (اليمن)",
40225 * This script refer to:
40226 * Title: International Telephone Input
40227 * Author: Jack O'Connor
40228 * Code version: v12.1.12
40229 * Availability: https://github.com/jackocnr/intl-tel-input.git
40233 * @class Roo.bootstrap.PhoneInput
40234 * @extends Roo.bootstrap.TriggerField
40235 * An input with International dial-code selection
40237 * @cfg {String} defaultDialCode default '+852'
40238 * @cfg {Array} preferedCountries default []
40241 * Create a new PhoneInput.
40242 * @param {Object} config Configuration options
40245 Roo.bootstrap.PhoneInput = function(config) {
40246 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40249 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40251 listWidth: undefined,
40253 selectedClass: 'active',
40255 invalidClass : "has-warning",
40257 validClass: 'has-success',
40259 allowed: '0123456789',
40264 * @cfg {String} defaultDialCode The default dial code when initializing the input
40266 defaultDialCode: '+852',
40269 * @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
40271 preferedCountries: false,
40273 getAutoCreate : function()
40275 var data = Roo.bootstrap.PhoneInputData();
40276 var align = this.labelAlign || this.parentLabelAlign();
40279 this.allCountries = [];
40280 this.dialCodeMapping = [];
40282 for (var i = 0; i < data.length; i++) {
40284 this.allCountries[i] = {
40288 priority: c[3] || 0,
40289 areaCodes: c[4] || null
40291 this.dialCodeMapping[c[2]] = {
40294 priority: c[3] || 0,
40295 areaCodes: c[4] || null
40307 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40308 maxlength: this.max_length,
40309 cls : 'form-control tel-input',
40310 autocomplete: 'new-password'
40313 var hiddenInput = {
40316 cls: 'hidden-tel-input'
40320 hiddenInput.name = this.name;
40323 if (this.disabled) {
40324 input.disabled = true;
40327 var flag_container = {
40344 cls: this.hasFeedback ? 'has-feedback' : '',
40350 cls: 'dial-code-holder',
40357 cls: 'roo-select2-container input-group',
40364 if (this.fieldLabel.length) {
40367 tooltip: 'This field is required'
40373 cls: 'control-label',
40379 html: this.fieldLabel
40382 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40388 if(this.indicatorpos == 'right') {
40389 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40396 if(align == 'left') {
40404 if(this.labelWidth > 12){
40405 label.style = "width: " + this.labelWidth + 'px';
40407 if(this.labelWidth < 13 && this.labelmd == 0){
40408 this.labelmd = this.labelWidth;
40410 if(this.labellg > 0){
40411 label.cls += ' col-lg-' + this.labellg;
40412 input.cls += ' col-lg-' + (12 - this.labellg);
40414 if(this.labelmd > 0){
40415 label.cls += ' col-md-' + this.labelmd;
40416 container.cls += ' col-md-' + (12 - this.labelmd);
40418 if(this.labelsm > 0){
40419 label.cls += ' col-sm-' + this.labelsm;
40420 container.cls += ' col-sm-' + (12 - this.labelsm);
40422 if(this.labelxs > 0){
40423 label.cls += ' col-xs-' + this.labelxs;
40424 container.cls += ' col-xs-' + (12 - this.labelxs);
40434 var settings = this;
40436 ['xs','sm','md','lg'].map(function(size){
40437 if (settings[size]) {
40438 cfg.cls += ' col-' + size + '-' + settings[size];
40442 this.store = new Roo.data.Store({
40443 proxy : new Roo.data.MemoryProxy({}),
40444 reader : new Roo.data.JsonReader({
40455 'name' : 'dialCode',
40459 'name' : 'priority',
40463 'name' : 'areaCodes',
40470 if(!this.preferedCountries) {
40471 this.preferedCountries = [
40478 var p = this.preferedCountries.reverse();
40481 for (var i = 0; i < p.length; i++) {
40482 for (var j = 0; j < this.allCountries.length; j++) {
40483 if(this.allCountries[j].iso2 == p[i]) {
40484 var t = this.allCountries[j];
40485 this.allCountries.splice(j,1);
40486 this.allCountries.unshift(t);
40492 this.store.proxy.data = {
40494 data: this.allCountries
40500 initEvents : function()
40503 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40505 this.indicator = this.indicatorEl();
40506 this.flag = this.flagEl();
40507 this.dialCodeHolder = this.dialCodeHolderEl();
40509 this.trigger = this.el.select('div.flag-box',true).first();
40510 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40515 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40516 _this.list.setWidth(lw);
40519 this.list.on('mouseover', this.onViewOver, this);
40520 this.list.on('mousemove', this.onViewMove, this);
40521 this.inputEl().on("keyup", this.onKeyUp, this);
40522 this.inputEl().on("keypress", this.onKeyPress, this);
40524 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40526 this.view = new Roo.View(this.list, this.tpl, {
40527 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40530 this.view.on('click', this.onViewClick, this);
40531 this.setValue(this.defaultDialCode);
40534 onTriggerClick : function(e)
40536 Roo.log('trigger click');
40541 if(this.isExpanded()){
40543 this.hasFocus = false;
40545 this.store.load({});
40546 this.hasFocus = true;
40551 isExpanded : function()
40553 return this.list.isVisible();
40556 collapse : function()
40558 if(!this.isExpanded()){
40562 Roo.get(document).un('mousedown', this.collapseIf, this);
40563 Roo.get(document).un('mousewheel', this.collapseIf, this);
40564 this.fireEvent('collapse', this);
40568 expand : function()
40572 if(this.isExpanded() || !this.hasFocus){
40576 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40577 this.list.setWidth(lw);
40580 this.restrictHeight();
40582 Roo.get(document).on('mousedown', this.collapseIf, this);
40583 Roo.get(document).on('mousewheel', this.collapseIf, this);
40585 this.fireEvent('expand', this);
40588 restrictHeight : function()
40590 this.list.alignTo(this.inputEl(), this.listAlign);
40591 this.list.alignTo(this.inputEl(), this.listAlign);
40594 onViewOver : function(e, t)
40596 if(this.inKeyMode){
40599 var item = this.view.findItemFromChild(t);
40602 var index = this.view.indexOf(item);
40603 this.select(index, false);
40608 onViewClick : function(view, doFocus, el, e)
40610 var index = this.view.getSelectedIndexes()[0];
40612 var r = this.store.getAt(index);
40615 this.onSelect(r, index);
40617 if(doFocus !== false && !this.blockFocus){
40618 this.inputEl().focus();
40622 onViewMove : function(e, t)
40624 this.inKeyMode = false;
40627 select : function(index, scrollIntoView)
40629 this.selectedIndex = index;
40630 this.view.select(index);
40631 if(scrollIntoView !== false){
40632 var el = this.view.getNode(index);
40634 this.list.scrollChildIntoView(el, false);
40639 createList : function()
40641 this.list = Roo.get(document.body).createChild({
40643 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40644 style: 'display:none'
40647 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40650 collapseIf : function(e)
40652 var in_combo = e.within(this.el);
40653 var in_list = e.within(this.list);
40654 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40656 if (in_combo || in_list || is_list) {
40662 onSelect : function(record, index)
40664 if(this.fireEvent('beforeselect', this, record, index) !== false){
40666 this.setFlagClass(record.data.iso2);
40667 this.setDialCode(record.data.dialCode);
40668 this.hasFocus = false;
40670 this.fireEvent('select', this, record, index);
40674 flagEl : function()
40676 var flag = this.el.select('div.flag',true).first();
40683 dialCodeHolderEl : function()
40685 var d = this.el.select('input.dial-code-holder',true).first();
40692 setDialCode : function(v)
40694 this.dialCodeHolder.dom.value = '+'+v;
40697 setFlagClass : function(n)
40699 this.flag.dom.className = 'flag '+n;
40702 getValue : function()
40704 var v = this.inputEl().getValue();
40705 if(this.dialCodeHolder) {
40706 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40711 setValue : function(v)
40713 var d = this.getDialCode(v);
40715 //invalid dial code
40716 if(v.length == 0 || !d || d.length == 0) {
40718 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40719 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40725 this.setFlagClass(this.dialCodeMapping[d].iso2);
40726 this.setDialCode(d);
40727 this.inputEl().dom.value = v.replace('+'+d,'');
40728 this.hiddenEl().dom.value = this.getValue();
40733 getDialCode : function(v)
40737 if (v.length == 0) {
40738 return this.dialCodeHolder.dom.value;
40742 if (v.charAt(0) != "+") {
40745 var numericChars = "";
40746 for (var i = 1; i < v.length; i++) {
40747 var c = v.charAt(i);
40750 if (this.dialCodeMapping[numericChars]) {
40751 dialCode = v.substr(1, i);
40753 if (numericChars.length == 4) {
40763 this.setValue(this.defaultDialCode);
40767 hiddenEl : function()
40769 return this.el.select('input.hidden-tel-input',true).first();
40772 // after setting val
40773 onKeyUp : function(e){
40774 this.setValue(this.getValue());
40777 onKeyPress : function(e){
40778 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40785 * @class Roo.bootstrap.MoneyField
40786 * @extends Roo.bootstrap.ComboBox
40787 * Bootstrap MoneyField class
40790 * Create a new MoneyField.
40791 * @param {Object} config Configuration options
40794 Roo.bootstrap.MoneyField = function(config) {
40796 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40800 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40803 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40805 allowDecimals : true,
40807 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40809 decimalSeparator : ".",
40811 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40813 decimalPrecision : 0,
40815 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40817 allowNegative : true,
40819 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40823 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40825 minValue : Number.NEGATIVE_INFINITY,
40827 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40829 maxValue : Number.MAX_VALUE,
40831 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40833 minText : "The minimum value for this field is {0}",
40835 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40837 maxText : "The maximum value for this field is {0}",
40839 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40840 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40842 nanText : "{0} is not a valid number",
40844 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40848 * @cfg {String} defaults currency of the MoneyField
40849 * value should be in lkey
40851 defaultCurrency : false,
40853 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40855 thousandsDelimiter : false,
40857 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40868 getAutoCreate : function()
40870 var align = this.labelAlign || this.parentLabelAlign();
40882 cls : 'form-control roo-money-amount-input',
40883 autocomplete: 'new-password'
40886 var hiddenInput = {
40890 cls: 'hidden-number-input'
40893 if(this.max_length) {
40894 input.maxlength = this.max_length;
40898 hiddenInput.name = this.name;
40901 if (this.disabled) {
40902 input.disabled = true;
40905 var clg = 12 - this.inputlg;
40906 var cmd = 12 - this.inputmd;
40907 var csm = 12 - this.inputsm;
40908 var cxs = 12 - this.inputxs;
40912 cls : 'row roo-money-field',
40916 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40920 cls: 'roo-select2-container input-group',
40924 cls : 'form-control roo-money-currency-input',
40925 autocomplete: 'new-password',
40927 name : this.currencyName
40931 cls : 'input-group-addon',
40945 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40949 cls: this.hasFeedback ? 'has-feedback' : '',
40960 if (this.fieldLabel.length) {
40963 tooltip: 'This field is required'
40969 cls: 'control-label',
40975 html: this.fieldLabel
40978 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40984 if(this.indicatorpos == 'right') {
40985 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40992 if(align == 'left') {
41000 if(this.labelWidth > 12){
41001 label.style = "width: " + this.labelWidth + 'px';
41003 if(this.labelWidth < 13 && this.labelmd == 0){
41004 this.labelmd = this.labelWidth;
41006 if(this.labellg > 0){
41007 label.cls += ' col-lg-' + this.labellg;
41008 input.cls += ' col-lg-' + (12 - this.labellg);
41010 if(this.labelmd > 0){
41011 label.cls += ' col-md-' + this.labelmd;
41012 container.cls += ' col-md-' + (12 - this.labelmd);
41014 if(this.labelsm > 0){
41015 label.cls += ' col-sm-' + this.labelsm;
41016 container.cls += ' col-sm-' + (12 - this.labelsm);
41018 if(this.labelxs > 0){
41019 label.cls += ' col-xs-' + this.labelxs;
41020 container.cls += ' col-xs-' + (12 - this.labelxs);
41031 var settings = this;
41033 ['xs','sm','md','lg'].map(function(size){
41034 if (settings[size]) {
41035 cfg.cls += ' col-' + size + '-' + settings[size];
41042 initEvents : function()
41044 this.indicator = this.indicatorEl();
41046 this.initCurrencyEvent();
41048 this.initNumberEvent();
41051 initCurrencyEvent : function()
41054 throw "can not find store for combo";
41057 this.store = Roo.factory(this.store, Roo.data);
41058 this.store.parent = this;
41062 this.triggerEl = this.el.select('.input-group-addon', true).first();
41064 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41069 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41070 _this.list.setWidth(lw);
41073 this.list.on('mouseover', this.onViewOver, this);
41074 this.list.on('mousemove', this.onViewMove, this);
41075 this.list.on('scroll', this.onViewScroll, this);
41078 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41081 this.view = new Roo.View(this.list, this.tpl, {
41082 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41085 this.view.on('click', this.onViewClick, this);
41087 this.store.on('beforeload', this.onBeforeLoad, this);
41088 this.store.on('load', this.onLoad, this);
41089 this.store.on('loadexception', this.onLoadException, this);
41091 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41092 "up" : function(e){
41093 this.inKeyMode = true;
41097 "down" : function(e){
41098 if(!this.isExpanded()){
41099 this.onTriggerClick();
41101 this.inKeyMode = true;
41106 "enter" : function(e){
41109 if(this.fireEvent("specialkey", this, e)){
41110 this.onViewClick(false);
41116 "esc" : function(e){
41120 "tab" : function(e){
41123 if(this.fireEvent("specialkey", this, e)){
41124 this.onViewClick(false);
41132 doRelay : function(foo, bar, hname){
41133 if(hname == 'down' || this.scope.isExpanded()){
41134 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41142 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41146 initNumberEvent : function(e)
41148 this.inputEl().on("keydown" , this.fireKey, this);
41149 this.inputEl().on("focus", this.onFocus, this);
41150 this.inputEl().on("blur", this.onBlur, this);
41152 this.inputEl().relayEvent('keyup', this);
41154 if(this.indicator){
41155 this.indicator.addClass('invisible');
41158 this.originalValue = this.getValue();
41160 if(this.validationEvent == 'keyup'){
41161 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41162 this.inputEl().on('keyup', this.filterValidation, this);
41164 else if(this.validationEvent !== false){
41165 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41168 if(this.selectOnFocus){
41169 this.on("focus", this.preFocus, this);
41172 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41173 this.inputEl().on("keypress", this.filterKeys, this);
41175 this.inputEl().relayEvent('keypress', this);
41178 var allowed = "0123456789";
41180 if(this.allowDecimals){
41181 allowed += this.decimalSeparator;
41184 if(this.allowNegative){
41188 if(this.thousandsDelimiter) {
41192 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41194 var keyPress = function(e){
41196 var k = e.getKey();
41198 var c = e.getCharCode();
41201 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41202 allowed.indexOf(String.fromCharCode(c)) === -1
41208 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41212 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41217 this.inputEl().on("keypress", keyPress, this);
41221 onTriggerClick : function(e)
41228 this.loadNext = false;
41230 if(this.isExpanded()){
41235 this.hasFocus = true;
41237 if(this.triggerAction == 'all') {
41238 this.doQuery(this.allQuery, true);
41242 this.doQuery(this.getRawValue());
41245 getCurrency : function()
41247 var v = this.currencyEl().getValue();
41252 restrictHeight : function()
41254 this.list.alignTo(this.currencyEl(), this.listAlign);
41255 this.list.alignTo(this.currencyEl(), this.listAlign);
41258 onViewClick : function(view, doFocus, el, e)
41260 var index = this.view.getSelectedIndexes()[0];
41262 var r = this.store.getAt(index);
41265 this.onSelect(r, index);
41269 onSelect : function(record, index){
41271 if(this.fireEvent('beforeselect', this, record, index) !== false){
41273 this.setFromCurrencyData(index > -1 ? record.data : false);
41277 this.fireEvent('select', this, record, index);
41281 setFromCurrencyData : function(o)
41285 this.lastCurrency = o;
41287 if (this.currencyField) {
41288 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41290 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41293 this.lastSelectionText = currency;
41295 //setting default currency
41296 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41297 this.setCurrency(this.defaultCurrency);
41301 this.setCurrency(currency);
41304 setFromData : function(o)
41308 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41310 this.setFromCurrencyData(c);
41315 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41317 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41320 this.setValue(value);
41324 setCurrency : function(v)
41326 this.currencyValue = v;
41329 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41334 setValue : function(v)
41336 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41342 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41344 this.inputEl().dom.value = (v == '') ? '' :
41345 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41347 if(!this.allowZero && v === '0') {
41348 this.hiddenEl().dom.value = '';
41349 this.inputEl().dom.value = '';
41356 getRawValue : function()
41358 var v = this.inputEl().getValue();
41363 getValue : function()
41365 return this.fixPrecision(this.parseValue(this.getRawValue()));
41368 parseValue : function(value)
41370 if(this.thousandsDelimiter) {
41372 r = new RegExp(",", "g");
41373 value = value.replace(r, "");
41376 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41377 return isNaN(value) ? '' : value;
41381 fixPrecision : function(value)
41383 if(this.thousandsDelimiter) {
41385 r = new RegExp(",", "g");
41386 value = value.replace(r, "");
41389 var nan = isNaN(value);
41391 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41392 return nan ? '' : value;
41394 return parseFloat(value).toFixed(this.decimalPrecision);
41397 decimalPrecisionFcn : function(v)
41399 return Math.floor(v);
41402 validateValue : function(value)
41404 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41408 var num = this.parseValue(value);
41411 this.markInvalid(String.format(this.nanText, value));
41415 if(num < this.minValue){
41416 this.markInvalid(String.format(this.minText, this.minValue));
41420 if(num > this.maxValue){
41421 this.markInvalid(String.format(this.maxText, this.maxValue));
41428 validate : function()
41430 if(this.disabled || this.allowBlank){
41435 var currency = this.getCurrency();
41437 if(this.validateValue(this.getRawValue()) && currency.length){
41442 this.markInvalid();
41446 getName: function()
41451 beforeBlur : function()
41457 var v = this.parseValue(this.getRawValue());
41464 onBlur : function()
41468 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41469 //this.el.removeClass(this.focusClass);
41472 this.hasFocus = false;
41474 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41478 var v = this.getValue();
41480 if(String(v) !== String(this.startValue)){
41481 this.fireEvent('change', this, v, this.startValue);
41484 this.fireEvent("blur", this);
41487 inputEl : function()
41489 return this.el.select('.roo-money-amount-input', true).first();
41492 currencyEl : function()
41494 return this.el.select('.roo-money-currency-input', true).first();
41497 hiddenEl : function()
41499 return this.el.select('input.hidden-number-input',true).first();
41503 * This script refer to:
41504 * Title: Signature Pad
41506 * Availability: https://github.com/szimek/signature_pad
41510 * @class Roo.bootstrap.BezierSignature
41511 * @extends Roo.bootstrap.Component
41512 * Bootstrap BezierSignature class
41515 * Create a new BezierSignature
41516 * @param {Object} config The config object
41519 Roo.bootstrap.BezierSignature = function(config){
41520 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41526 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component, {
41532 _mouseButtonDown: true,
41535 * @cfg(int) canvas height
41537 canvas_height: '200px',
41540 * @cfg(float or function) Radius of a single dot.
41545 * @cfg(float) Minimum width of a line. Defaults to 0.5.
41550 * @cfg(float) Maximum width of a line. Defaults to 2.5.
41555 * @cfg(integer) Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41560 * @cfg(integer) Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41565 * @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.
41567 backgroundColor: 'rgba(0, 0, 0, 0)',
41570 * @cfg(string) Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41575 * @cfg(float) Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41577 velocityFilterWeight: 0.7,
41580 * @cfg(function) Callback when stroke begin.
41585 * @cfg(function) Callback when stroke end.
41589 getAutoCreate : function()
41591 var cls = 'roo-signature column';
41594 cls += ' ' + this.cls;
41604 for(var i = 0; i < col_sizes.length; i++) {
41605 if(this[col_sizes[i]]) {
41606 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41616 cls: 'roo-signature-body',
41620 cls: 'roo-signature-body-canvas',
41621 height: this.canvas_height,
41622 width: this.canvas_width
41632 initEvents: function()
41634 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41636 var canvas = this.canvasEl();
41638 // mouse && touch event swapping...
41639 canvas.dom.style.touchAction = 'none';
41640 canvas.dom.style.msTouchAction = 'none';
41642 this._mouseButtonDown = false;
41643 canvas.on('mousedown', this._handleMouseDown, this);
41644 canvas.on('mousemove', this._handleMouseMove, this);
41645 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41647 if (window.ontouchstart) {
41648 canvas.on('touchstart', this._handleTouchStart, this);
41649 canvas.on('touchmove', this._handleTouchMove, this);
41650 canvas.on('touchend', this._handleTouchEnd, this);
41653 if(this.resize_to_parent_width) {
41654 Roo.EventManager.onWindowResize(this.resize, this, true);
41662 resize: function(){
41663 this.canvasEl().dom.width = this.el.dom.offsetWidth;
41666 _handleMouseDown: function(e)
41668 if (e.browserEvent.which === 1) {
41669 this._mouseButtonDown = true;
41670 this.strokeBegin(e);
41674 _handleMouseMove: function (e)
41676 if (this._mouseButtonDown) {
41677 this.strokeMoveUpdate(e);
41681 _handleMouseUp: function (e)
41683 if (e.browserEvent.which === 1 && this._mouseButtonDown) {
41684 this._mouseButtonDown = false;
41689 _handleTouchStart: function (e) {
41690 e.preventDefault();
41691 if (e.browserEvent.targetTouches.length === 1) {
41692 // var touch = e.browserEvent.changedTouches[0];
41693 // this.strokeBegin(touch);
41695 this.strokeBegin(e); // assume e catching the correct xy...
41699 _handleTouchMove: function (e) {
41700 e.preventDefault();
41701 // var touch = event.targetTouches[0];
41702 // _this._strokeMoveUpdate(touch);
41703 this._strokeMoveUpdate(e);
41706 _handleTouchEnd: function (e) {
41707 var wasCanvasTouched = e.target === this.canvasEl().dom;
41708 if (wasCanvasTouched) {
41709 e.preventDefault();
41710 // var touch = event.changedTouches[0];
41711 // _this._strokeEnd(touch);
41716 reset: function () {
41717 this._lastPoints = [];
41718 this._lastVelocity = 0;
41719 this._lastWidth = (this.minWidth + this.maxWidth) / 2;
41720 this.canvasElCtx().fillStyle = this.penColor;
41723 strokeMoveUpdate: function(e)
41725 this.strokeUpdate(e);
41727 if (this.throttle) {
41728 this.throttle(this.strokeUpdate, this.throttle);
41731 this.strokeUpdate(e);
41735 strokeBegin: function(e)
41737 var newPointGroup = {
41738 color: this.penColor,
41742 if (typeof this.onBegin === 'function') {
41746 this._data.push(newPointGroup);
41748 this.strokeUpdate(e);
41751 strokeUpdate: function(e)
41753 var rect = this.canvasEl().dom.getBoundingClientRect();
41754 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41755 var lastPointGroup = this._data[this._data.length - 1];
41756 var lastPoints = lastPointGroup.points;
41757 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41758 var isLastPointTooClose = lastPoint
41759 ? point.distanceTo(lastPoint) <= this.minDistance
41761 var color = lastPointGroup.color;
41762 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41763 var curve = this.addPoint(point);
41765 this.drawDot({color: color, point: point});
41768 this.drawCurve({color: color, curve: curve});
41778 strokeEnd: function(e)
41780 this.strokeUpdate(e);
41781 if (typeof this.onEnd === 'function') {
41786 addPoint: function (point) {
41787 var _lastPoints = this._lastPoints;
41788 _lastPoints.push(point);
41789 if (_lastPoints.length > 2) {
41790 if (_lastPoints.length === 3) {
41791 _lastPoints.unshift(_lastPoints[0]);
41793 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41794 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41795 _lastPoints.shift();
41801 calculateCurveWidths: function (startPoint, endPoint) {
41802 var velocity = this.velocityFilterWeight * endPoint.velocityFrom(startPoint) +
41803 (1 - this.velocityFilterWeight) * this._lastVelocity;
41805 var newWidth = Math.max(this.maxWidth / (velocity + 1), this.minWidth);
41808 start: this._lastWidth
41811 this._lastVelocity = velocity;
41812 this._lastWidth = newWidth;
41816 drawDot: function (_a) {
41817 var color = _a.color, point = _a.point;
41818 var ctx = this.canvasElCtx();
41819 var width = typeof this.dotSize === 'function' ? this.dotSize() : this.dotSize;
41821 this.drawCurveSegment(point.x, point.y, width);
41823 ctx.fillStyle = color;
41827 drawCurve: function (_a) {
41828 var color = _a.color, curve = _a.curve;
41829 var ctx = this.canvasElCtx();
41830 var widthDelta = curve.endWidth - curve.startWidth;
41831 var drawSteps = Math.floor(curve.length()) * 2;
41833 ctx.fillStyle = color;
41834 for (var i = 0; i < drawSteps; i += 1) {
41835 var t = i / drawSteps;
41841 var x = uuu * curve.startPoint.x;
41842 x += 3 * uu * t * curve.control1.x;
41843 x += 3 * u * tt * curve.control2.x;
41844 x += ttt * curve.endPoint.x;
41845 var y = uuu * curve.startPoint.y;
41846 y += 3 * uu * t * curve.control1.y;
41847 y += 3 * u * tt * curve.control2.y;
41848 y += ttt * curve.endPoint.y;
41849 var width = curve.startWidth + ttt * widthDelta;
41850 this.drawCurveSegment(x, y, width);
41856 drawCurveSegment: function (x, y, width) {
41857 var ctx = this.canvasElCtx();
41859 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
41860 this._isEmpty = false;
41865 var ctx = this.canvasElCtx();
41866 var canvas = this.canvasEl().dom;
41867 ctx.fillStyle = this.backgroundColor;
41868 ctx.clearRect(0, 0, canvas.width, canvas.height);
41869 ctx.fillRect(0, 0, canvas.width, canvas.height);
41872 this._isEmpty = true;
41875 canvasEl: function()
41877 return this.el.select('canvas',true).first();
41880 canvasElCtx: function()
41882 return this.el.select('canvas',true).first().dom.getContext('2d');
41885 getImage: function(type)
41887 if(this._isEmpty) {
41892 return this.canvasEl().dom.toDataURL('image/'+type, false);
41895 drawFromImage: function(img_src)
41897 var img = new Image();
41901 this.canvasElCtx().drawImage(img, 0, 0);
41904 // Bezier Point Constructor
41905 Point: (function () {
41906 function Point(x, y, time) {
41909 this.time = time || Date.now();
41911 Point.prototype.distanceTo = function (start) {
41912 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
41914 Point.prototype.equals = function (other) {
41915 return this.x === other.x && this.y === other.y && this.time === other.time;
41917 Point.prototype.velocityFrom = function (start) {
41918 return this.time !== start.time
41919 ? this.distanceTo(start) / (this.time - start.time)
41926 // Bezier Constructor
41927 Bezier: (function () {
41928 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
41929 this.startPoint = startPoint;
41930 this.control2 = control2;
41931 this.control1 = control1;
41932 this.endPoint = endPoint;
41933 this.startWidth = startWidth;
41934 this.endWidth = endWidth;
41936 Bezier.fromPoints = function (points, widths, scope) {
41937 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
41938 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
41939 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
41941 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
41942 var dx1 = s1.x - s2.x;
41943 var dy1 = s1.y - s2.y;
41944 var dx2 = s2.x - s3.x;
41945 var dy2 = s2.y - s3.y;
41946 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
41947 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
41948 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
41949 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
41950 var dxm = m1.x - m2.x;
41951 var dym = m1.y - m2.y;
41952 var k = l2 / (l1 + l2);
41953 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
41954 var tx = s2.x - cm.x;
41955 var ty = s2.y - cm.y;
41957 c1: new scope.Point(m1.x + tx, m1.y + ty),
41958 c2: new scope.Point(m2.x + tx, m2.y + ty)
41961 Bezier.prototype.length = function () {
41966 for (var i = 0; i <= steps; i += 1) {
41968 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
41969 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
41971 var xdiff = cx - px;
41972 var ydiff = cy - py;
41973 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
41980 Bezier.prototype.point = function (t, start, c1, c2, end) {
41981 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
41982 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
41983 + (3.0 * c2 * (1.0 - t) * t * t)
41984 + (end * t * t * t);
41989 throttle: function(fn, wait) {
41990 if (wait === void 0) { wait = 250; }
41992 var timeout = null;
41996 var later = function () {
41997 previous = Date.now();
41999 result = fn.apply(storedContext, storedArgs);
42001 storedContext = null;
42005 return function wrapper() {
42007 for (var _i = 0; _i < arguments.length; _i++) {
42008 args[_i] = arguments[_i];
42010 var now = Date.now();
42011 var remaining = wait - (now - previous);
42012 storedContext = this;
42014 if (remaining <= 0 || remaining > wait) {
42016 clearTimeout(timeout);
42020 result = fn.apply(storedContext, storedArgs);
42022 storedContext = null;
42026 else if (!timeout) {
42027 timeout = window.setTimeout(later, remaining);