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 (return false to block)
2064 * @param {Roo.menu.Menu} this
2069 * Fires before this menu is hidden (return false to block)
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)
2293 if (false === this.fireEvent("beforeshow", this)) {
2294 Roo.log("show canceled");
2297 this.parentMenu = parentMenu;
2302 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
2305 * Displays this menu at a specific xy position
2306 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
2307 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
2309 showAt : function(xy, parentMenu, /* private: */_e){
2310 this.parentMenu = parentMenu;
2315 this.fireEvent("beforeshow", this);
2316 //xy = this.el.adjustForConstraints(xy);
2320 this.hideMenuItems();
2321 this.hidden = false;
2322 this.triggerEl.addClass('open');
2323 this.el.addClass('show');
2325 // reassign x when hitting right
2326 if(this.el.getWidth() + xy[0] >= Roo.lib.Dom.getViewWidth()){
2327 xy[0] = xy[0] - this.el.getWidth() + this.triggerEl.getWidth();
2330 // reassign y when hitting bottom
2331 if(this.el.getHeight() + xy[1] >= Roo.lib.Dom.getViewHeight()){
2332 xy[1] = xy[1] - this.el.getHeight() - this.triggerEl.getHeight();
2335 // but the list may align on trigger left or trigger top... should it be a properity?
2337 if(this.el.getStyle('top') != 'auto' && this.el.getStyle('top').slice(-1) != "%"){
2342 this.fireEvent("show", this);
2348 this.doFocus.defer(50, this);
2352 doFocus : function(){
2354 this.focusEl.focus();
2359 * Hides this menu and optionally all parent menus
2360 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
2362 hide : function(deep)
2364 if (false === this.fireEvent("beforehide", this)) {
2365 Roo.log("hide canceled");
2368 this.hideMenuItems();
2369 if(this.el && this.isVisible()){
2371 if(this.activeItem){
2372 this.activeItem.deactivate();
2373 this.activeItem = null;
2375 this.triggerEl.removeClass('open');;
2376 this.el.removeClass('show');
2378 this.fireEvent("hide", this);
2380 if(deep === true && this.parentMenu){
2381 this.parentMenu.hide(true);
2385 onTriggerClick : function(e)
2387 Roo.log('trigger click');
2389 var target = e.getTarget();
2391 Roo.log(target.nodeName.toLowerCase());
2393 if(target.nodeName.toLowerCase() === 'i'){
2399 onTriggerPress : function(e)
2401 Roo.log('trigger press');
2402 //Roo.log(e.getTarget());
2403 // Roo.log(this.triggerEl.dom);
2405 // trigger only occurs on normal menu's -- if it's a treeview or dropdown... do not hide/show..
2406 var pel = Roo.get(e.getTarget());
2407 if (pel.findParent('.dropdown-menu') || pel.findParent('.treeview-menu') ) {
2408 Roo.log('is treeview or dropdown?');
2412 if(e.getTarget().nodeName.toLowerCase() !== 'i' && this.isLink){
2416 if (this.isVisible()) {
2421 this.show(this.triggerEl, '?', false);
2424 if(this.stopEvent || e.getTarget().nodeName.toLowerCase() === 'i'){
2431 hideMenuItems : function()
2433 Roo.log("hide Menu Items");
2438 this.el.select('.open',true).each(function(aa) {
2440 aa.removeClass('open');
2444 addxtypeChild : function (tree, cntr) {
2445 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
2447 this.menuitems.add(comp);
2459 this.getEl().dom.innerHTML = '';
2460 this.menuitems.clear();
2474 * @class Roo.bootstrap.MenuItem
2475 * @extends Roo.bootstrap.Component
2476 * Bootstrap MenuItem class
2477 * @cfg {String} html the menu label
2478 * @cfg {String} href the link
2479 * @cfg {Boolean} preventDefault do not trigger A href on clicks (default false).
2480 * @cfg {Boolean} isContainer is it a container - just returns a drop down item..
2481 * @cfg {Boolean} active used on sidebars to highlight active itesm
2482 * @cfg {String} fa favicon to show on left of menu item.
2483 * @cfg {Roo.bootsrap.Menu} menu the child menu.
2487 * Create a new MenuItem
2488 * @param {Object} config The config object
2492 Roo.bootstrap.MenuItem = function(config){
2493 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
2498 * The raw click event for the entire grid.
2499 * @param {Roo.bootstrap.MenuItem} this
2500 * @param {Roo.EventObject} e
2506 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
2510 preventDefault: false,
2511 isContainer : false,
2515 getAutoCreate : function(){
2517 if(this.isContainer){
2520 cls: 'dropdown-menu-item '
2530 cls : 'dropdown-item',
2535 if (this.fa !== false) {
2538 cls : 'fa fa-' + this.fa
2547 cls: 'dropdown-menu-item',
2550 if (this.parent().type == 'treeview') {
2551 cfg.cls = 'treeview-menu';
2554 cfg.cls += ' active';
2559 anc.href = this.href || cfg.cn[0].href ;
2560 ctag.html = this.html || cfg.cn[0].html ;
2564 initEvents: function()
2566 if (this.parent().type == 'treeview') {
2567 this.el.select('a').on('click', this.onClick, this);
2571 this.menu.parentType = this.xtype;
2572 this.menu.triggerEl = this.el;
2573 this.menu = this.addxtype(Roo.apply({}, this.menu));
2577 onClick : function(e)
2579 Roo.log('item on click ');
2581 if(this.preventDefault){
2584 //this.parent().hideMenuItems();
2586 this.fireEvent('click', this, e);
2605 * @class Roo.bootstrap.MenuSeparator
2606 * @extends Roo.bootstrap.Component
2607 * Bootstrap MenuSeparator class
2610 * Create a new MenuItem
2611 * @param {Object} config The config object
2615 Roo.bootstrap.MenuSeparator = function(config){
2616 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
2619 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
2621 getAutoCreate : function(){
2640 * @class Roo.bootstrap.Modal
2641 * @extends Roo.bootstrap.Component
2642 * Bootstrap Modal class
2643 * @cfg {String} title Title of dialog
2644 * @cfg {String} html - the body of the dialog (for simple ones) - you can also use template..
2645 * @cfg {Roo.Template} tmpl - a template with variables. to use it, add a handler in show:method adn
2646 * @cfg {Boolean} specificTitle default false
2647 * @cfg {Array} buttons Array of buttons or standard button set..
2648 * @cfg {String} buttonPosition (left|right|center) default right (DEPRICATED) - use mr-auto on buttons to put them on the left
2649 * @cfg {Boolean} animate default true
2650 * @cfg {Boolean} allow_close default true
2651 * @cfg {Boolean} fitwindow default false
2652 * @cfg {String} size (sm|lg) default empty
2653 * @cfg {Number} max_width set the max width of modal
2657 * Create a new Modal Dialog
2658 * @param {Object} config The config object
2661 Roo.bootstrap.Modal = function(config){
2662 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
2667 * The raw btnclick event for the button
2668 * @param {Roo.EventObject} e
2673 * Fire when dialog resize
2674 * @param {Roo.bootstrap.Modal} this
2675 * @param {Roo.EventObject} e
2679 this.buttons = this.buttons || [];
2682 this.tmpl = Roo.factory(this.tmpl);
2687 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
2689 title : 'test dialog',
2699 specificTitle: false,
2701 buttonPosition: 'right',
2724 onRender : function(ct, position)
2726 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
2729 var cfg = Roo.apply({}, this.getAutoCreate());
2732 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
2734 //if (!cfg.name.length) {
2738 cfg.cls += ' ' + this.cls;
2741 cfg.style = this.style;
2743 this.el = Roo.get(document.body).createChild(cfg, position);
2745 //var type = this.el.dom.type;
2748 if(this.tabIndex !== undefined){
2749 this.el.dom.setAttribute('tabIndex', this.tabIndex);
2752 this.dialogEl = this.el.select('.modal-dialog',true).first();
2753 this.bodyEl = this.el.select('.modal-body',true).first();
2754 this.closeEl = this.el.select('.modal-header .close', true).first();
2755 this.headerEl = this.el.select('.modal-header',true).first();
2756 this.titleEl = this.el.select('.modal-title',true).first();
2757 this.footerEl = this.el.select('.modal-footer',true).first();
2759 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
2761 //this.el.addClass("x-dlg-modal");
2763 if (this.buttons.length) {
2764 Roo.each(this.buttons, function(bb) {
2765 var b = Roo.apply({}, bb);
2766 b.xns = b.xns || Roo.bootstrap;
2767 b.xtype = b.xtype || 'Button';
2768 if (typeof(b.listeners) == 'undefined') {
2769 b.listeners = { click : this.onButtonClick.createDelegate(this) };
2772 var btn = Roo.factory(b);
2774 btn.render(this.getButtonContainer());
2778 // render the children.
2781 if(typeof(this.items) != 'undefined'){
2782 var items = this.items;
2785 for(var i =0;i < items.length;i++) {
2786 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2790 this.items = nitems;
2792 // where are these used - they used to be body/close/footer
2796 //this.el.addClass([this.fieldClass, this.cls]);
2800 getAutoCreate : function()
2804 html : this.html || ''
2809 cls : 'modal-title',
2813 if(this.specificTitle){
2819 if (this.allow_close && Roo.bootstrap.version == 3) {
2829 if (this.allow_close && Roo.bootstrap.version == 4) {
2839 if(this.size.length){
2840 size = 'modal-' + this.size;
2843 var footer = Roo.bootstrap.version == 3 ?
2845 cls : 'modal-footer',
2849 cls: 'btn-' + this.buttonPosition
2854 { // BS4 uses mr-auto on left buttons....
2855 cls : 'modal-footer'
2866 cls: "modal-dialog " + size,
2869 cls : "modal-content",
2872 cls : 'modal-header',
2887 modal.cls += ' fade';
2893 getChildContainer : function() {
2898 getButtonContainer : function() {
2900 return Roo.bootstrap.version == 4 ?
2901 this.el.select('.modal-footer',true).first()
2902 : this.el.select('.modal-footer div',true).first();
2905 initEvents : function()
2907 if (this.allow_close) {
2908 this.closeEl.on('click', this.hide, this);
2910 Roo.EventManager.onWindowResize(this.resize, this, true);
2918 this.maskEl.setSize(
2919 Roo.lib.Dom.getViewWidth(true),
2920 Roo.lib.Dom.getViewHeight(true)
2923 if (this.fitwindow) {
2927 this.width || Roo.lib.Dom.getViewportWidth(true) - 30,
2928 this.height || Roo.lib.Dom.getViewportHeight(true) // catering margin-top 30 margin-bottom 30
2933 if(this.max_width !== 0) {
2935 var w = Math.min(this.max_width, Roo.lib.Dom.getViewportWidth(true) - 30);
2938 this.setSize(w, this.height);
2942 if(this.max_height) {
2943 this.setSize(w,Math.min(
2945 Roo.lib.Dom.getViewportHeight(true) - 60
2951 if(!this.fit_content) {
2952 this.setSize(w, Roo.lib.Dom.getViewportHeight(true) - 60);
2956 this.setSize(w, Math.min(
2958 this.headerEl.getHeight() +
2959 this.footerEl.getHeight() +
2960 this.getChildHeight(this.bodyEl.dom.childNodes),
2961 Roo.lib.Dom.getViewportHeight(true) - 60)
2967 setSize : function(w,h)
2978 if (!this.rendered) {
2982 //this.el.setStyle('display', 'block');
2983 this.el.removeClass('hideing');
2984 this.el.dom.style.display='block';
2986 Roo.get(document.body).addClass('modal-open');
2988 if(this.animate){ // element has 'fade' - so stuff happens after .3s ?- not sure why the delay?
2991 this.el.addClass('show');
2992 this.el.addClass('in');
2995 this.el.addClass('show');
2996 this.el.addClass('in');
2999 // not sure how we can show data in here..
3001 // this.getChildContainer().dom.innerHTML = this.tmpl.applyTemplate(this);
3004 Roo.get(document.body).addClass("x-body-masked");
3006 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
3007 this.maskEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3008 this.maskEl.dom.style.display = 'block';
3009 this.maskEl.addClass('show');
3014 this.fireEvent('show', this);
3016 // set zindex here - otherwise it appears to be ignored...
3017 this.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
3020 this.items.forEach( function(e) {
3021 e.layout ? e.layout() : false;
3029 if(this.fireEvent("beforehide", this) !== false){
3031 this.maskEl.removeClass('show');
3033 this.maskEl.dom.style.display = '';
3034 Roo.get(document.body).removeClass("x-body-masked");
3035 this.el.removeClass('in');
3036 this.el.select('.modal-dialog', true).first().setStyle('transform','');
3038 if(this.animate){ // why
3039 this.el.addClass('hideing');
3040 this.el.removeClass('show');
3042 if (!this.el.hasClass('hideing')) {
3043 return; // it's been shown again...
3046 this.el.dom.style.display='';
3048 Roo.get(document.body).removeClass('modal-open');
3049 this.el.removeClass('hideing');
3053 this.el.removeClass('show');
3054 this.el.dom.style.display='';
3055 Roo.get(document.body).removeClass('modal-open');
3058 this.fireEvent('hide', this);
3061 isVisible : function()
3064 return this.el.hasClass('show') && !this.el.hasClass('hideing');
3068 addButton : function(str, cb)
3072 var b = Roo.apply({}, { html : str } );
3073 b.xns = b.xns || Roo.bootstrap;
3074 b.xtype = b.xtype || 'Button';
3075 if (typeof(b.listeners) == 'undefined') {
3076 b.listeners = { click : cb.createDelegate(this) };
3079 var btn = Roo.factory(b);
3081 btn.render(this.getButtonContainer());
3087 setDefaultButton : function(btn)
3089 //this.el.select('.modal-footer').()
3092 resizeTo: function(w,h)
3094 this.dialogEl.setWidth(w);
3096 var diff = this.headerEl.getHeight() + this.footerEl.getHeight() + 60; // dialog margin-bottom: 30
3098 this.bodyEl.setHeight(h - diff);
3100 this.fireEvent('resize', this);
3103 setContentSize : function(w, h)
3107 onButtonClick: function(btn,e)
3110 this.fireEvent('btnclick', btn.name, e);
3113 * Set the title of the Dialog
3114 * @param {String} str new Title
3116 setTitle: function(str) {
3117 this.titleEl.dom.innerHTML = str;
3120 * Set the body of the Dialog
3121 * @param {String} str new Title
3123 setBody: function(str) {
3124 this.bodyEl.dom.innerHTML = str;
3127 * Set the body of the Dialog using the template
3128 * @param {Obj} data - apply this data to the template and replace the body contents.
3130 applyBody: function(obj)
3133 Roo.log("Error - using apply Body without a template");
3136 this.tmpl.overwrite(this.bodyEl, obj);
3139 getChildHeight : function(child_nodes)
3143 child_nodes.length == 0
3148 var child_height = 0;
3150 for(var i = 0; i < child_nodes.length; i++) {
3153 * for modal with tabs...
3154 if(child_nodes[i].classList.contains('roo-layout-panel')) {
3156 var layout_childs = child_nodes[i].childNodes;
3158 for(var j = 0; j < layout_childs.length; j++) {
3160 if(layout_childs[j].classList.contains('roo-layout-panel-body')) {
3162 var layout_body_childs = layout_childs[j].childNodes;
3164 for(var k = 0; k < layout_body_childs.length; k++) {
3166 if(layout_body_childs[k].classList.contains('navbar')) {
3167 child_height += layout_body_childs[k].offsetHeight;
3171 if(layout_body_childs[k].classList.contains('roo-layout-tabs-body')) {
3173 var layout_body_tab_childs = layout_body_childs[k].childNodes;
3175 for(var m = 0; m < layout_body_tab_childs.length; m++) {
3177 if(layout_body_tab_childs[m].classList.contains('roo-layout-active-content')) {
3178 child_height += this.getChildHeight(layout_body_tab_childs[m].childNodes);
3193 child_height += child_nodes[i].offsetHeight;
3194 // Roo.log(child_nodes[i].offsetHeight);
3197 return child_height;
3203 Roo.apply(Roo.bootstrap.Modal, {
3205 * Button config that displays a single OK button
3214 * Button config that displays Yes and No buttons
3230 * Button config that displays OK and Cancel buttons
3245 * Button config that displays Yes, No and Cancel buttons
3269 * messagebox - can be used as a replace
3273 * @class Roo.MessageBox
3274 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
3278 Roo.Msg.alert('Status', 'Changes saved successfully.');
3280 // Prompt for user data:
3281 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
3283 // process text value...
3287 // Show a dialog using config options:
3289 title:'Save Changes?',
3290 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
3291 buttons: Roo.Msg.YESNOCANCEL,
3298 Roo.bootstrap.MessageBox = function(){
3299 var dlg, opt, mask, waitTimer;
3300 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
3301 var buttons, activeTextEl, bwidth;
3305 var handleButton = function(button){
3307 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
3311 var handleHide = function(){
3313 dlg.el.removeClass(opt.cls);
3316 // Roo.TaskMgr.stop(waitTimer);
3317 // waitTimer = null;
3322 var updateButtons = function(b){
3325 buttons["ok"].hide();
3326 buttons["cancel"].hide();
3327 buttons["yes"].hide();
3328 buttons["no"].hide();
3329 dlg.footerEl.hide();
3333 dlg.footerEl.show();
3334 for(var k in buttons){
3335 if(typeof buttons[k] != "function"){
3338 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
3339 width += buttons[k].el.getWidth()+15;
3349 var handleEsc = function(d, k, e){
3350 if(opt && opt.closable !== false){
3360 * Returns a reference to the underlying {@link Roo.BasicDialog} element
3361 * @return {Roo.BasicDialog} The BasicDialog element
3363 getDialog : function(){
3365 dlg = new Roo.bootstrap.Modal( {
3368 //constraintoviewport:false,
3370 //collapsible : false,
3375 //buttonAlign:"center",
3376 closeClick : function(){
3377 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
3380 handleButton("cancel");
3385 dlg.on("hide", handleHide);
3387 //dlg.addKeyListener(27, handleEsc);
3389 this.buttons = buttons;
3390 var bt = this.buttonText;
3391 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
3392 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
3393 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
3394 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
3396 bodyEl = dlg.bodyEl.createChild({
3398 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
3399 '<textarea class="roo-mb-textarea"></textarea>' +
3400 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
3402 msgEl = bodyEl.dom.firstChild;
3403 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
3404 textboxEl.enableDisplayMode();
3405 textboxEl.addKeyListener([10,13], function(){
3406 if(dlg.isVisible() && opt && opt.buttons){
3409 }else if(opt.buttons.yes){
3410 handleButton("yes");
3414 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
3415 textareaEl.enableDisplayMode();
3416 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
3417 progressEl.enableDisplayMode();
3419 // This is supposed to be the progessElement.. but I think it's controlling the height of everything..
3420 var pf = progressEl.dom.firstChild;
3422 pp = Roo.get(pf.firstChild);
3423 pp.setHeight(pf.offsetHeight);
3431 * Updates the message box body text
3432 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
3433 * the XHTML-compliant non-breaking space character '&#160;')
3434 * @return {Roo.MessageBox} This message box
3436 updateText : function(text)
3438 if(!dlg.isVisible() && !opt.width){
3439 dlg.dialogEl.setStyle({ 'max-width' : this.maxWidth});
3440 // dlg.resizeTo(this.maxWidth, 100); // forcing the height breaks long alerts()
3442 msgEl.innerHTML = text || ' ';
3444 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
3445 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
3447 Math.min(opt.width || cw , this.maxWidth),
3448 Math.max(opt.minWidth || this.minWidth, bwidth)
3451 activeTextEl.setWidth(w);
3453 if(dlg.isVisible()){
3454 dlg.fixedcenter = false;
3456 // to big, make it scroll. = But as usual stupid IE does not support
3459 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
3460 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
3461 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
3463 bodyEl.dom.style.height = '';
3464 bodyEl.dom.style.overflowY = '';
3467 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
3469 bodyEl.dom.style.overflowX = '';
3472 dlg.setContentSize(w, bodyEl.getHeight());
3473 if(dlg.isVisible()){
3474 dlg.fixedcenter = true;
3480 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
3481 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
3482 * @param {Number} value Any number between 0 and 1 (e.g., .5)
3483 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
3484 * @return {Roo.MessageBox} This message box
3486 updateProgress : function(value, text){
3488 this.updateText(text);
3491 if (pp) { // weird bug on my firefox - for some reason this is not defined
3492 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
3493 pp.setHeight(Math.floor(progressEl.dom.firstChild.offsetHeight));
3499 * Returns true if the message box is currently displayed
3500 * @return {Boolean} True if the message box is visible, else false
3502 isVisible : function(){
3503 return dlg && dlg.isVisible();
3507 * Hides the message box if it is displayed
3510 if(this.isVisible()){
3516 * Displays a new message box, or reinitializes an existing message box, based on the config options
3517 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
3518 * The following config object properties are supported:
3520 Property Type Description
3521 ---------- --------------- ------------------------------------------------------------------------------------
3522 animEl String/Element An id or Element from which the message box should animate as it opens and
3523 closes (defaults to undefined)
3524 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
3525 cancel:'Bar'}), or false to not show any buttons (defaults to false)
3526 closable Boolean False to hide the top-right close button (defaults to true). Note that
3527 progress and wait dialogs will ignore this property and always hide the
3528 close button as they can only be closed programmatically.
3529 cls String A custom CSS class to apply to the message box element
3530 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
3531 displayed (defaults to 75)
3532 fn Function A callback function to execute after closing the dialog. The arguments to the
3533 function will be btn (the name of the button that was clicked, if applicable,
3534 e.g. "ok"), and text (the value of the active text field, if applicable).
3535 Progress and wait dialogs will ignore this option since they do not respond to
3536 user actions and can only be closed programmatically, so any required function
3537 should be called by the same code after it closes the dialog.
3538 icon String A CSS class that provides a background image to be used as an icon for
3539 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
3540 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
3541 minWidth Number The minimum width in pixels of the message box (defaults to 100)
3542 modal Boolean False to allow user interaction with the page while the message box is
3543 displayed (defaults to true)
3544 msg String A string that will replace the existing message box body text (defaults
3545 to the XHTML-compliant non-breaking space character ' ')
3546 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
3547 progress Boolean True to display a progress bar (defaults to false)
3548 progressText String The text to display inside the progress bar if progress = true (defaults to '')
3549 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
3550 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
3551 title String The title text
3552 value String The string value to set into the active textbox element if displayed
3553 wait Boolean True to display a progress bar (defaults to false)
3554 width Number The width of the dialog in pixels
3561 msg: 'Please enter your address:',
3563 buttons: Roo.MessageBox.OKCANCEL,
3566 animEl: 'addAddressBtn'
3569 * @param {Object} config Configuration options
3570 * @return {Roo.MessageBox} This message box
3572 show : function(options)
3575 // this causes nightmares if you show one dialog after another
3576 // especially on callbacks..
3578 if(this.isVisible()){
3581 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
3582 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
3583 Roo.log("New Dialog Message:" + options.msg )
3584 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
3585 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
3588 var d = this.getDialog();
3590 d.setTitle(opt.title || " ");
3591 d.closeEl.setDisplayed(opt.closable !== false);
3592 activeTextEl = textboxEl;
3593 opt.prompt = opt.prompt || (opt.multiline ? true : false);
3598 textareaEl.setHeight(typeof opt.multiline == "number" ?
3599 opt.multiline : this.defaultTextHeight);
3600 activeTextEl = textareaEl;
3609 progressEl.setDisplayed(opt.progress === true);
3611 d.animate = false; // do not animate progress, as it may not have finished animating before we close it..
3613 this.updateProgress(0);
3614 activeTextEl.dom.value = opt.value || "";
3616 dlg.setDefaultButton(activeTextEl);
3618 var bs = opt.buttons;
3622 }else if(bs && bs.yes){
3623 db = buttons["yes"];
3625 dlg.setDefaultButton(db);
3627 bwidth = updateButtons(opt.buttons);
3628 this.updateText(opt.msg);
3630 d.el.addClass(opt.cls);
3632 d.proxyDrag = opt.proxyDrag === true;
3633 d.modal = opt.modal !== false;
3634 d.mask = opt.modal !== false ? mask : false;
3636 // force it to the end of the z-index stack so it gets a cursor in FF
3637 document.body.appendChild(dlg.el.dom);
3638 d.animateTarget = null;
3639 d.show(options.animEl);
3645 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
3646 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
3647 * and closing the message box when the process is complete.
3648 * @param {String} title The title bar text
3649 * @param {String} msg The message box body text
3650 * @return {Roo.MessageBox} This message box
3652 progress : function(title, msg){
3659 minWidth: this.minProgressWidth,
3666 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
3667 * If a callback function is passed it will be called after the user clicks the button, and the
3668 * id of the button that was clicked will be passed as the only parameter to the callback
3669 * (could also be the top-right close button).
3670 * @param {String} title The title bar text
3671 * @param {String} msg The message box body text
3672 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3673 * @param {Object} scope (optional) The scope of the callback function
3674 * @return {Roo.MessageBox} This message box
3676 alert : function(title, msg, fn, scope)
3691 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
3692 * interaction while waiting for a long-running process to complete that does not have defined intervals.
3693 * You are responsible for closing the message box when the process is complete.
3694 * @param {String} msg The message box body text
3695 * @param {String} title (optional) The title bar text
3696 * @return {Roo.MessageBox} This message box
3698 wait : function(msg, title){
3709 waitTimer = Roo.TaskMgr.start({
3711 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
3719 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
3720 * If a callback function is passed it will be called after the user clicks either button, and the id of the
3721 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
3722 * @param {String} title The title bar text
3723 * @param {String} msg The message box body text
3724 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3725 * @param {Object} scope (optional) The scope of the callback function
3726 * @return {Roo.MessageBox} This message box
3728 confirm : function(title, msg, fn, scope){
3732 buttons: this.YESNO,
3741 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
3742 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
3743 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
3744 * (could also be the top-right close button) and the text that was entered will be passed as the two
3745 * parameters to the callback.
3746 * @param {String} title The title bar text
3747 * @param {String} msg The message box body text
3748 * @param {Function} fn (optional) The callback function invoked after the message box is closed
3749 * @param {Object} scope (optional) The scope of the callback function
3750 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
3751 * property, or the height in pixels to create the textbox (defaults to false / single-line)
3752 * @return {Roo.MessageBox} This message box
3754 prompt : function(title, msg, fn, scope, multiline){
3758 buttons: this.OKCANCEL,
3763 multiline: multiline,
3770 * Button config that displays a single OK button
3775 * Button config that displays Yes and No buttons
3778 YESNO : {yes:true, no:true},
3780 * Button config that displays OK and Cancel buttons
3783 OKCANCEL : {ok:true, cancel:true},
3785 * Button config that displays Yes, No and Cancel buttons
3788 YESNOCANCEL : {yes:true, no:true, cancel:true},
3791 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
3794 defaultTextHeight : 75,
3796 * The maximum width in pixels of the message box (defaults to 600)
3801 * The minimum width in pixels of the message box (defaults to 100)
3806 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
3807 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
3810 minProgressWidth : 250,
3812 * An object containing the default button text strings that can be overriden for localized language support.
3813 * Supported properties are: ok, cancel, yes and no.
3814 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
3827 * Shorthand for {@link Roo.MessageBox}
3829 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox;
3830 Roo.Msg = Roo.Msg || Roo.MessageBox;
3839 * @class Roo.bootstrap.Navbar
3840 * @extends Roo.bootstrap.Component
3841 * Bootstrap Navbar class
3844 * Create a new Navbar
3845 * @param {Object} config The config object
3849 Roo.bootstrap.Navbar = function(config){
3850 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
3854 * @event beforetoggle
3855 * Fire before toggle the menu
3856 * @param {Roo.EventObject} e
3858 "beforetoggle" : true
3862 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
3871 getAutoCreate : function(){
3874 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
3878 initEvents :function ()
3880 //Roo.log(this.el.select('.navbar-toggle',true));
3881 this.el.select('.navbar-toggle',true).on('click', this.onToggle , this);
3888 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
3890 var size = this.el.getSize();
3891 this.maskEl.setSize(size.width, size.height);
3892 this.maskEl.enableDisplayMode("block");
3901 getChildContainer : function()
3903 if (this.el && this.el.select('.collapse').getCount()) {
3904 return this.el.select('.collapse',true).first();
3919 onToggle : function()
3922 if(this.fireEvent('beforetoggle', this) === false){
3925 var ce = this.el.select('.navbar-collapse',true).first();
3927 if (ce.hasClass('collapse')) {
3937 * Expand the navbar pulldown
3939 expand : function ()
3941 var ce = this.el.select('.navbar-collapse',true).first();
3943 ce.addClass('in'); // old...
3944 ce.removeClass('collapse');
3945 ce.addClass('show');
3946 var h = ce.getHeight();
3948 ce.removeClass('show');
3949 // at this point we should be able to see it..
3950 ce.addClass('collapsing');
3952 ce.setHeight(0); // resize it ...
3953 ce.on('transitionend', function() {
3954 //Roo.log('done transition');
3955 ce.removeClass('collapsing');
3956 ce.addClass('show');
3957 ce.removeClass('collapse');
3959 ce.dom.style.height = '';
3960 }, this, { single: true} );
3964 * Collapse the navbar pulldown
3966 collapse : function()
3968 var ce = this.el.select('.navbar-collapse',true).first();
3969 ce.removeClass('in'); // old...
3970 ce.setHeight(ce.getHeight());
3971 ce.removeClass('show');
3972 ce.addClass('collapsing');
3974 ce.on('transitionend', function() {
3975 ce.dom.style.height = '';
3976 ce.removeClass('collapsing');
3977 ce.addClass('collapse');
3978 }, this, { single: true} );
3998 * @class Roo.bootstrap.NavSimplebar
3999 * @extends Roo.bootstrap.Navbar
4000 * Bootstrap Sidebar class
4002 * @cfg {Boolean} inverse is inverted color
4004 * @cfg {String} type (nav | pills | tabs)
4005 * @cfg {Boolean} arrangement stacked | justified
4006 * @cfg {String} align (left | right) alignment
4008 * @cfg {Boolean} main (true|false) main nav bar? default false
4009 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
4011 * @cfg {String} tag (header|footer|nav|div) default is nav
4013 * @cfg {String} weight (light|primary|secondary|success|danger|warning|info|dark|white) default is light.
4017 * Create a new Sidebar
4018 * @param {Object} config The config object
4022 Roo.bootstrap.NavSimplebar = function(config){
4023 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
4026 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
4042 getAutoCreate : function(){
4046 tag : this.tag || 'div',
4047 cls : 'navbar navbar-expand-lg roo-navbar-simple'
4049 if (['light','white'].indexOf(this.weight) > -1) {
4050 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4052 cfg.cls += ' bg-' + this.weight;
4055 cfg.cls += ' navbar-inverse';
4059 // i'm not actually sure these are really used - normally we add a navGroup to a navbar
4061 //if (Roo.bootstrap.version == 4) {
4073 this.type = this.type || 'nav';
4074 if (['tabs','pills'].indexOf(this.type) != -1) {
4075 cfg.cn[0].cls += ' nav-' + this.type
4079 if (this.type!=='nav') {
4080 Roo.log('nav type must be nav/tabs/pills')
4082 cfg.cn[0].cls += ' navbar-nav'
4088 if (['stacked','justified'].indexOf(this.arrangement) != -1) {
4089 cfg.cn[0].cls += ' nav-' + this.arrangement;
4093 if (this.align === 'right') {
4094 cfg.cn[0].cls += ' navbar-right';
4119 * navbar-expand-md fixed-top
4123 * @class Roo.bootstrap.NavHeaderbar
4124 * @extends Roo.bootstrap.NavSimplebar
4125 * Bootstrap Sidebar class
4127 * @cfg {String} brand what is brand
4128 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
4129 * @cfg {String} brand_href href of the brand
4130 * @cfg {Boolean} srButton generate the (screen reader / mobile) sr-only button default true
4131 * @cfg {Boolean} autohide a top nav bar header that hides on scroll.
4132 * @cfg {Boolean} desktopCenter should the header be centered on desktop using a container class
4133 * @cfg {Roo.bootstrap.Row} mobilerow - a row to display on mobile only..
4136 * Create a new Sidebar
4137 * @param {Object} config The config object
4141 Roo.bootstrap.NavHeaderbar = function(config){
4142 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
4146 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
4153 desktopCenter : false,
4156 getAutoCreate : function(){
4159 tag: this.nav || 'nav',
4160 cls: 'navbar navbar-expand-md',
4166 if (this.desktopCenter) {
4167 cn.push({cls : 'container', cn : []});
4175 cls: 'navbar-toggle navbar-toggler',
4176 'data-toggle': 'collapse',
4181 html: 'Toggle navigation'
4185 cls: 'icon-bar navbar-toggler-icon'
4198 cn.push( Roo.bootstrap.version == 4 ? btn : {
4200 cls: 'navbar-header',
4209 cls: 'collapse navbar-collapse',
4213 cfg.cls += this.inverse ? ' navbar-inverse navbar-dark bg-dark' : ' navbar-default';
4215 if (['light','white'].indexOf(this.weight) > -1) {
4216 cfg.cls += ['light','white'].indexOf(this.weight) > -1 ? ' navbar-light' : ' navbar-dark';
4218 cfg.cls += ' bg-' + this.weight;
4221 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
4222 cfg.cls += ' navbar-' + this.position + ' ' + this.position ;
4224 // tag can override this..
4226 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
4229 if (this.brand !== '') {
4230 var cp = Roo.bootstrap.version == 4 ? cn : cn[0].cn;
4231 cp.unshift({ // changed from push ?? BS4 needs it at the start? - does this break or exsiting?
4233 href: this.brand_href ? this.brand_href : '#',
4234 cls: 'navbar-brand',
4242 cfg.cls += ' main-nav';
4250 getHeaderChildContainer : function()
4252 if (this.srButton && this.el.select('.navbar-header').getCount()) {
4253 return this.el.select('.navbar-header',true).first();
4256 return this.getChildContainer();
4260 initEvents : function()
4262 Roo.bootstrap.NavHeaderbar.superclass.initEvents.call(this);
4264 if (this.autohide) {
4269 Roo.get(document).on('scroll',function(e) {
4270 var ns = Roo.get(document).getScroll().top;
4271 var os = prevScroll;
4275 ft.removeClass('slideDown');
4276 ft.addClass('slideUp');
4279 ft.removeClass('slideUp');
4280 ft.addClass('slideDown');
4301 * @class Roo.bootstrap.NavSidebar
4302 * @extends Roo.bootstrap.Navbar
4303 * Bootstrap Sidebar class
4306 * Create a new Sidebar
4307 * @param {Object} config The config object
4311 Roo.bootstrap.NavSidebar = function(config){
4312 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
4315 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
4317 sidebar : true, // used by Navbar Item and NavbarGroup at present...
4319 getAutoCreate : function(){
4324 cls: 'sidebar sidebar-nav'
4346 * @class Roo.bootstrap.NavGroup
4347 * @extends Roo.bootstrap.Component
4348 * Bootstrap NavGroup class
4349 * @cfg {String} align (left|right)
4350 * @cfg {Boolean} inverse
4351 * @cfg {String} type (nav|pills|tab) default nav
4352 * @cfg {String} navId - reference Id for navbar.
4356 * Create a new nav group
4357 * @param {Object} config The config object
4360 Roo.bootstrap.NavGroup = function(config){
4361 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
4364 Roo.bootstrap.NavGroup.register(this);
4368 * Fires when the active item changes
4369 * @param {Roo.bootstrap.NavGroup} this
4370 * @param {Roo.bootstrap.Navbar.Item} selected The item selected
4371 * @param {Roo.bootstrap.Navbar.Item} prev The previously selected item
4378 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
4389 getAutoCreate : function()
4391 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
4397 if (Roo.bootstrap.version == 4) {
4398 if (['tabs','pills'].indexOf(this.type) != -1) {
4399 cfg.cls += ' nav-' + this.type;
4401 cfg.cls += ' navbar-nav';
4404 if (['tabs','pills'].indexOf(this.type) != -1) {
4405 cfg.cls += ' nav-' + this.type
4407 if (this.type !== 'nav') {
4408 Roo.log('nav type must be nav/tabs/pills')
4410 cfg.cls += ' navbar-nav'
4414 if (this.parent() && this.parent().sidebar) {
4417 cls: 'dashboard-menu sidebar-menu'
4423 if (this.form === true) {
4426 cls: 'navbar-form form-inline'
4429 if (this.align === 'right') {
4430 cfg.cls += ' navbar-right ml-md-auto';
4432 cfg.cls += ' navbar-left';
4436 if (this.align === 'right') {
4437 cfg.cls += ' navbar-right ml-md-auto';
4439 cfg.cls += ' mr-auto';
4443 cfg.cls += ' navbar-inverse';
4451 * sets the active Navigation item
4452 * @param {Roo.bootstrap.NavItem} the new current navitem
4454 setActiveItem : function(item)
4457 Roo.each(this.navItems, function(v){
4462 v.setActive(false, true);
4469 item.setActive(true, true);
4470 this.fireEvent('changed', this, item, prev);
4475 * gets the active Navigation item
4476 * @return {Roo.bootstrap.NavItem} the current navitem
4478 getActive : function()
4482 Roo.each(this.navItems, function(v){
4493 indexOfNav : function()
4497 Roo.each(this.navItems, function(v,i){
4508 * adds a Navigation item
4509 * @param {Roo.bootstrap.NavItem} the navitem to add
4511 addItem : function(cfg)
4513 if (this.form && Roo.bootstrap.version == 4) {
4516 var cn = new Roo.bootstrap.NavItem(cfg);
4518 cn.parentId = this.id;
4519 cn.onRender(this.el, null);
4523 * register a Navigation item
4524 * @param {Roo.bootstrap.NavItem} the navitem to add
4526 register : function(item)
4528 this.navItems.push( item);
4529 item.navId = this.navId;
4534 * clear all the Navigation item
4537 clearAll : function()
4540 this.el.dom.innerHTML = '';
4543 getNavItem: function(tabId)
4546 Roo.each(this.navItems, function(e) {
4547 if (e.tabId == tabId) {
4557 setActiveNext : function()
4559 var i = this.indexOfNav(this.getActive());
4560 if (i > this.navItems.length) {
4563 this.setActiveItem(this.navItems[i+1]);
4565 setActivePrev : function()
4567 var i = this.indexOfNav(this.getActive());
4571 this.setActiveItem(this.navItems[i-1]);
4573 clearWasActive : function(except) {
4574 Roo.each(this.navItems, function(e) {
4575 if (e.tabId != except.tabId && e.was_active) {
4576 e.was_active = false;
4583 getWasActive : function ()
4586 Roo.each(this.navItems, function(e) {
4601 Roo.apply(Roo.bootstrap.NavGroup, {
4605 * register a Navigation Group
4606 * @param {Roo.bootstrap.NavGroup} the navgroup to add
4608 register : function(navgrp)
4610 this.groups[navgrp.navId] = navgrp;
4614 * fetch a Navigation Group based on the navigation ID
4615 * @param {string} the navgroup to add
4616 * @returns {Roo.bootstrap.NavGroup} the navgroup
4618 get: function(navId) {
4619 if (typeof(this.groups[navId]) == 'undefined') {
4621 //this.register(new Roo.bootstrap.NavGroup({ navId : navId }));
4623 return this.groups[navId] ;
4638 * @class Roo.bootstrap.NavItem
4639 * @extends Roo.bootstrap.Component
4640 * Bootstrap Navbar.NavItem class
4641 * @cfg {String} href link to
4642 * @cfg {String} button_weight (default | primary | secondary | success | info | warning | danger | link ) default none
4644 * @cfg {String} html content of button
4645 * @cfg {String} badge text inside badge
4646 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
4647 * @cfg {String} glyphicon DEPRICATED - use fa
4648 * @cfg {String} icon DEPRICATED - use fa
4649 * @cfg {String} fa - Fontawsome icon name (can add stuff to it like fa-2x)
4650 * @cfg {Boolean} active Is item active
4651 * @cfg {Boolean} disabled Is item disabled
4653 * @cfg {Boolean} preventDefault (true | false) default false
4654 * @cfg {String} tabId the tab that this item activates.
4655 * @cfg {String} tagtype (a|span) render as a href or span?
4656 * @cfg {Boolean} animateRef (true|false) link to element default false
4659 * Create a new Navbar Item
4660 * @param {Object} config The config object
4662 Roo.bootstrap.NavItem = function(config){
4663 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
4668 * The raw click event for the entire grid.
4669 * @param {Roo.EventObject} e
4674 * Fires when the active item active state changes
4675 * @param {Roo.bootstrap.NavItem} this
4676 * @param {boolean} state the new state
4682 * Fires when scroll to element
4683 * @param {Roo.bootstrap.NavItem} this
4684 * @param {Object} options
4685 * @param {Roo.EventObject} e
4693 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
4702 preventDefault : false,
4710 button_outline : false,
4714 getAutoCreate : function(){
4722 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
4724 if (this.disabled) {
4725 cfg.cls += ' disabled';
4729 if (this.button_weight.length) {
4730 cfg.tag = this.href ? 'a' : 'button';
4731 cfg.html = this.html || '';
4732 cfg.cls += ' btn btn' + (this.button_outline ? '-outline' : '') + '-' + this.button_weight;
4734 cfg.href = this.href;
4737 cfg.html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + this.html + '</span>';
4740 // menu .. should add dropdown-menu class - so no need for carat..
4742 if (this.badge !== '') {
4744 cfg.html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4749 if (this.href || this.html || this.glyphicon || this.icon || this.fa) {
4753 href : this.href || "#",
4754 html: this.html || ''
4757 if (this.tagtype == 'a') {
4758 cfg.cn[0].cls = 'nav-link';
4761 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>';
4764 cfg.cn[0].html = '<i class="fa fas fa-'+this.fa+'"></i> <span>' + cfg.cn[0].html + '</span>';
4766 if(this.glyphicon) {
4767 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
4772 cfg.cn[0].html += " <span class='caret'></span>";
4776 if (this.badge !== '') {
4778 cfg.cn[0].html += ' <span class="badge badge-secondary">' + this.badge + '</span>';
4786 onRender : function(ct, position)
4788 // Roo.log("Call onRender: " + this.xtype);
4789 if (Roo.bootstrap.version == 4 && ct.dom.type != 'ul') {
4793 var ret = Roo.bootstrap.NavItem.superclass.onRender.call(this, ct, position);
4794 this.navLink = this.el.select('.nav-link',true).first();
4799 initEvents: function()
4801 if (typeof (this.menu) != 'undefined') {
4802 this.menu.parentType = this.xtype;
4803 this.menu.triggerEl = this.el;
4804 this.menu = this.addxtype(Roo.apply({}, this.menu));
4807 this.el.select('a',true).on('click', this.onClick, this);
4809 if(this.tagtype == 'span'){
4810 this.el.select('span',true).on('click', this.onClick, this);
4813 // at this point parent should be available..
4814 this.parent().register(this);
4817 onClick : function(e)
4819 if (e.getTarget('.dropdown-menu-item')) {
4820 // did you click on a menu itemm.... - then don't trigger onclick..
4825 this.preventDefault ||
4828 Roo.log("NavItem - prevent Default?");
4832 if (this.disabled) {
4836 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4837 if (tg && tg.transition) {
4838 Roo.log("waiting for the transitionend");
4844 //Roo.log("fire event clicked");
4845 if(this.fireEvent('click', this, e) === false){
4849 if(this.tagtype == 'span'){
4853 //Roo.log(this.href);
4854 var ael = this.el.select('a',true).first();
4857 if(ael && this.animateRef && this.href.indexOf('#') > -1){
4858 //Roo.log(["test:",ael.dom.href.split("#")[0], document.location.toString().split("#")[0]]);
4859 if (ael.dom.href.split("#")[0] != document.location.toString().split("#")[0]) {
4860 return; // ignore... - it's a 'hash' to another page.
4862 Roo.log("NavItem - prevent Default?");
4864 this.scrollToElement(e);
4868 var p = this.parent();
4870 if (['tabs','pills'].indexOf(p.type)!==-1) {
4871 if (typeof(p.setActiveItem) !== 'undefined') {
4872 p.setActiveItem(this);
4876 // if parent is a navbarheader....- and link is probably a '#' page ref.. then remove the expanded menu.
4877 if (p.parentType == 'NavHeaderbar' && !this.menu) {
4878 // remove the collapsed menu expand...
4879 p.parent().el.select('.navbar-collapse',true).removeClass('in');
4883 isActive: function () {
4886 setActive : function(state, fire, is_was_active)
4888 if (this.active && !state && this.navId) {
4889 this.was_active = true;
4890 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4892 nv.clearWasActive(this);
4896 this.active = state;
4899 this.el.removeClass('active');
4900 this.navLink ? this.navLink.removeClass('active') : false;
4901 } else if (!this.el.hasClass('active')) {
4903 this.el.addClass('active');
4904 if (Roo.bootstrap.version == 4 && this.navLink ) {
4905 this.navLink.addClass('active');
4910 this.fireEvent('changed', this, state);
4913 // show a panel if it's registered and related..
4915 if (!this.navId || !this.tabId || !state || is_was_active) {
4919 var tg = Roo.bootstrap.TabGroup.get(this.navId);
4923 var pan = tg.getPanelByName(this.tabId);
4927 // if we can not flip to new panel - go back to old nav highlight..
4928 if (false == tg.showPanel(pan)) {
4929 var nv = Roo.bootstrap.NavGroup.get(this.navId);
4931 var onav = nv.getWasActive();
4933 onav.setActive(true, false, true);
4942 // this should not be here...
4943 setDisabled : function(state)
4945 this.disabled = state;
4947 this.el.removeClass('disabled');
4948 } else if (!this.el.hasClass('disabled')) {
4949 this.el.addClass('disabled');
4955 * Fetch the element to display the tooltip on.
4956 * @return {Roo.Element} defaults to this.el
4958 tooltipEl : function()
4960 return this.el.select('' + this.tagtype + '', true).first();
4963 scrollToElement : function(e)
4965 var c = document.body;
4968 * Firefox / IE places the overflow at the html level, unless specifically styled to behave differently.
4970 if(Roo.isFirefox || Roo.isIE || Roo.isIE11){
4971 c = document.documentElement;
4974 var target = Roo.get(c).select('a[name=' + this.href.split('#')[1] +']', true).first();
4980 var o = target.calcOffsetsTo(c);
4987 this.fireEvent('scrollto', this, options, e);
4989 Roo.get(c).scrollTo('top', options.value, true);
5002 * <span> icon </span>
5003 * <span> text </span>
5004 * <span>badge </span>
5008 * @class Roo.bootstrap.NavSidebarItem
5009 * @extends Roo.bootstrap.NavItem
5010 * Bootstrap Navbar.NavSidebarItem class
5011 * {String} badgeWeight (default|primary|success|info|warning|danger)the extra classes for the badge
5012 * {Boolean} open is the menu open
5013 * {Boolean} buttonView use button as the tigger el rather that a (default false)
5014 * {String} buttonWeight (default|primary|success|info|warning|danger)the extra classes for the button
5015 * {String} buttonSize (sm|md|lg)the extra classes for the button
5016 * {Boolean} showArrow show arrow next to the text (default true)
5018 * Create a new Navbar Button
5019 * @param {Object} config The config object
5021 Roo.bootstrap.NavSidebarItem = function(config){
5022 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
5027 * The raw click event for the entire grid.
5028 * @param {Roo.EventObject} e
5033 * Fires when the active item active state changes
5034 * @param {Roo.bootstrap.NavSidebarItem} this
5035 * @param {boolean} state the new state
5043 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
5045 badgeWeight : 'default',
5051 buttonWeight : 'default',
5057 getAutoCreate : function(){
5062 href : this.href || '#',
5068 if(this.buttonView){
5071 href : this.href || '#',
5072 cls: 'btn btn-' + this.buttonWeight + ' btn-' + this.buttonSize + 'roo-button-dropdown-toggle',
5085 cfg.cls += ' active';
5088 if (this.disabled) {
5089 cfg.cls += ' disabled';
5092 cfg.cls += ' open x-open';
5095 if (this.glyphicon || this.icon) {
5096 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
5097 a.cn.push({ tag : 'i', cls : c }) ;
5100 if(!this.buttonView){
5103 html : this.html || ''
5110 if (this.badge !== '') {
5111 a.cn.push({ tag: 'span', cls : 'badge pull-right badge-' + this.badgeWeight, html: this.badge });
5117 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
5120 a.cls += ' dropdown-toggle treeview' ;
5126 initEvents : function()
5128 if (typeof (this.menu) != 'undefined') {
5129 this.menu.parentType = this.xtype;
5130 this.menu.triggerEl = this.el;
5131 this.menu = this.addxtype(Roo.apply({}, this.menu));
5134 this.el.on('click', this.onClick, this);
5136 if(this.badge !== ''){
5137 this.badgeEl = this.el.select('.badge', true).first().setVisibilityMode(Roo.Element.DISPLAY);
5142 onClick : function(e)
5149 if(this.preventDefault){
5153 this.fireEvent('click', this, e);
5156 disable : function()
5158 this.setDisabled(true);
5163 this.setDisabled(false);
5166 setDisabled : function(state)
5168 if(this.disabled == state){
5172 this.disabled = state;
5175 this.el.addClass('disabled');
5179 this.el.removeClass('disabled');
5184 setActive : function(state)
5186 if(this.active == state){
5190 this.active = state;
5193 this.el.addClass('active');
5197 this.el.removeClass('active');
5202 isActive: function ()
5207 setBadge : function(str)
5213 this.badgeEl.dom.innerHTML = str;
5230 * @class Roo.bootstrap.Row
5231 * @extends Roo.bootstrap.Component
5232 * Bootstrap Row class (contains columns...)
5236 * @param {Object} config The config object
5239 Roo.bootstrap.Row = function(config){
5240 Roo.bootstrap.Row.superclass.constructor.call(this, config);
5243 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
5245 getAutoCreate : function(){
5264 * @class Roo.bootstrap.Element
5265 * @extends Roo.bootstrap.Component
5266 * Bootstrap Element class
5267 * @cfg {String} html contents of the element
5268 * @cfg {String} tag tag of the element
5269 * @cfg {String} cls class of the element
5270 * @cfg {Boolean} preventDefault (true|false) default false
5271 * @cfg {Boolean} clickable (true|false) default false
5274 * Create a new Element
5275 * @param {Object} config The config object
5278 Roo.bootstrap.Element = function(config){
5279 Roo.bootstrap.Element.superclass.constructor.call(this, config);
5285 * When a element is chick
5286 * @param {Roo.bootstrap.Element} this
5287 * @param {Roo.EventObject} e
5293 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
5298 preventDefault: false,
5301 getAutoCreate : function(){
5305 // cls: this.cls, double assign in parent class Component.js :: onRender
5312 initEvents: function()
5314 Roo.bootstrap.Element.superclass.initEvents.call(this);
5317 this.el.on('click', this.onClick, this);
5322 onClick : function(e)
5324 if(this.preventDefault){
5328 this.fireEvent('click', this, e);
5331 getValue : function()
5333 return this.el.dom.innerHTML;
5336 setValue : function(value)
5338 this.el.dom.innerHTML = value;
5353 * @class Roo.bootstrap.Pagination
5354 * @extends Roo.bootstrap.Component
5355 * Bootstrap Pagination class
5356 * @cfg {String} size xs | sm | md | lg
5357 * @cfg {Boolean} inverse false | true
5360 * Create a new Pagination
5361 * @param {Object} config The config object
5364 Roo.bootstrap.Pagination = function(config){
5365 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
5368 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
5374 getAutoCreate : function(){
5380 cfg.cls += ' inverse';
5386 cfg.cls += " " + this.cls;
5404 * @class Roo.bootstrap.PaginationItem
5405 * @extends Roo.bootstrap.Component
5406 * Bootstrap PaginationItem class
5407 * @cfg {String} html text
5408 * @cfg {String} href the link
5409 * @cfg {Boolean} preventDefault (true | false) default true
5410 * @cfg {Boolean} active (true | false) default false
5411 * @cfg {Boolean} disabled default false
5415 * Create a new PaginationItem
5416 * @param {Object} config The config object
5420 Roo.bootstrap.PaginationItem = function(config){
5421 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
5426 * The raw click event for the entire grid.
5427 * @param {Roo.EventObject} e
5433 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
5437 preventDefault: true,
5442 getAutoCreate : function(){
5448 href : this.href ? this.href : '#',
5449 html : this.html ? this.html : ''
5459 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' disabled' : 'disabled';
5463 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
5469 initEvents: function() {
5471 this.el.on('click', this.onClick, this);
5474 onClick : function(e)
5476 Roo.log('PaginationItem on click ');
5477 if(this.preventDefault){
5485 this.fireEvent('click', this, e);
5501 * @class Roo.bootstrap.Slider
5502 * @extends Roo.bootstrap.Component
5503 * Bootstrap Slider class
5506 * Create a new Slider
5507 * @param {Object} config The config object
5510 Roo.bootstrap.Slider = function(config){
5511 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
5514 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
5516 getAutoCreate : function(){
5520 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
5524 cls: 'ui-slider-handle ui-state-default ui-corner-all'
5536 * Ext JS Library 1.1.1
5537 * Copyright(c) 2006-2007, Ext JS, LLC.
5539 * Originally Released Under LGPL - original licence link has changed is not relivant.
5542 * <script type="text/javascript">
5547 * @class Roo.grid.ColumnModel
5548 * @extends Roo.util.Observable
5549 * This is the default implementation of a ColumnModel used by the Grid. It defines
5550 * the columns in the grid.
5553 var colModel = new Roo.grid.ColumnModel([
5554 {header: "Ticker", width: 60, sortable: true, locked: true},
5555 {header: "Company Name", width: 150, sortable: true},
5556 {header: "Market Cap.", width: 100, sortable: true},
5557 {header: "$ Sales", width: 100, sortable: true, renderer: money},
5558 {header: "Employees", width: 100, sortable: true, resizable: false}
5563 * The config options listed for this class are options which may appear in each
5564 * individual column definition.
5565 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
5567 * @param {Object} config An Array of column config objects. See this class's
5568 * config objects for details.
5570 Roo.grid.ColumnModel = function(config){
5572 * The config passed into the constructor
5574 this.config = config;
5577 // if no id, create one
5578 // if the column does not have a dataIndex mapping,
5579 // map it to the order it is in the config
5580 for(var i = 0, len = config.length; i < len; i++){
5582 if(typeof c.dataIndex == "undefined"){
5585 if(typeof c.renderer == "string"){
5586 c.renderer = Roo.util.Format[c.renderer];
5588 if(typeof c.id == "undefined"){
5591 if(c.editor && c.editor.xtype){
5592 c.editor = Roo.factory(c.editor, Roo.grid);
5594 if(c.editor && c.editor.isFormField){
5595 c.editor = new Roo.grid.GridEditor(c.editor);
5597 this.lookup[c.id] = c;
5601 * The width of columns which have no width specified (defaults to 100)
5604 this.defaultWidth = 100;
5607 * Default sortable of columns which have no sortable specified (defaults to false)
5610 this.defaultSortable = false;
5614 * @event widthchange
5615 * Fires when the width of a column changes.
5616 * @param {ColumnModel} this
5617 * @param {Number} columnIndex The column index
5618 * @param {Number} newWidth The new width
5620 "widthchange": true,
5622 * @event headerchange
5623 * Fires when the text of a header changes.
5624 * @param {ColumnModel} this
5625 * @param {Number} columnIndex The column index
5626 * @param {Number} newText The new header text
5628 "headerchange": true,
5630 * @event hiddenchange
5631 * Fires when a column is hidden or "unhidden".
5632 * @param {ColumnModel} this
5633 * @param {Number} columnIndex The column index
5634 * @param {Boolean} hidden true if hidden, false otherwise
5636 "hiddenchange": true,
5638 * @event columnmoved
5639 * Fires when a column is moved.
5640 * @param {ColumnModel} this
5641 * @param {Number} oldIndex
5642 * @param {Number} newIndex
5644 "columnmoved" : true,
5646 * @event columlockchange
5647 * Fires when a column's locked state is changed
5648 * @param {ColumnModel} this
5649 * @param {Number} colIndex
5650 * @param {Boolean} locked true if locked
5652 "columnlockchange" : true
5654 Roo.grid.ColumnModel.superclass.constructor.call(this);
5656 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
5658 * @cfg {String} header The header text to display in the Grid view.
5661 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
5662 * {@link Roo.data.Record} definition from which to draw the column's value. If not
5663 * specified, the column's index is used as an index into the Record's data Array.
5666 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
5667 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
5670 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
5671 * Defaults to the value of the {@link #defaultSortable} property.
5672 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
5675 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
5678 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
5681 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
5684 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
5687 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
5688 * given the cell's data value. See {@link #setRenderer}. If not specified, the
5689 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
5690 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
5693 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
5696 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
5699 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
5702 * @cfg {String} cursor (Optional)
5705 * @cfg {String} tooltip (Optional)
5708 * @cfg {Number} xs (Optional)
5711 * @cfg {Number} sm (Optional)
5714 * @cfg {Number} md (Optional)
5717 * @cfg {Number} lg (Optional)
5720 * Returns the id of the column at the specified index.
5721 * @param {Number} index The column index
5722 * @return {String} the id
5724 getColumnId : function(index){
5725 return this.config[index].id;
5729 * Returns the column for a specified id.
5730 * @param {String} id The column id
5731 * @return {Object} the column
5733 getColumnById : function(id){
5734 return this.lookup[id];
5739 * Returns the column for a specified dataIndex.
5740 * @param {String} dataIndex The column dataIndex
5741 * @return {Object|Boolean} the column or false if not found
5743 getColumnByDataIndex: function(dataIndex){
5744 var index = this.findColumnIndex(dataIndex);
5745 return index > -1 ? this.config[index] : false;
5749 * Returns the index for a specified column id.
5750 * @param {String} id The column id
5751 * @return {Number} the index, or -1 if not found
5753 getIndexById : function(id){
5754 for(var i = 0, len = this.config.length; i < len; i++){
5755 if(this.config[i].id == id){
5763 * Returns the index for a specified column dataIndex.
5764 * @param {String} dataIndex The column dataIndex
5765 * @return {Number} the index, or -1 if not found
5768 findColumnIndex : function(dataIndex){
5769 for(var i = 0, len = this.config.length; i < len; i++){
5770 if(this.config[i].dataIndex == dataIndex){
5778 moveColumn : function(oldIndex, newIndex){
5779 var c = this.config[oldIndex];
5780 this.config.splice(oldIndex, 1);
5781 this.config.splice(newIndex, 0, c);
5782 this.dataMap = null;
5783 this.fireEvent("columnmoved", this, oldIndex, newIndex);
5786 isLocked : function(colIndex){
5787 return this.config[colIndex].locked === true;
5790 setLocked : function(colIndex, value, suppressEvent){
5791 if(this.isLocked(colIndex) == value){
5794 this.config[colIndex].locked = value;
5796 this.fireEvent("columnlockchange", this, colIndex, value);
5800 getTotalLockedWidth : function(){
5802 for(var i = 0; i < this.config.length; i++){
5803 if(this.isLocked(i) && !this.isHidden(i)){
5804 this.totalWidth += this.getColumnWidth(i);
5810 getLockedCount : function(){
5811 for(var i = 0, len = this.config.length; i < len; i++){
5812 if(!this.isLocked(i)){
5817 return this.config.length;
5821 * Returns the number of columns.
5824 getColumnCount : function(visibleOnly){
5825 if(visibleOnly === true){
5827 for(var i = 0, len = this.config.length; i < len; i++){
5828 if(!this.isHidden(i)){
5834 return this.config.length;
5838 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
5839 * @param {Function} fn
5840 * @param {Object} scope (optional)
5841 * @return {Array} result
5843 getColumnsBy : function(fn, scope){
5845 for(var i = 0, len = this.config.length; i < len; i++){
5846 var c = this.config[i];
5847 if(fn.call(scope||this, c, i) === true){
5855 * Returns true if the specified column is sortable.
5856 * @param {Number} col The column index
5859 isSortable : function(col){
5860 if(typeof this.config[col].sortable == "undefined"){
5861 return this.defaultSortable;
5863 return this.config[col].sortable;
5867 * Returns the rendering (formatting) function defined for the column.
5868 * @param {Number} col The column index.
5869 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
5871 getRenderer : function(col){
5872 if(!this.config[col].renderer){
5873 return Roo.grid.ColumnModel.defaultRenderer;
5875 return this.config[col].renderer;
5879 * Sets the rendering (formatting) function for a column.
5880 * @param {Number} col The column index
5881 * @param {Function} fn The function to use to process the cell's raw data
5882 * to return HTML markup for the grid view. The render function is called with
5883 * the following parameters:<ul>
5884 * <li>Data value.</li>
5885 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
5886 * <li>css A CSS style string to apply to the table cell.</li>
5887 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
5888 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
5889 * <li>Row index</li>
5890 * <li>Column index</li>
5891 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
5893 setRenderer : function(col, fn){
5894 this.config[col].renderer = fn;
5898 * Returns the width for the specified column.
5899 * @param {Number} col The column index
5902 getColumnWidth : function(col){
5903 return this.config[col].width * 1 || this.defaultWidth;
5907 * Sets the width for a column.
5908 * @param {Number} col The column index
5909 * @param {Number} width The new width
5911 setColumnWidth : function(col, width, suppressEvent){
5912 this.config[col].width = width;
5913 this.totalWidth = null;
5915 this.fireEvent("widthchange", this, col, width);
5920 * Returns the total width of all columns.
5921 * @param {Boolean} includeHidden True to include hidden column widths
5924 getTotalWidth : function(includeHidden){
5925 if(!this.totalWidth){
5926 this.totalWidth = 0;
5927 for(var i = 0, len = this.config.length; i < len; i++){
5928 if(includeHidden || !this.isHidden(i)){
5929 this.totalWidth += this.getColumnWidth(i);
5933 return this.totalWidth;
5937 * Returns the header for the specified column.
5938 * @param {Number} col The column index
5941 getColumnHeader : function(col){
5942 return this.config[col].header;
5946 * Sets the header for a column.
5947 * @param {Number} col The column index
5948 * @param {String} header The new header
5950 setColumnHeader : function(col, header){
5951 this.config[col].header = header;
5952 this.fireEvent("headerchange", this, col, header);
5956 * Returns the tooltip for the specified column.
5957 * @param {Number} col The column index
5960 getColumnTooltip : function(col){
5961 return this.config[col].tooltip;
5964 * Sets the tooltip for a column.
5965 * @param {Number} col The column index
5966 * @param {String} tooltip The new tooltip
5968 setColumnTooltip : function(col, tooltip){
5969 this.config[col].tooltip = tooltip;
5973 * Returns the dataIndex for the specified column.
5974 * @param {Number} col The column index
5977 getDataIndex : function(col){
5978 return this.config[col].dataIndex;
5982 * Sets the dataIndex for a column.
5983 * @param {Number} col The column index
5984 * @param {Number} dataIndex The new dataIndex
5986 setDataIndex : function(col, dataIndex){
5987 this.config[col].dataIndex = dataIndex;
5993 * Returns true if the cell is editable.
5994 * @param {Number} colIndex The column index
5995 * @param {Number} rowIndex The row index - this is nto actually used..?
5998 isCellEditable : function(colIndex, rowIndex){
5999 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
6003 * Returns the editor defined for the cell/column.
6004 * return false or null to disable editing.
6005 * @param {Number} colIndex The column index
6006 * @param {Number} rowIndex The row index
6009 getCellEditor : function(colIndex, rowIndex){
6010 return this.config[colIndex].editor;
6014 * Sets if a column is editable.
6015 * @param {Number} col The column index
6016 * @param {Boolean} editable True if the column is editable
6018 setEditable : function(col, editable){
6019 this.config[col].editable = editable;
6024 * Returns true if the column is hidden.
6025 * @param {Number} colIndex The column index
6028 isHidden : function(colIndex){
6029 return this.config[colIndex].hidden;
6034 * Returns true if the column width cannot be changed
6036 isFixed : function(colIndex){
6037 return this.config[colIndex].fixed;
6041 * Returns true if the column can be resized
6044 isResizable : function(colIndex){
6045 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
6048 * Sets if a column is hidden.
6049 * @param {Number} colIndex The column index
6050 * @param {Boolean} hidden True if the column is hidden
6052 setHidden : function(colIndex, hidden){
6053 this.config[colIndex].hidden = hidden;
6054 this.totalWidth = null;
6055 this.fireEvent("hiddenchange", this, colIndex, hidden);
6059 * Sets the editor for a column.
6060 * @param {Number} col The column index
6061 * @param {Object} editor The editor object
6063 setEditor : function(col, editor){
6064 this.config[col].editor = editor;
6068 Roo.grid.ColumnModel.defaultRenderer = function(value)
6070 if(typeof value == "object") {
6073 if(typeof value == "string" && value.length < 1){
6077 return String.format("{0}", value);
6080 // Alias for backwards compatibility
6081 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
6084 * Ext JS Library 1.1.1
6085 * Copyright(c) 2006-2007, Ext JS, LLC.
6087 * Originally Released Under LGPL - original licence link has changed is not relivant.
6090 * <script type="text/javascript">
6094 * @class Roo.LoadMask
6095 * A simple utility class for generically masking elements while loading data. If the element being masked has
6096 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
6097 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
6098 * element's UpdateManager load indicator and will be destroyed after the initial load.
6100 * Create a new LoadMask
6101 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
6102 * @param {Object} config The config object
6104 Roo.LoadMask = function(el, config){
6105 this.el = Roo.get(el);
6106 Roo.apply(this, config);
6108 this.store.on('beforeload', this.onBeforeLoad, this);
6109 this.store.on('load', this.onLoad, this);
6110 this.store.on('loadexception', this.onLoadException, this);
6111 this.removeMask = false;
6113 var um = this.el.getUpdateManager();
6114 um.showLoadIndicator = false; // disable the default indicator
6115 um.on('beforeupdate', this.onBeforeLoad, this);
6116 um.on('update', this.onLoad, this);
6117 um.on('failure', this.onLoad, this);
6118 this.removeMask = true;
6122 Roo.LoadMask.prototype = {
6124 * @cfg {Boolean} removeMask
6125 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
6126 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
6130 * The text to display in a centered loading message box (defaults to 'Loading...')
6134 * @cfg {String} msgCls
6135 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
6137 msgCls : 'x-mask-loading',
6140 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
6146 * Disables the mask to prevent it from being displayed
6148 disable : function(){
6149 this.disabled = true;
6153 * Enables the mask so that it can be displayed
6155 enable : function(){
6156 this.disabled = false;
6159 onLoadException : function()
6163 if (typeof(arguments[3]) != 'undefined') {
6164 Roo.MessageBox.alert("Error loading",arguments[3]);
6168 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
6169 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
6176 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6181 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
6185 onBeforeLoad : function(){
6187 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
6192 destroy : function(){
6194 this.store.un('beforeload', this.onBeforeLoad, this);
6195 this.store.un('load', this.onLoad, this);
6196 this.store.un('loadexception', this.onLoadException, this);
6198 var um = this.el.getUpdateManager();
6199 um.un('beforeupdate', this.onBeforeLoad, this);
6200 um.un('update', this.onLoad, this);
6201 um.un('failure', this.onLoad, this);
6212 * @class Roo.bootstrap.Table
6213 * @extends Roo.bootstrap.Component
6214 * Bootstrap Table class
6215 * @cfg {String} cls table class
6216 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
6217 * @cfg {String} bgcolor Specifies the background color for a table
6218 * @cfg {Number} border Specifies whether the table cells should have borders or not
6219 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
6220 * @cfg {Number} cellspacing Specifies the space between cells
6221 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
6222 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
6223 * @cfg {String} sortable Specifies that the table should be sortable
6224 * @cfg {String} summary Specifies a summary of the content of a table
6225 * @cfg {Number} width Specifies the width of a table
6226 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
6228 * @cfg {boolean} striped Should the rows be alternative striped
6229 * @cfg {boolean} bordered Add borders to the table
6230 * @cfg {boolean} hover Add hover highlighting
6231 * @cfg {boolean} condensed Format condensed
6232 * @cfg {boolean} responsive Format condensed
6233 * @cfg {Boolean} loadMask (true|false) default false
6234 * @cfg {Boolean} footerShow (true|false) generate tfoot, default true
6235 * @cfg {Boolean} headerShow (true|false) generate thead, default true
6236 * @cfg {Boolean} rowSelection (true|false) default false
6237 * @cfg {Boolean} cellSelection (true|false) default false
6238 * @cfg {Boolean} scrollBody (true|false) default false - body scrolled / fixed header
6239 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
6240 * @cfg {Boolean} lazyLoad auto load data while scrolling to the end (default false)
6241 * @cfg {Boolean} auto_hide_footer auto hide footer if only one page (default false)
6245 * Create a new Table
6246 * @param {Object} config The config object
6249 Roo.bootstrap.Table = function(config){
6250 Roo.bootstrap.Table.superclass.constructor.call(this, config);
6255 this.rowSelection = (typeof(config.rowSelection) != 'undefined') ? config.rowSelection : this.rowSelection;
6256 this.cellSelection = (typeof(config.cellSelection) != 'undefined') ? config.cellSelection : this.cellSelection;
6257 this.headerShow = (typeof(config.thead) != 'undefined') ? config.thead : this.headerShow;
6258 this.footerShow = (typeof(config.tfoot) != 'undefined') ? config.tfoot : this.footerShow;
6260 this.sm = this.sm || {xtype: 'RowSelectionModel'};
6262 this.sm.grid = this;
6263 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
6264 this.sm = this.selModel;
6265 this.sm.xmodule = this.xmodule || false;
6268 if (this.cm && typeof(this.cm.config) == 'undefined') {
6269 this.colModel = new Roo.grid.ColumnModel(this.cm);
6270 this.cm = this.colModel;
6271 this.cm.xmodule = this.xmodule || false;
6274 this.store= Roo.factory(this.store, Roo.data);
6275 this.ds = this.store;
6276 this.ds.xmodule = this.xmodule || false;
6279 if (this.footer && this.store) {
6280 this.footer.dataSource = this.ds;
6281 this.footer = Roo.factory(this.footer);
6288 * Fires when a cell is clicked
6289 * @param {Roo.bootstrap.Table} this
6290 * @param {Roo.Element} el
6291 * @param {Number} rowIndex
6292 * @param {Number} columnIndex
6293 * @param {Roo.EventObject} e
6297 * @event celldblclick
6298 * Fires when a cell is double clicked
6299 * @param {Roo.bootstrap.Table} this
6300 * @param {Roo.Element} el
6301 * @param {Number} rowIndex
6302 * @param {Number} columnIndex
6303 * @param {Roo.EventObject} e
6305 "celldblclick" : true,
6308 * Fires when a row is clicked
6309 * @param {Roo.bootstrap.Table} this
6310 * @param {Roo.Element} el
6311 * @param {Number} rowIndex
6312 * @param {Roo.EventObject} e
6316 * @event rowdblclick
6317 * Fires when a row is double clicked
6318 * @param {Roo.bootstrap.Table} this
6319 * @param {Roo.Element} el
6320 * @param {Number} rowIndex
6321 * @param {Roo.EventObject} e
6323 "rowdblclick" : true,
6326 * Fires when a mouseover occur
6327 * @param {Roo.bootstrap.Table} this
6328 * @param {Roo.Element} el
6329 * @param {Number} rowIndex
6330 * @param {Number} columnIndex
6331 * @param {Roo.EventObject} e
6336 * Fires when a mouseout occur
6337 * @param {Roo.bootstrap.Table} this
6338 * @param {Roo.Element} el
6339 * @param {Number} rowIndex
6340 * @param {Number} columnIndex
6341 * @param {Roo.EventObject} e
6346 * Fires when a row is rendered, so you can change add a style to it.
6347 * @param {Roo.bootstrap.Table} this
6348 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
6352 * @event rowsrendered
6353 * Fires when all the rows have been rendered
6354 * @param {Roo.bootstrap.Table} this
6356 'rowsrendered' : true,
6358 * @event contextmenu
6359 * The raw contextmenu event for the entire grid.
6360 * @param {Roo.EventObject} e
6362 "contextmenu" : true,
6364 * @event rowcontextmenu
6365 * Fires when a row is right clicked
6366 * @param {Roo.bootstrap.Table} this
6367 * @param {Number} rowIndex
6368 * @param {Roo.EventObject} e
6370 "rowcontextmenu" : true,
6372 * @event cellcontextmenu
6373 * Fires when a cell is right clicked
6374 * @param {Roo.bootstrap.Table} this
6375 * @param {Number} rowIndex
6376 * @param {Number} cellIndex
6377 * @param {Roo.EventObject} e
6379 "cellcontextmenu" : true,
6381 * @event headercontextmenu
6382 * Fires when a header is right clicked
6383 * @param {Roo.bootstrap.Table} this
6384 * @param {Number} columnIndex
6385 * @param {Roo.EventObject} e
6387 "headercontextmenu" : true
6391 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
6417 rowSelection : false,
6418 cellSelection : false,
6421 // Roo.Element - the tbody
6423 // Roo.Element - thead element
6426 container: false, // used by gridpanel...
6432 auto_hide_footer : false,
6434 getAutoCreate : function()
6436 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
6443 if (this.scrollBody) {
6444 cfg.cls += ' table-body-fixed';
6447 cfg.cls += ' table-striped';
6451 cfg.cls += ' table-hover';
6453 if (this.bordered) {
6454 cfg.cls += ' table-bordered';
6456 if (this.condensed) {
6457 cfg.cls += ' table-condensed';
6459 if (this.responsive) {
6460 cfg.cls += ' table-responsive';
6464 cfg.cls+= ' ' +this.cls;
6467 // this lot should be simplifed...
6480 ].forEach(function(k) {
6488 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
6491 if(this.store || this.cm){
6492 if(this.headerShow){
6493 cfg.cn.push(this.renderHeader());
6496 cfg.cn.push(this.renderBody());
6498 if(this.footerShow){
6499 cfg.cn.push(this.renderFooter());
6501 // where does this come from?
6502 //cfg.cls+= ' TableGrid';
6505 return { cn : [ cfg ] };
6508 initEvents : function()
6510 if(!this.store || !this.cm){
6513 if (this.selModel) {
6514 this.selModel.initEvents();
6518 //Roo.log('initEvents with ds!!!!');
6520 this.mainBody = this.el.select('tbody', true).first();
6521 this.mainHead = this.el.select('thead', true).first();
6522 this.mainFoot = this.el.select('tfoot', true).first();
6528 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6529 e.on('click', _this.sort, _this);
6532 this.mainBody.on("click", this.onClick, this);
6533 this.mainBody.on("dblclick", this.onDblClick, this);
6535 // why is this done????? = it breaks dialogs??
6536 //this.parent().el.setStyle('position', 'relative');
6540 this.footer.parentId = this.id;
6541 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
6544 this.el.select('tfoot tr td').first().addClass('hide');
6549 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
6552 this.store.on('load', this.onLoad, this);
6553 this.store.on('beforeload', this.onBeforeLoad, this);
6554 this.store.on('update', this.onUpdate, this);
6555 this.store.on('add', this.onAdd, this);
6556 this.store.on("clear", this.clear, this);
6558 this.el.on("contextmenu", this.onContextMenu, this);
6560 this.mainBody.on('scroll', this.onBodyScroll, this);
6562 this.cm.on("headerchange", this.onHeaderChange, this);
6564 this.cm.on("hiddenchange", this.onHiddenChange, this, arguments);
6568 onContextMenu : function(e, t)
6570 this.processEvent("contextmenu", e);
6573 processEvent : function(name, e)
6575 if (name != 'touchstart' ) {
6576 this.fireEvent(name, e);
6579 var t = e.getTarget();
6581 var cell = Roo.get(t);
6587 if(cell.findParent('tfoot', false, true)){
6591 if(cell.findParent('thead', false, true)){
6593 if(e.getTarget().nodeName.toLowerCase() != 'th'){
6594 cell = Roo.get(t).findParent('th', false, true);
6596 Roo.log("failed to find th in thead?");
6597 Roo.log(e.getTarget());
6602 var cellIndex = cell.dom.cellIndex;
6604 var ename = name == 'touchstart' ? 'click' : name;
6605 this.fireEvent("header" + ename, this, cellIndex, e);
6610 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6611 cell = Roo.get(t).findParent('td', false, true);
6613 Roo.log("failed to find th in tbody?");
6614 Roo.log(e.getTarget());
6619 var row = cell.findParent('tr', false, true);
6620 var cellIndex = cell.dom.cellIndex;
6621 var rowIndex = row.dom.rowIndex - 1;
6625 this.fireEvent("row" + name, this, rowIndex, e);
6629 this.fireEvent("cell" + name, this, rowIndex, cellIndex, e);
6635 onMouseover : function(e, el)
6637 var cell = Roo.get(el);
6643 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6644 cell = cell.findParent('td', false, true);
6647 var row = cell.findParent('tr', false, true);
6648 var cellIndex = cell.dom.cellIndex;
6649 var rowIndex = row.dom.rowIndex - 1; // start from 0
6651 this.fireEvent('mouseover', this, cell, rowIndex, cellIndex, e);
6655 onMouseout : function(e, el)
6657 var cell = Roo.get(el);
6663 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6664 cell = cell.findParent('td', false, true);
6667 var row = cell.findParent('tr', false, true);
6668 var cellIndex = cell.dom.cellIndex;
6669 var rowIndex = row.dom.rowIndex - 1; // start from 0
6671 this.fireEvent('mouseout', this, cell, rowIndex, cellIndex, e);
6675 onClick : function(e, el)
6677 var cell = Roo.get(el);
6679 if(!cell || (!this.cellSelection && !this.rowSelection)){
6683 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6684 cell = cell.findParent('td', false, true);
6687 if(!cell || typeof(cell) == 'undefined'){
6691 var row = cell.findParent('tr', false, true);
6693 if(!row || typeof(row) == 'undefined'){
6697 var cellIndex = cell.dom.cellIndex;
6698 var rowIndex = this.getRowIndex(row);
6700 // why??? - should these not be based on SelectionModel?
6701 if(this.cellSelection){
6702 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
6705 if(this.rowSelection){
6706 this.fireEvent('rowclick', this, row, rowIndex, e);
6712 onDblClick : function(e,el)
6714 var cell = Roo.get(el);
6716 if(!cell || (!this.cellSelection && !this.rowSelection)){
6720 if(e.getTarget().nodeName.toLowerCase() != 'td'){
6721 cell = cell.findParent('td', false, true);
6724 if(!cell || typeof(cell) == 'undefined'){
6728 var row = cell.findParent('tr', false, true);
6730 if(!row || typeof(row) == 'undefined'){
6734 var cellIndex = cell.dom.cellIndex;
6735 var rowIndex = this.getRowIndex(row);
6737 if(this.cellSelection){
6738 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
6741 if(this.rowSelection){
6742 this.fireEvent('rowdblclick', this, row, rowIndex, e);
6746 sort : function(e,el)
6748 var col = Roo.get(el);
6750 if(!col.hasClass('sortable')){
6754 var sort = col.attr('sort');
6757 if(col.select('i', true).first().hasClass('glyphicon-arrow-up')){
6761 this.store.sortInfo = {field : sort, direction : dir};
6764 Roo.log("calling footer first");
6765 this.footer.onClick('first');
6768 this.store.load({ params : { start : 0 } });
6772 renderHeader : function()
6780 this.totalWidth = 0;
6782 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
6784 var config = cm.config[i];
6788 cls : 'x-hcol-' + i,
6790 html: cm.getColumnHeader(i)
6795 if(typeof(config.sortable) != 'undefined' && config.sortable){
6797 c.html = '<i class="glyphicon"></i>' + c.html;
6800 if(typeof(config.lgHeader) != 'undefined'){
6801 hh += '<span class="hidden-xs hidden-sm hidden-md">' + config.lgHeader + '</span>';
6804 if(typeof(config.mdHeader) != 'undefined'){
6805 hh += '<span class="hidden-xs hidden-sm hidden-lg">' + config.mdHeader + '</span>';
6808 if(typeof(config.smHeader) != 'undefined'){
6809 hh += '<span class="hidden-xs hidden-md hidden-lg">' + config.smHeader + '</span>';
6812 if(typeof(config.xsHeader) != 'undefined'){
6813 hh += '<span class="hidden-sm hidden-md hidden-lg">' + config.xsHeader + '</span>';
6820 if(typeof(config.tooltip) != 'undefined'){
6821 c.tooltip = config.tooltip;
6824 if(typeof(config.colspan) != 'undefined'){
6825 c.colspan = config.colspan;
6828 if(typeof(config.hidden) != 'undefined' && config.hidden){
6829 c.style += ' display:none;';
6832 if(typeof(config.dataIndex) != 'undefined'){
6833 c.sort = config.dataIndex;
6838 if(typeof(config.align) != 'undefined' && config.align.length){
6839 c.style += ' text-align:' + config.align + ';';
6842 if(typeof(config.width) != 'undefined'){
6843 c.style += ' width:' + config.width + 'px;';
6844 this.totalWidth += config.width;
6846 this.totalWidth += 100; // assume minimum of 100 per column?
6849 if(typeof(config.cls) != 'undefined'){
6850 c.cls = (typeof(c.cls) == 'undefined') ? config.cls : (c.cls + ' ' + config.cls);
6853 ['xs','sm','md','lg'].map(function(size){
6855 if(typeof(config[size]) == 'undefined'){
6859 if (!config[size]) { // 0 = hidden
6860 c.cls += ' hidden-' + size;
6864 c.cls += ' col-' + size + '-' + config[size];
6874 renderBody : function()
6884 colspan : this.cm.getColumnCount()
6894 renderFooter : function()
6904 colspan : this.cm.getColumnCount()
6918 // Roo.log('ds onload');
6923 var ds = this.store;
6925 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
6926 e.select('i', true).removeClass(['glyphicon-arrow-up', 'glyphicon-arrow-down']);
6927 if (_this.store.sortInfo) {
6929 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
6930 e.select('i', true).addClass(['glyphicon-arrow-up']);
6933 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
6934 e.select('i', true).addClass(['glyphicon-arrow-down']);
6939 var tbody = this.mainBody;
6941 if(ds.getCount() > 0){
6942 ds.data.each(function(d,rowIndex){
6943 var row = this.renderRow(cm, ds, rowIndex);
6945 tbody.createChild(row);
6949 if(row.cellObjects.length){
6950 Roo.each(row.cellObjects, function(r){
6951 _this.renderCellObject(r);
6958 var tfoot = this.el.select('tfoot', true).first();
6960 if(this.footerShow && this.auto_hide_footer && this.mainFoot){
6962 this.mainFoot.setVisibilityMode(Roo.Element.DISPLAY).hide();
6964 var total = this.ds.getTotalCount();
6966 if(this.footer.pageSize < total){
6967 this.mainFoot.show();
6971 Roo.each(this.el.select('tbody td', true).elements, function(e){
6972 e.on('mouseover', _this.onMouseover, _this);
6975 Roo.each(this.el.select('tbody td', true).elements, function(e){
6976 e.on('mouseout', _this.onMouseout, _this);
6978 this.fireEvent('rowsrendered', this);
6984 onUpdate : function(ds,record)
6986 this.refreshRow(record);
6990 onRemove : function(ds, record, index, isUpdate){
6991 if(isUpdate !== true){
6992 this.fireEvent("beforerowremoved", this, index, record);
6994 var bt = this.mainBody.dom;
6996 var rows = this.el.select('tbody > tr', true).elements;
6998 if(typeof(rows[index]) != 'undefined'){
6999 bt.removeChild(rows[index].dom);
7002 // if(bt.rows[index]){
7003 // bt.removeChild(bt.rows[index]);
7006 if(isUpdate !== true){
7007 //this.stripeRows(index);
7008 //this.syncRowHeights(index, index);
7010 this.fireEvent("rowremoved", this, index, record);
7014 onAdd : function(ds, records, rowIndex)
7016 //Roo.log('on Add called');
7017 // - note this does not handle multiple adding very well..
7018 var bt = this.mainBody.dom;
7019 for (var i =0 ; i < records.length;i++) {
7020 //Roo.log('call insert row Add called on ' + rowIndex + ':' + i);
7021 //Roo.log(records[i]);
7022 //Roo.log(this.store.getAt(rowIndex+i));
7023 this.insertRow(this.store, rowIndex + i, false);
7030 refreshRow : function(record){
7031 var ds = this.store, index;
7032 if(typeof record == 'number'){
7034 record = ds.getAt(index);
7036 index = ds.indexOf(record);
7038 this.insertRow(ds, index, true);
7040 this.onRemove(ds, record, index+1, true);
7042 //this.syncRowHeights(index, index);
7044 this.fireEvent("rowupdated", this, index, record);
7047 insertRow : function(dm, rowIndex, isUpdate){
7050 this.fireEvent("beforerowsinserted", this, rowIndex);
7052 //var s = this.getScrollState();
7053 var row = this.renderRow(this.cm, this.store, rowIndex);
7054 // insert before rowIndex..
7055 var e = this.mainBody.createChild(row,this.getRowDom(rowIndex));
7059 if(row.cellObjects.length){
7060 Roo.each(row.cellObjects, function(r){
7061 _this.renderCellObject(r);
7066 this.fireEvent("rowsinserted", this, rowIndex);
7067 //this.syncRowHeights(firstRow, lastRow);
7068 //this.stripeRows(firstRow);
7075 getRowDom : function(rowIndex)
7077 var rows = this.el.select('tbody > tr', true).elements;
7079 return (typeof(rows[rowIndex]) == 'undefined') ? false : rows[rowIndex];
7082 // returns the object tree for a tr..
7085 renderRow : function(cm, ds, rowIndex)
7087 var d = ds.getAt(rowIndex);
7091 cls : 'x-row-' + rowIndex,
7095 var cellObjects = [];
7097 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
7098 var config = cm.config[i];
7100 var renderer = cm.getRenderer(i);
7104 if(typeof(renderer) !== 'undefined'){
7105 value = renderer(d.data[cm.getDataIndex(i)], false, d);
7107 // if object are returned, then they are expected to be Roo.bootstrap.Component instances
7108 // and are rendered into the cells after the row is rendered - using the id for the element.
7110 if(typeof(value) === 'object'){
7120 rowIndex : rowIndex,
7125 this.fireEvent('rowclass', this, rowcfg);
7129 cls : rowcfg.rowClass + ' x-col-' + i,
7131 html: (typeof(value) === 'object') ? '' : value
7138 if(typeof(config.colspan) != 'undefined'){
7139 td.colspan = config.colspan;
7142 if(typeof(config.hidden) != 'undefined' && config.hidden){
7143 td.style += ' display:none;';
7146 if(typeof(config.align) != 'undefined' && config.align.length){
7147 td.style += ' text-align:' + config.align + ';';
7149 if(typeof(config.valign) != 'undefined' && config.valign.length){
7150 td.style += ' vertical-align:' + config.valign + ';';
7153 if(typeof(config.width) != 'undefined'){
7154 td.style += ' width:' + config.width + 'px;';
7157 if(typeof(config.cursor) != 'undefined'){
7158 td.style += ' cursor:' + config.cursor + ';';
7161 if(typeof(config.cls) != 'undefined'){
7162 td.cls = (typeof(td.cls) == 'undefined') ? config.cls : (td.cls + ' ' + config.cls);
7165 ['xs','sm','md','lg'].map(function(size){
7167 if(typeof(config[size]) == 'undefined'){
7171 if (!config[size]) { // 0 = hidden
7172 td.cls += ' hidden-' + size;
7176 td.cls += ' col-' + size + '-' + config[size];
7184 row.cellObjects = cellObjects;
7192 onBeforeLoad : function()
7201 this.el.select('tbody', true).first().dom.innerHTML = '';
7204 * Show or hide a row.
7205 * @param {Number} rowIndex to show or hide
7206 * @param {Boolean} state hide
7208 setRowVisibility : function(rowIndex, state)
7210 var bt = this.mainBody.dom;
7212 var rows = this.el.select('tbody > tr', true).elements;
7214 if(typeof(rows[rowIndex]) == 'undefined'){
7217 rows[rowIndex].dom.style.display = state ? '' : 'none';
7221 getSelectionModel : function(){
7223 this.selModel = new Roo.bootstrap.Table.RowSelectionModel({grid: this});
7225 return this.selModel;
7228 * Render the Roo.bootstrap object from renderder
7230 renderCellObject : function(r)
7234 r.cfg.parentId = (typeof(r.container) == 'string') ? r.container : r.container.id;
7236 var t = r.cfg.render(r.container);
7239 Roo.each(r.cfg.cn, function(c){
7241 container: t.getChildContainer(),
7244 _this.renderCellObject(child);
7249 getRowIndex : function(row)
7253 Roo.each(this.el.select('tbody > tr', true).elements, function(el, index){
7264 * Returns the grid's underlying element = used by panel.Grid
7265 * @return {Element} The element
7267 getGridEl : function(){
7271 * Forces a resize - used by panel.Grid
7272 * @return {Element} The element
7274 autoSize : function()
7276 //var ctr = Roo.get(this.container.dom.parentElement);
7277 var ctr = Roo.get(this.el.dom);
7279 var thd = this.getGridEl().select('thead',true).first();
7280 var tbd = this.getGridEl().select('tbody', true).first();
7281 var tfd = this.getGridEl().select('tfoot', true).first();
7283 var cw = ctr.getWidth();
7287 tbd.setSize(ctr.getWidth(),
7288 ctr.getHeight() - ((thd ? thd.getHeight() : 0) + (tfd ? tfd.getHeight() : 0))
7290 var barsize = (tbd.dom.offsetWidth - tbd.dom.clientWidth);
7293 cw = Math.max(cw, this.totalWidth);
7294 this.getGridEl().select('tr',true).setWidth(cw);
7295 // resize 'expandable coloumn?
7297 return; // we doe not have a view in this design..
7300 onBodyScroll: function()
7302 //Roo.log("body scrolled');" + this.mainBody.dom.scrollLeft);
7304 this.mainHead.setStyle({
7305 'position' : 'relative',
7306 'left': (-1* this.mainBody.dom.scrollLeft) + 'px'
7312 var scrollHeight = this.mainBody.dom.scrollHeight;
7314 var scrollTop = Math.ceil(this.mainBody.getScroll().top);
7316 var height = this.mainBody.getHeight();
7318 if(scrollHeight - height == scrollTop) {
7320 var total = this.ds.getTotalCount();
7322 if(this.footer.cursor + this.footer.pageSize < total){
7324 this.footer.ds.load({
7326 start : this.footer.cursor + this.footer.pageSize,
7327 limit : this.footer.pageSize
7337 onHeaderChange : function()
7339 var header = this.renderHeader();
7340 var table = this.el.select('table', true).first();
7342 this.mainHead.remove();
7343 this.mainHead = table.createChild(header, this.mainBody, false);
7346 onHiddenChange : function(colModel, colIndex, hidden)
7348 var thSelector = '#' + this.id + ' .x-hcol-' + colIndex;
7349 var tdSelector = '#' + this.id + ' .x-col-' + colIndex;
7351 this.CSS.updateRule(thSelector, "display", "");
7352 this.CSS.updateRule(tdSelector, "display", "");
7355 this.CSS.updateRule(thSelector, "display", "none");
7356 this.CSS.updateRule(tdSelector, "display", "none");
7359 this.onHeaderChange();
7363 setColumnWidth: function(col_index, width)
7365 // width = "md-2 xs-2..."
7366 if(!this.colModel.config[col_index]) {
7370 var w = width.split(" ");
7372 var rows = this.el.dom.getElementsByClassName("x-col-"+col_index);
7374 var h_row = this.el.dom.getElementsByClassName("x-hcol-"+col_index);
7377 for(var j = 0; j < w.length; j++) {
7383 var size_cls = w[j].split("-");
7385 if(!Number.isInteger(size_cls[1] * 1)) {
7389 if(!this.colModel.config[col_index][size_cls[0]]) {
7393 if(!h_row[0].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7397 h_row[0].classList.replace(
7398 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7399 "col-"+size_cls[0]+"-"+size_cls[1]
7402 for(var i = 0; i < rows.length; i++) {
7404 var size_cls = w[j].split("-");
7406 if(!Number.isInteger(size_cls[1] * 1)) {
7410 if(!this.colModel.config[col_index][size_cls[0]]) {
7414 if(!rows[i].classList.contains("col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]])) {
7418 rows[i].classList.replace(
7419 "col-"+size_cls[0]+"-"+this.colModel.config[col_index][size_cls[0]],
7420 "col-"+size_cls[0]+"-"+size_cls[1]
7424 this.colModel.config[col_index][size_cls[0]] = size_cls[1];
7439 * @class Roo.bootstrap.TableCell
7440 * @extends Roo.bootstrap.Component
7441 * Bootstrap TableCell class
7442 * @cfg {String} html cell contain text
7443 * @cfg {String} cls cell class
7444 * @cfg {String} tag cell tag (td|th) default td
7445 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
7446 * @cfg {String} align Aligns the content in a cell
7447 * @cfg {String} axis Categorizes cells
7448 * @cfg {String} bgcolor Specifies the background color of a cell
7449 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7450 * @cfg {Number} colspan Specifies the number of columns a cell should span
7451 * @cfg {String} headers Specifies one or more header cells a cell is related to
7452 * @cfg {Number} height Sets the height of a cell
7453 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
7454 * @cfg {Number} rowspan Sets the number of rows a cell should span
7455 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
7456 * @cfg {String} valign Vertical aligns the content in a cell
7457 * @cfg {Number} width Specifies the width of a cell
7460 * Create a new TableCell
7461 * @param {Object} config The config object
7464 Roo.bootstrap.TableCell = function(config){
7465 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
7468 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
7488 getAutoCreate : function(){
7489 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
7509 cfg.align=this.align
7515 cfg.bgcolor=this.bgcolor
7518 cfg.charoff=this.charoff
7521 cfg.colspan=this.colspan
7524 cfg.headers=this.headers
7527 cfg.height=this.height
7530 cfg.nowrap=this.nowrap
7533 cfg.rowspan=this.rowspan
7536 cfg.scope=this.scope
7539 cfg.valign=this.valign
7542 cfg.width=this.width
7561 * @class Roo.bootstrap.TableRow
7562 * @extends Roo.bootstrap.Component
7563 * Bootstrap TableRow class
7564 * @cfg {String} cls row class
7565 * @cfg {String} align Aligns the content in a table row
7566 * @cfg {String} bgcolor Specifies a background color for a table row
7567 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
7568 * @cfg {String} valign Vertical aligns the content in a table row
7571 * Create a new TableRow
7572 * @param {Object} config The config object
7575 Roo.bootstrap.TableRow = function(config){
7576 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
7579 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
7587 getAutoCreate : function(){
7588 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
7598 cfg.align = this.align;
7601 cfg.bgcolor = this.bgcolor;
7604 cfg.charoff = this.charoff;
7607 cfg.valign = this.valign;
7625 * @class Roo.bootstrap.TableBody
7626 * @extends Roo.bootstrap.Component
7627 * Bootstrap TableBody class
7628 * @cfg {String} cls element class
7629 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
7630 * @cfg {String} align Aligns the content inside the element
7631 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
7632 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
7635 * Create a new TableBody
7636 * @param {Object} config The config object
7639 Roo.bootstrap.TableBody = function(config){
7640 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
7643 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
7651 getAutoCreate : function(){
7652 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
7666 cfg.align = this.align;
7669 cfg.charoff = this.charoff;
7672 cfg.valign = this.valign;
7679 // initEvents : function()
7686 // this.store = Roo.factory(this.store, Roo.data);
7687 // this.store.on('load', this.onLoad, this);
7689 // this.store.load();
7693 // onLoad: function ()
7695 // this.fireEvent('load', this);
7705 * Ext JS Library 1.1.1
7706 * Copyright(c) 2006-2007, Ext JS, LLC.
7708 * Originally Released Under LGPL - original licence link has changed is not relivant.
7711 * <script type="text/javascript">
7714 // as we use this in bootstrap.
7715 Roo.namespace('Roo.form');
7717 * @class Roo.form.Action
7718 * Internal Class used to handle form actions
7720 * @param {Roo.form.BasicForm} el The form element or its id
7721 * @param {Object} config Configuration options
7726 // define the action interface
7727 Roo.form.Action = function(form, options){
7729 this.options = options || {};
7732 * Client Validation Failed
7735 Roo.form.Action.CLIENT_INVALID = 'client';
7737 * Server Validation Failed
7740 Roo.form.Action.SERVER_INVALID = 'server';
7742 * Connect to Server Failed
7745 Roo.form.Action.CONNECT_FAILURE = 'connect';
7747 * Reading Data from Server Failed
7750 Roo.form.Action.LOAD_FAILURE = 'load';
7752 Roo.form.Action.prototype = {
7754 failureType : undefined,
7755 response : undefined,
7759 run : function(options){
7764 success : function(response){
7769 handleResponse : function(response){
7773 // default connection failure
7774 failure : function(response){
7776 this.response = response;
7777 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7778 this.form.afterAction(this, false);
7781 processResponse : function(response){
7782 this.response = response;
7783 if(!response.responseText){
7786 this.result = this.handleResponse(response);
7790 // utility functions used internally
7791 getUrl : function(appendParams){
7792 var url = this.options.url || this.form.url || this.form.el.dom.action;
7794 var p = this.getParams();
7796 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
7802 getMethod : function(){
7803 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
7806 getParams : function(){
7807 var bp = this.form.baseParams;
7808 var p = this.options.params;
7810 if(typeof p == "object"){
7811 p = Roo.urlEncode(Roo.applyIf(p, bp));
7812 }else if(typeof p == 'string' && bp){
7813 p += '&' + Roo.urlEncode(bp);
7816 p = Roo.urlEncode(bp);
7821 createCallback : function(){
7823 success: this.success,
7824 failure: this.failure,
7826 timeout: (this.form.timeout*1000),
7827 upload: this.form.fileUpload ? this.success : undefined
7832 Roo.form.Action.Submit = function(form, options){
7833 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
7836 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
7839 haveProgress : false,
7840 uploadComplete : false,
7842 // uploadProgress indicator.
7843 uploadProgress : function()
7845 if (!this.form.progressUrl) {
7849 if (!this.haveProgress) {
7850 Roo.MessageBox.progress("Uploading", "Uploading");
7852 if (this.uploadComplete) {
7853 Roo.MessageBox.hide();
7857 this.haveProgress = true;
7859 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
7861 var c = new Roo.data.Connection();
7863 url : this.form.progressUrl,
7868 success : function(req){
7869 //console.log(data);
7873 rdata = Roo.decode(req.responseText)
7875 Roo.log("Invalid data from server..");
7879 if (!rdata || !rdata.success) {
7881 Roo.MessageBox.alert(Roo.encode(rdata));
7884 var data = rdata.data;
7886 if (this.uploadComplete) {
7887 Roo.MessageBox.hide();
7892 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
7893 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
7896 this.uploadProgress.defer(2000,this);
7899 failure: function(data) {
7900 Roo.log('progress url failed ');
7911 // run get Values on the form, so it syncs any secondary forms.
7912 this.form.getValues();
7914 var o = this.options;
7915 var method = this.getMethod();
7916 var isPost = method == 'POST';
7917 if(o.clientValidation === false || this.form.isValid()){
7919 if (this.form.progressUrl) {
7920 this.form.findField('UPLOAD_IDENTIFIER').setValue(
7921 (new Date() * 1) + '' + Math.random());
7926 Roo.Ajax.request(Roo.apply(this.createCallback(), {
7927 form:this.form.el.dom,
7928 url:this.getUrl(!isPost),
7930 params:isPost ? this.getParams() : null,
7931 isUpload: this.form.fileUpload,
7932 formData : this.form.formData
7935 this.uploadProgress();
7937 }else if (o.clientValidation !== false){ // client validation failed
7938 this.failureType = Roo.form.Action.CLIENT_INVALID;
7939 this.form.afterAction(this, false);
7943 success : function(response)
7945 this.uploadComplete= true;
7946 if (this.haveProgress) {
7947 Roo.MessageBox.hide();
7951 var result = this.processResponse(response);
7952 if(result === true || result.success){
7953 this.form.afterAction(this, true);
7957 this.form.markInvalid(result.errors);
7958 this.failureType = Roo.form.Action.SERVER_INVALID;
7960 this.form.afterAction(this, false);
7962 failure : function(response)
7964 this.uploadComplete= true;
7965 if (this.haveProgress) {
7966 Roo.MessageBox.hide();
7969 this.response = response;
7970 this.failureType = Roo.form.Action.CONNECT_FAILURE;
7971 this.form.afterAction(this, false);
7974 handleResponse : function(response){
7975 if(this.form.errorReader){
7976 var rs = this.form.errorReader.read(response);
7979 for(var i = 0, len = rs.records.length; i < len; i++) {
7980 var r = rs.records[i];
7984 if(errors.length < 1){
7988 success : rs.success,
7994 ret = Roo.decode(response.responseText);
7998 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
8008 Roo.form.Action.Load = function(form, options){
8009 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
8010 this.reader = this.form.reader;
8013 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
8018 Roo.Ajax.request(Roo.apply(
8019 this.createCallback(), {
8020 method:this.getMethod(),
8021 url:this.getUrl(false),
8022 params:this.getParams()
8026 success : function(response){
8028 var result = this.processResponse(response);
8029 if(result === true || !result.success || !result.data){
8030 this.failureType = Roo.form.Action.LOAD_FAILURE;
8031 this.form.afterAction(this, false);
8034 this.form.clearInvalid();
8035 this.form.setValues(result.data);
8036 this.form.afterAction(this, true);
8039 handleResponse : function(response){
8040 if(this.form.reader){
8041 var rs = this.form.reader.read(response);
8042 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
8044 success : rs.success,
8048 return Roo.decode(response.responseText);
8052 Roo.form.Action.ACTION_TYPES = {
8053 'load' : Roo.form.Action.Load,
8054 'submit' : Roo.form.Action.Submit
8063 * @class Roo.bootstrap.Form
8064 * @extends Roo.bootstrap.Component
8065 * Bootstrap Form class
8066 * @cfg {String} method GET | POST (default POST)
8067 * @cfg {String} labelAlign top | left (default top)
8068 * @cfg {String} align left | right - for navbars
8069 * @cfg {Boolean} loadMask load mask when submit (default true)
8074 * @param {Object} config The config object
8078 Roo.bootstrap.Form = function(config){
8080 Roo.bootstrap.Form.superclass.constructor.call(this, config);
8082 Roo.bootstrap.Form.popover.apply();
8086 * @event clientvalidation
8087 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
8088 * @param {Form} this
8089 * @param {Boolean} valid true if the form has passed client-side validation
8091 clientvalidation: true,
8093 * @event beforeaction
8094 * Fires before any action is performed. Return false to cancel the action.
8095 * @param {Form} this
8096 * @param {Action} action The action to be performed
8100 * @event actionfailed
8101 * Fires when an action fails.
8102 * @param {Form} this
8103 * @param {Action} action The action that failed
8105 actionfailed : true,
8107 * @event actioncomplete
8108 * Fires when an action is completed.
8109 * @param {Form} this
8110 * @param {Action} action The action that completed
8112 actioncomplete : true
8116 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
8119 * @cfg {String} method
8120 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
8125 * The URL to use for form actions if one isn't supplied in the action options.
8128 * @cfg {Boolean} fileUpload
8129 * Set to true if this form is a file upload.
8133 * @cfg {Object} baseParams
8134 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
8138 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
8142 * @cfg {Sting} align (left|right) for navbar forms
8147 activeAction : null,
8150 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
8151 * element by passing it or its id or mask the form itself by passing in true.
8154 waitMsgTarget : false,
8159 * @cfg {Boolean} errorMask (true|false) default false
8164 * @cfg {Number} maskOffset Default 100
8169 * @cfg {Boolean} maskBody
8173 getAutoCreate : function(){
8177 method : this.method || 'POST',
8178 id : this.id || Roo.id(),
8181 if (this.parent().xtype.match(/^Nav/)) {
8182 cfg.cls = 'navbar-form form-inline navbar-' + this.align;
8186 if (this.labelAlign == 'left' ) {
8187 cfg.cls += ' form-horizontal';
8193 initEvents : function()
8195 this.el.on('submit', this.onSubmit, this);
8196 // this was added as random key presses on the form where triggering form submit.
8197 this.el.on('keypress', function(e) {
8198 if (e.getCharCode() != 13) {
8201 // we might need to allow it for textareas.. and some other items.
8202 // check e.getTarget().
8204 if(e.getTarget().nodeName.toLowerCase() === 'textarea'){
8208 Roo.log("keypress blocked");
8216 onSubmit : function(e){
8221 * Returns true if client-side validation on the form is successful.
8224 isValid : function(){
8225 var items = this.getItems();
8229 items.each(function(f){
8235 Roo.log('invalid field: ' + f.name);
8239 if(!target && f.el.isVisible(true)){
8245 if(this.errorMask && !valid){
8246 Roo.bootstrap.Form.popover.mask(this, target);
8253 * Returns true if any fields in this form have changed since their original load.
8256 isDirty : function(){
8258 var items = this.getItems();
8259 items.each(function(f){
8269 * Performs a predefined action (submit or load) or custom actions you define on this form.
8270 * @param {String} actionName The name of the action type
8271 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
8272 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
8273 * accept other config options):
8275 Property Type Description
8276 ---------------- --------------- ----------------------------------------------------------------------------------
8277 url String The url for the action (defaults to the form's url)
8278 method String The form method to use (defaults to the form's method, or POST if not defined)
8279 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
8280 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
8281 validate the form on the client (defaults to false)
8283 * @return {BasicForm} this
8285 doAction : function(action, options){
8286 if(typeof action == 'string'){
8287 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
8289 if(this.fireEvent('beforeaction', this, action) !== false){
8290 this.beforeAction(action);
8291 action.run.defer(100, action);
8297 beforeAction : function(action){
8298 var o = action.options;
8303 Roo.get(document.body).mask(o.waitMsg || "Sending", 'x-mask-loading')
8305 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8308 // not really supported yet.. ??
8310 //if(this.waitMsgTarget === true){
8311 // this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
8312 //}else if(this.waitMsgTarget){
8313 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
8314 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
8316 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
8322 afterAction : function(action, success){
8323 this.activeAction = null;
8324 var o = action.options;
8329 Roo.get(document.body).unmask();
8335 //if(this.waitMsgTarget === true){
8336 // this.el.unmask();
8337 //}else if(this.waitMsgTarget){
8338 // this.waitMsgTarget.unmask();
8340 // Roo.MessageBox.updateProgress(1);
8341 // Roo.MessageBox.hide();
8348 Roo.callback(o.success, o.scope, [this, action]);
8349 this.fireEvent('actioncomplete', this, action);
8353 // failure condition..
8354 // we have a scenario where updates need confirming.
8355 // eg. if a locking scenario exists..
8356 // we look for { errors : { needs_confirm : true }} in the response.
8358 (typeof(action.result) != 'undefined') &&
8359 (typeof(action.result.errors) != 'undefined') &&
8360 (typeof(action.result.errors.needs_confirm) != 'undefined')
8363 Roo.log("not supported yet");
8366 Roo.MessageBox.confirm(
8367 "Change requires confirmation",
8368 action.result.errorMsg,
8373 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
8383 Roo.callback(o.failure, o.scope, [this, action]);
8384 // show an error message if no failed handler is set..
8385 if (!this.hasListener('actionfailed')) {
8386 Roo.log("need to add dialog support");
8388 Roo.MessageBox.alert("Error",
8389 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
8390 action.result.errorMsg :
8391 "Saving Failed, please check your entries or try again"
8396 this.fireEvent('actionfailed', this, action);
8401 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
8402 * @param {String} id The value to search for
8405 findField : function(id){
8406 var items = this.getItems();
8407 var field = items.get(id);
8409 items.each(function(f){
8410 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
8417 return field || null;
8420 * Mark fields in this form invalid in bulk.
8421 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
8422 * @return {BasicForm} this
8424 markInvalid : function(errors){
8425 if(errors instanceof Array){
8426 for(var i = 0, len = errors.length; i < len; i++){
8427 var fieldError = errors[i];
8428 var f = this.findField(fieldError.id);
8430 f.markInvalid(fieldError.msg);
8436 if(typeof errors[id] != 'function' && (field = this.findField(id))){
8437 field.markInvalid(errors[id]);
8441 //Roo.each(this.childForms || [], function (f) {
8442 // f.markInvalid(errors);
8449 * Set values for fields in this form in bulk.
8450 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
8451 * @return {BasicForm} this
8453 setValues : function(values){
8454 if(values instanceof Array){ // array of objects
8455 for(var i = 0, len = values.length; i < len; i++){
8457 var f = this.findField(v.id);
8459 f.setValue(v.value);
8460 if(this.trackResetOnLoad){
8461 f.originalValue = f.getValue();
8465 }else{ // object hash
8468 if(typeof values[id] != 'function' && (field = this.findField(id))){
8470 if (field.setFromData &&
8472 field.displayField &&
8473 // combos' with local stores can
8474 // be queried via setValue()
8475 // to set their value..
8476 (field.store && !field.store.isLocal)
8480 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
8481 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
8482 field.setFromData(sd);
8484 } else if(field.setFromData && (field.store && !field.store.isLocal)) {
8486 field.setFromData(values);
8489 field.setValue(values[id]);
8493 if(this.trackResetOnLoad){
8494 field.originalValue = field.getValue();
8500 //Roo.each(this.childForms || [], function (f) {
8501 // f.setValues(values);
8508 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
8509 * they are returned as an array.
8510 * @param {Boolean} asString
8513 getValues : function(asString){
8514 //if (this.childForms) {
8515 // copy values from the child forms
8516 // Roo.each(this.childForms, function (f) {
8517 // this.setValues(f.getValues());
8523 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
8524 if(asString === true){
8527 return Roo.urlDecode(fs);
8531 * Returns the fields in this form as an object with key/value pairs.
8532 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
8535 getFieldValues : function(with_hidden)
8537 var items = this.getItems();
8539 items.each(function(f){
8545 var v = f.getValue();
8547 if (f.inputType =='radio') {
8548 if (typeof(ret[f.getName()]) == 'undefined') {
8549 ret[f.getName()] = ''; // empty..
8552 if (!f.el.dom.checked) {
8560 if(f.xtype == 'MoneyField'){
8561 ret[f.currencyName] = f.getCurrency();
8564 // not sure if this supported any more..
8565 if ((typeof(v) == 'object') && f.getRawValue) {
8566 v = f.getRawValue() ; // dates..
8568 // combo boxes where name != hiddenName...
8569 if (f.name !== false && f.name != '' && f.name != f.getName()) {
8570 ret[f.name] = f.getRawValue();
8572 ret[f.getName()] = v;
8579 * Clears all invalid messages in this form.
8580 * @return {BasicForm} this
8582 clearInvalid : function(){
8583 var items = this.getItems();
8585 items.each(function(f){
8594 * @return {BasicForm} this
8597 var items = this.getItems();
8598 items.each(function(f){
8602 Roo.each(this.childForms || [], function (f) {
8610 getItems : function()
8612 var r=new Roo.util.MixedCollection(false, function(o){
8613 return o.id || (o.id = Roo.id());
8615 var iter = function(el) {
8622 Roo.each(el.items,function(e) {
8631 hideFields : function(items)
8633 Roo.each(items, function(i){
8635 var f = this.findField(i);
8646 showFields : function(items)
8648 Roo.each(items, function(i){
8650 var f = this.findField(i);
8663 Roo.apply(Roo.bootstrap.Form, {
8690 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
8691 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
8692 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
8693 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
8696 this.maskEl.top.enableDisplayMode("block");
8697 this.maskEl.left.enableDisplayMode("block");
8698 this.maskEl.bottom.enableDisplayMode("block");
8699 this.maskEl.right.enableDisplayMode("block");
8701 this.toolTip = new Roo.bootstrap.Tooltip({
8702 cls : 'roo-form-error-popover',
8704 'left' : ['r-l', [-2,0], 'right'],
8705 'right' : ['l-r', [2,0], 'left'],
8706 'bottom' : ['tl-bl', [0,2], 'top'],
8707 'top' : [ 'bl-tl', [0,-2], 'bottom']
8711 this.toolTip.render(Roo.get(document.body));
8713 this.toolTip.el.enableDisplayMode("block");
8715 Roo.get(document.body).on('click', function(){
8719 Roo.get(document.body).on('touchstart', function(){
8723 this.isApplied = true
8726 mask : function(form, target)
8730 this.target = target;
8732 if(!this.form.errorMask || !target.el){
8736 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.modal', 100, true) || Roo.get(document.body);
8738 Roo.log(scrollable);
8740 var ot = this.target.el.calcOffsetsTo(scrollable);
8742 var scrollTo = ot[1] - this.form.maskOffset;
8744 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
8746 scrollable.scrollTo('top', scrollTo);
8748 var box = this.target.el.getBox();
8750 var zIndex = Roo.bootstrap.Modal.zIndex++;
8753 this.maskEl.top.setStyle('position', 'absolute');
8754 this.maskEl.top.setStyle('z-index', zIndex);
8755 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
8756 this.maskEl.top.setLeft(0);
8757 this.maskEl.top.setTop(0);
8758 this.maskEl.top.show();
8760 this.maskEl.left.setStyle('position', 'absolute');
8761 this.maskEl.left.setStyle('z-index', zIndex);
8762 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
8763 this.maskEl.left.setLeft(0);
8764 this.maskEl.left.setTop(box.y - this.padding);
8765 this.maskEl.left.show();
8767 this.maskEl.bottom.setStyle('position', 'absolute');
8768 this.maskEl.bottom.setStyle('z-index', zIndex);
8769 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
8770 this.maskEl.bottom.setLeft(0);
8771 this.maskEl.bottom.setTop(box.bottom + this.padding);
8772 this.maskEl.bottom.show();
8774 this.maskEl.right.setStyle('position', 'absolute');
8775 this.maskEl.right.setStyle('z-index', zIndex);
8776 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
8777 this.maskEl.right.setLeft(box.right + this.padding);
8778 this.maskEl.right.setTop(box.y - this.padding);
8779 this.maskEl.right.show();
8781 this.toolTip.bindEl = this.target.el;
8783 this.toolTip.el.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
8785 var tip = this.target.blankText;
8787 if(this.target.getValue() !== '' ) {
8789 if (this.target.invalidText.length) {
8790 tip = this.target.invalidText;
8791 } else if (this.target.regexText.length){
8792 tip = this.target.regexText;
8796 this.toolTip.show(tip);
8798 this.intervalID = window.setInterval(function() {
8799 Roo.bootstrap.Form.popover.unmask();
8802 window.onwheel = function(){ return false;};
8804 (function(){ this.isMasked = true; }).defer(500, this);
8810 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
8814 this.maskEl.top.setStyle('position', 'absolute');
8815 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
8816 this.maskEl.top.hide();
8818 this.maskEl.left.setStyle('position', 'absolute');
8819 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
8820 this.maskEl.left.hide();
8822 this.maskEl.bottom.setStyle('position', 'absolute');
8823 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
8824 this.maskEl.bottom.hide();
8826 this.maskEl.right.setStyle('position', 'absolute');
8827 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
8828 this.maskEl.right.hide();
8830 this.toolTip.hide();
8832 this.toolTip.el.hide();
8834 window.onwheel = function(){ return true;};
8836 if(this.intervalID){
8837 window.clearInterval(this.intervalID);
8838 this.intervalID = false;
8841 this.isMasked = false;
8851 * Ext JS Library 1.1.1
8852 * Copyright(c) 2006-2007, Ext JS, LLC.
8854 * Originally Released Under LGPL - original licence link has changed is not relivant.
8857 * <script type="text/javascript">
8860 * @class Roo.form.VTypes
8861 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
8864 Roo.form.VTypes = function(){
8865 // closure these in so they are only created once.
8866 var alpha = /^[a-zA-Z_]+$/;
8867 var alphanum = /^[a-zA-Z0-9_]+$/;
8868 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
8869 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
8871 // All these messages and functions are configurable
8874 * The function used to validate email addresses
8875 * @param {String} value The email address
8877 'email' : function(v){
8878 return email.test(v);
8881 * The error text to display when the email validation function returns false
8884 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
8886 * The keystroke filter mask to be applied on email input
8889 'emailMask' : /[a-z0-9_\.\-@]/i,
8892 * The function used to validate URLs
8893 * @param {String} value The URL
8895 'url' : function(v){
8899 * The error text to display when the url validation function returns false
8902 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
8905 * The function used to validate alpha values
8906 * @param {String} value The value
8908 'alpha' : function(v){
8909 return alpha.test(v);
8912 * The error text to display when the alpha validation function returns false
8915 'alphaText' : 'This field should only contain letters and _',
8917 * The keystroke filter mask to be applied on alpha input
8920 'alphaMask' : /[a-z_]/i,
8923 * The function used to validate alphanumeric values
8924 * @param {String} value The value
8926 'alphanum' : function(v){
8927 return alphanum.test(v);
8930 * The error text to display when the alphanumeric validation function returns false
8933 'alphanumText' : 'This field should only contain letters, numbers and _',
8935 * The keystroke filter mask to be applied on alphanumeric input
8938 'alphanumMask' : /[a-z0-9_]/i
8948 * @class Roo.bootstrap.Input
8949 * @extends Roo.bootstrap.Component
8950 * Bootstrap Input class
8951 * @cfg {Boolean} disabled is it disabled
8952 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
8953 * @cfg {String} name name of the input
8954 * @cfg {string} fieldLabel - the label associated
8955 * @cfg {string} placeholder - placeholder to put in text.
8956 * @cfg {string} before - input group add on before
8957 * @cfg {string} after - input group add on after
8958 * @cfg {string} size - (lg|sm) or leave empty..
8959 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
8960 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
8961 * @cfg {Number} md colspan out of 12 for computer-sized screens
8962 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
8963 * @cfg {string} value default value of the input
8964 * @cfg {Number} labelWidth set the width of label
8965 * @cfg {Number} labellg set the width of label (1-12)
8966 * @cfg {Number} labelmd set the width of label (1-12)
8967 * @cfg {Number} labelsm set the width of label (1-12)
8968 * @cfg {Number} labelxs set the width of label (1-12)
8969 * @cfg {String} labelAlign (top|left)
8970 * @cfg {Boolean} readOnly Specifies that the field should be read-only
8971 * @cfg {String} autocomplete - default is new-password see: https://developers.google.com/web/fundamentals/input/form/label-and-name-inputs?hl=en
8972 * @cfg {String} indicatorpos (left|right) default left
8973 * @cfg {String} capture (user|camera) use for file input only. (default empty)
8974 * @cfg {String} accept (image|video|audio) use for file input only. (default empty)
8976 * @cfg {String} align (left|center|right) Default left
8977 * @cfg {Boolean} forceFeedback (true|false) Default false
8980 * Create a new Input
8981 * @param {Object} config The config object
8984 Roo.bootstrap.Input = function(config){
8986 Roo.bootstrap.Input.superclass.constructor.call(this, config);
8991 * Fires when this field receives input focus.
8992 * @param {Roo.form.Field} this
8997 * Fires when this field loses input focus.
8998 * @param {Roo.form.Field} this
9003 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
9004 * {@link Roo.EventObject#getKey} to determine which key was pressed.
9005 * @param {Roo.form.Field} this
9006 * @param {Roo.EventObject} e The event object
9011 * Fires just before the field blurs if the field value has changed.
9012 * @param {Roo.form.Field} this
9013 * @param {Mixed} newValue The new value
9014 * @param {Mixed} oldValue The original value
9019 * Fires after the field has been marked as invalid.
9020 * @param {Roo.form.Field} this
9021 * @param {String} msg The validation message
9026 * Fires after the field has been validated with no errors.
9027 * @param {Roo.form.Field} this
9032 * Fires after the key up
9033 * @param {Roo.form.Field} this
9034 * @param {Roo.EventObject} e The event Object
9040 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
9042 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
9043 automatic validation (defaults to "keyup").
9045 validationEvent : "keyup",
9047 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
9049 validateOnBlur : true,
9051 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
9053 validationDelay : 250,
9055 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
9057 focusClass : "x-form-focus", // not needed???
9061 * @cfg {String} invalidClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9063 invalidClass : "has-warning",
9066 * @cfg {String} validClass DEPRICATED - code uses BS4 - is-valid / is-invalid
9068 validClass : "has-success",
9071 * @cfg {Boolean} hasFeedback (true|false) default true
9076 * @cfg {String} invalidFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9078 invalidFeedbackClass : "glyphicon-warning-sign",
9081 * @cfg {String} validFeedbackIcon The CSS class to use when create feedback icon (defaults to "x-form-invalid")
9083 validFeedbackClass : "glyphicon-ok",
9086 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
9088 selectOnFocus : false,
9091 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
9095 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
9100 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
9102 disableKeyFilter : false,
9105 * @cfg {Boolean} disabled True to disable the field (defaults to false).
9109 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
9113 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
9115 blankText : "Please complete this mandatory field",
9118 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
9122 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
9124 maxLength : Number.MAX_VALUE,
9126 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
9128 minLengthText : "The minimum length for this field is {0}",
9130 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
9132 maxLengthText : "The maximum length for this field is {0}",
9136 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
9137 * If available, this function will be called only after the basic validators all return true, and will be passed the
9138 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
9142 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
9143 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
9144 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
9148 * @cfg {String} regexText -- Depricated - use Invalid Text
9153 * @cfg {String} invalidText The error text to display if {@link #validator} test fails during validation (defaults to "")
9159 autocomplete: false,
9178 formatedValue : false,
9179 forceFeedback : false,
9181 indicatorpos : 'left',
9191 parentLabelAlign : function()
9194 while (parent.parent()) {
9195 parent = parent.parent();
9196 if (typeof(parent.labelAlign) !='undefined') {
9197 return parent.labelAlign;
9204 getAutoCreate : function()
9206 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
9212 if(this.inputType != 'hidden'){
9213 cfg.cls = 'form-group' //input-group
9219 type : this.inputType,
9221 cls : 'form-control',
9222 placeholder : this.placeholder || '',
9223 autocomplete : this.autocomplete || 'new-password'
9226 if(this.capture.length){
9227 input.capture = this.capture;
9230 if(this.accept.length){
9231 input.accept = this.accept + "/*";
9235 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
9238 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
9239 input.maxLength = this.maxLength;
9242 if (this.disabled) {
9243 input.disabled=true;
9246 if (this.readOnly) {
9247 input.readonly=true;
9251 input.name = this.name;
9255 input.cls += ' input-' + this.size;
9259 ['xs','sm','md','lg'].map(function(size){
9260 if (settings[size]) {
9261 cfg.cls += ' col-' + size + '-' + settings[size];
9265 var inputblock = input;
9269 cls: 'glyphicon form-control-feedback'
9272 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9275 cls : 'has-feedback',
9283 if (this.before || this.after) {
9286 cls : 'input-group',
9290 if (this.before && typeof(this.before) == 'string') {
9292 inputblock.cn.push({
9294 cls : 'roo-input-before input-group-addon input-group-prepend input-group-text',
9298 if (this.before && typeof(this.before) == 'object') {
9299 this.before = Roo.factory(this.before);
9301 inputblock.cn.push({
9303 cls : 'roo-input-before input-group-prepend input-group-text input-group-' +
9304 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9308 inputblock.cn.push(input);
9310 if (this.after && typeof(this.after) == 'string') {
9311 inputblock.cn.push({
9313 cls : 'roo-input-after input-group-append input-group-text input-group-addon',
9317 if (this.after && typeof(this.after) == 'object') {
9318 this.after = Roo.factory(this.after);
9320 inputblock.cn.push({
9322 cls : 'roo-input-after input-group-append input-group-text input-group-' +
9323 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
9327 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9328 inputblock.cls += ' has-feedback';
9329 inputblock.cn.push(feedback);
9334 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
9335 tooltip : 'This field is required'
9337 if (Roo.bootstrap.version == 4) {
9340 style : 'display-none'
9343 if (align ==='left' && this.fieldLabel.length) {
9345 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
9352 cls : 'control-label col-form-label',
9353 html : this.fieldLabel
9364 var labelCfg = cfg.cn[1];
9365 var contentCfg = cfg.cn[2];
9367 if(this.indicatorpos == 'right'){
9372 cls : 'control-label col-form-label',
9376 html : this.fieldLabel
9390 labelCfg = cfg.cn[0];
9391 contentCfg = cfg.cn[1];
9395 if(this.labelWidth > 12){
9396 labelCfg.style = "width: " + this.labelWidth + 'px';
9399 if(this.labelWidth < 13 && this.labelmd == 0){
9400 this.labelmd = this.labelWidth;
9403 if(this.labellg > 0){
9404 labelCfg.cls += ' col-lg-' + this.labellg;
9405 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
9408 if(this.labelmd > 0){
9409 labelCfg.cls += ' col-md-' + this.labelmd;
9410 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
9413 if(this.labelsm > 0){
9414 labelCfg.cls += ' col-sm-' + this.labelsm;
9415 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
9418 if(this.labelxs > 0){
9419 labelCfg.cls += ' col-xs-' + this.labelxs;
9420 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
9424 } else if ( this.fieldLabel.length) {
9429 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
9430 tooltip : 'This field is required'
9434 //cls : 'input-group-addon',
9435 html : this.fieldLabel
9443 if(this.indicatorpos == 'right'){
9448 //cls : 'input-group-addon',
9449 html : this.fieldLabel
9454 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
9455 tooltip : 'This field is required'
9475 if (this.parentType === 'Navbar' && this.parent().bar) {
9476 cfg.cls += ' navbar-form';
9479 if (this.parentType === 'NavGroup' && !(Roo.bootstrap.version == 4 && this.parent().form)) {
9480 // on BS4 we do this only if not form
9481 cfg.cls += ' navbar-form';
9489 * return the real input element.
9491 inputEl: function ()
9493 return this.el.select('input.form-control',true).first();
9496 tooltipEl : function()
9498 return this.inputEl();
9501 indicatorEl : function()
9503 if (Roo.bootstrap.version == 4) {
9504 return false; // not enabled in v4 yet.
9507 var indicator = this.el.select('i.roo-required-indicator',true).first();
9517 setDisabled : function(v)
9519 var i = this.inputEl().dom;
9521 i.removeAttribute('disabled');
9525 i.setAttribute('disabled','true');
9527 initEvents : function()
9530 this.inputEl().on("keydown" , this.fireKey, this);
9531 this.inputEl().on("focus", this.onFocus, this);
9532 this.inputEl().on("blur", this.onBlur, this);
9534 this.inputEl().relayEvent('keyup', this);
9536 this.indicator = this.indicatorEl();
9539 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible'); // changed from invisible??? -
9542 // reference to original value for reset
9543 this.originalValue = this.getValue();
9544 //Roo.form.TextField.superclass.initEvents.call(this);
9545 if(this.validationEvent == 'keyup'){
9546 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
9547 this.inputEl().on('keyup', this.filterValidation, this);
9549 else if(this.validationEvent !== false){
9550 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
9553 if(this.selectOnFocus){
9554 this.on("focus", this.preFocus, this);
9557 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
9558 this.inputEl().on("keypress", this.filterKeys, this);
9560 this.inputEl().relayEvent('keypress', this);
9563 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
9564 this.el.on("click", this.autoSize, this);
9567 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
9568 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
9571 if (typeof(this.before) == 'object') {
9572 this.before.render(this.el.select('.roo-input-before',true).first());
9574 if (typeof(this.after) == 'object') {
9575 this.after.render(this.el.select('.roo-input-after',true).first());
9578 this.inputEl().on('change', this.onChange, this);
9581 filterValidation : function(e){
9582 if(!e.isNavKeyPress()){
9583 this.validationTask.delay(this.validationDelay);
9587 * Validates the field value
9588 * @return {Boolean} True if the value is valid, else false
9590 validate : function(){
9591 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
9592 if(this.disabled || this.validateValue(this.getRawValue())){
9603 * Validates a value according to the field's validation rules and marks the field as invalid
9604 * if the validation fails
9605 * @param {Mixed} value The value to validate
9606 * @return {Boolean} True if the value is valid, else false
9608 validateValue : function(value)
9610 if(this.getVisibilityEl().hasClass('hidden')){
9614 if(value.length < 1) { // if it's blank
9615 if(this.allowBlank){
9621 if(value.length < this.minLength){
9624 if(value.length > this.maxLength){
9628 var vt = Roo.form.VTypes;
9629 if(!vt[this.vtype](value, this)){
9633 if(typeof this.validator == "function"){
9634 var msg = this.validator(value);
9638 if (typeof(msg) == 'string') {
9639 this.invalidText = msg;
9643 if(this.regex && !this.regex.test(value)){
9651 fireKey : function(e){
9652 //Roo.log('field ' + e.getKey());
9653 if(e.isNavKeyPress()){
9654 this.fireEvent("specialkey", this, e);
9657 focus : function (selectText){
9659 this.inputEl().focus();
9660 if(selectText === true){
9661 this.inputEl().dom.select();
9667 onFocus : function(){
9668 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9669 // this.el.addClass(this.focusClass);
9672 this.hasFocus = true;
9673 this.startValue = this.getValue();
9674 this.fireEvent("focus", this);
9678 beforeBlur : Roo.emptyFn,
9682 onBlur : function(){
9684 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
9685 //this.el.removeClass(this.focusClass);
9687 this.hasFocus = false;
9688 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
9691 var v = this.getValue();
9692 if(String(v) !== String(this.startValue)){
9693 this.fireEvent('change', this, v, this.startValue);
9695 this.fireEvent("blur", this);
9698 onChange : function(e)
9700 var v = this.getValue();
9701 if(String(v) !== String(this.startValue)){
9702 this.fireEvent('change', this, v, this.startValue);
9708 * Resets the current field value to the originally loaded value and clears any validation messages
9711 this.setValue(this.originalValue);
9715 * Returns the name of the field
9716 * @return {Mixed} name The name field
9718 getName: function(){
9722 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
9723 * @return {Mixed} value The field value
9725 getValue : function(){
9727 var v = this.inputEl().getValue();
9732 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
9733 * @return {Mixed} value The field value
9735 getRawValue : function(){
9736 var v = this.inputEl().getValue();
9742 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
9743 * @param {Mixed} value The value to set
9745 setRawValue : function(v){
9746 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9749 selectText : function(start, end){
9750 var v = this.getRawValue();
9752 start = start === undefined ? 0 : start;
9753 end = end === undefined ? v.length : end;
9754 var d = this.inputEl().dom;
9755 if(d.setSelectionRange){
9756 d.setSelectionRange(start, end);
9757 }else if(d.createTextRange){
9758 var range = d.createTextRange();
9759 range.moveStart("character", start);
9760 range.moveEnd("character", v.length-end);
9767 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
9768 * @param {Mixed} value The value to set
9770 setValue : function(v){
9773 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
9779 processValue : function(value){
9780 if(this.stripCharsRe){
9781 var newValue = value.replace(this.stripCharsRe, '');
9782 if(newValue !== value){
9783 this.setRawValue(newValue);
9790 preFocus : function(){
9792 if(this.selectOnFocus){
9793 this.inputEl().dom.select();
9796 filterKeys : function(e){
9798 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
9801 var c = e.getCharCode(), cc = String.fromCharCode(c);
9802 if(Roo.isIE && (e.isSpecialKey() || !cc)){
9805 if(!this.maskRe.test(cc)){
9810 * Clear any invalid styles/messages for this field
9812 clearInvalid : function(){
9814 if(!this.el || this.preventMark){ // not rendered
9819 this.el.removeClass([this.invalidClass, 'is-invalid']);
9821 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9823 var feedback = this.el.select('.form-control-feedback', true).first();
9826 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
9832 this.indicator.removeClass('visible');
9833 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9836 this.fireEvent('valid', this);
9840 * Mark this field as valid
9842 markValid : function()
9844 if(!this.el || this.preventMark){ // not rendered...
9848 this.el.removeClass([this.invalidClass, this.validClass]);
9849 this.inputEl().removeClass(['is-valid', 'is-invalid']);
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]);
9858 this.indicator.removeClass('visible');
9859 this.indicator.addClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9866 if(this.allowBlank && !this.getRawValue().length){
9869 if (Roo.bootstrap.version == 3) {
9870 this.el.addClass(this.validClass);
9872 this.inputEl().addClass('is-valid');
9875 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
9877 var feedback = this.el.select('.form-control-feedback', true).first();
9880 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9881 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
9886 this.fireEvent('valid', this);
9890 * Mark this field as invalid
9891 * @param {String} msg The validation message
9893 markInvalid : function(msg)
9895 if(!this.el || this.preventMark){ // not rendered
9899 this.el.removeClass([this.invalidClass, this.validClass]);
9900 this.inputEl().removeClass(['is-valid', 'is-invalid']);
9902 var feedback = this.el.select('.form-control-feedback', true).first();
9905 this.el.select('.form-control-feedback', true).first().removeClass(
9906 [this.invalidFeedbackClass, this.validFeedbackClass]);
9913 if(this.allowBlank && !this.getRawValue().length){
9918 this.indicator.removeClass(this.indicatorpos == 'right' ? 'hidden' : 'invisible');
9919 this.indicator.addClass('visible');
9921 if (Roo.bootstrap.version == 3) {
9922 this.el.addClass(this.invalidClass);
9924 this.inputEl().addClass('is-invalid');
9929 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
9931 var feedback = this.el.select('.form-control-feedback', true).first();
9934 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
9936 if(this.getValue().length || this.forceFeedback){
9937 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
9944 this.fireEvent('invalid', this, msg);
9947 SafariOnKeyDown : function(event)
9949 // this is a workaround for a password hang bug on chrome/ webkit.
9950 if (this.inputEl().dom.type != 'password') {
9954 var isSelectAll = false;
9956 if(this.inputEl().dom.selectionEnd > 0){
9957 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
9959 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
9960 event.preventDefault();
9965 if(isSelectAll && event.getCharCode() > 31 && !event.ctrlKey) { // not backspace and delete key (or ctrl-v)
9967 event.preventDefault();
9968 // this is very hacky as keydown always get's upper case.
9970 var cc = String.fromCharCode(event.getCharCode());
9971 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
9975 adjustWidth : function(tag, w){
9976 tag = tag.toLowerCase();
9977 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
9978 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
9982 if(tag == 'textarea'){
9985 }else if(Roo.isOpera){
9989 if(tag == 'textarea'){
9997 setFieldLabel : function(v)
10003 if(this.indicatorEl()){
10004 var ar = this.el.select('label > span',true);
10006 if (ar.elements.length) {
10007 this.el.select('label > span',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10008 this.fieldLabel = v;
10012 var br = this.el.select('label',true);
10014 if(br.elements.length) {
10015 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10016 this.fieldLabel = v;
10020 Roo.log('Cannot Found any of label > span || label in input');
10024 this.el.select('label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
10025 this.fieldLabel = v;
10040 * @class Roo.bootstrap.TextArea
10041 * @extends Roo.bootstrap.Input
10042 * Bootstrap TextArea class
10043 * @cfg {Number} cols Specifies the visible width of a text area
10044 * @cfg {Number} rows Specifies the visible number of lines in a text area
10045 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
10046 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
10047 * @cfg {string} html text
10050 * Create a new TextArea
10051 * @param {Object} config The config object
10054 Roo.bootstrap.TextArea = function(config){
10055 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
10059 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
10069 getAutoCreate : function(){
10071 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
10077 if(this.inputType != 'hidden'){
10078 cfg.cls = 'form-group' //input-group
10086 value : this.value || '',
10087 html: this.html || '',
10088 cls : 'form-control',
10089 placeholder : this.placeholder || ''
10093 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
10094 input.maxLength = this.maxLength;
10098 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
10102 input.cols = this.cols;
10105 if (this.readOnly) {
10106 input.readonly = true;
10110 input.name = this.name;
10114 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
10118 ['xs','sm','md','lg'].map(function(size){
10119 if (settings[size]) {
10120 cfg.cls += ' col-' + size + '-' + settings[size];
10124 var inputblock = input;
10126 if(this.hasFeedback && !this.allowBlank){
10130 cls: 'glyphicon form-control-feedback'
10134 cls : 'has-feedback',
10143 if (this.before || this.after) {
10146 cls : 'input-group',
10150 inputblock.cn.push({
10152 cls : 'input-group-addon',
10157 inputblock.cn.push(input);
10159 if(this.hasFeedback && !this.allowBlank){
10160 inputblock.cls += ' has-feedback';
10161 inputblock.cn.push(feedback);
10165 inputblock.cn.push({
10167 cls : 'input-group-addon',
10174 if (align ==='left' && this.fieldLabel.length) {
10179 cls : 'control-label',
10180 html : this.fieldLabel
10191 if(this.labelWidth > 12){
10192 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
10195 if(this.labelWidth < 13 && this.labelmd == 0){
10196 this.labelmd = this.labelWidth;
10199 if(this.labellg > 0){
10200 cfg.cn[0].cls += ' col-lg-' + this.labellg;
10201 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
10204 if(this.labelmd > 0){
10205 cfg.cn[0].cls += ' col-md-' + this.labelmd;
10206 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
10209 if(this.labelsm > 0){
10210 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
10211 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
10214 if(this.labelxs > 0){
10215 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
10216 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
10219 } else if ( this.fieldLabel.length) {
10224 //cls : 'input-group-addon',
10225 html : this.fieldLabel
10243 if (this.disabled) {
10244 input.disabled=true;
10251 * return the real textarea element.
10253 inputEl: function ()
10255 return this.el.select('textarea.form-control',true).first();
10259 * Clear any invalid styles/messages for this field
10261 clearInvalid : function()
10264 if(!this.el || this.preventMark){ // not rendered
10268 var label = this.el.select('label', true).first();
10269 var icon = this.el.select('i.fa-star', true).first();
10274 this.el.removeClass( this.validClass);
10275 this.inputEl().removeClass('is-invalid');
10277 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10279 var feedback = this.el.select('.form-control-feedback', true).first();
10282 this.el.select('.form-control-feedback', true).first().removeClass(this.invalidFeedbackClass);
10287 this.fireEvent('valid', this);
10291 * Mark this field as valid
10293 markValid : function()
10295 if(!this.el || this.preventMark){ // not rendered
10299 this.el.removeClass([this.invalidClass, this.validClass]);
10300 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10302 var feedback = this.el.select('.form-control-feedback', true).first();
10305 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10308 if(this.disabled || this.allowBlank){
10312 var label = this.el.select('label', true).first();
10313 var icon = this.el.select('i.fa-star', true).first();
10318 if (Roo.bootstrap.version == 3) {
10319 this.el.addClass(this.validClass);
10321 this.inputEl().addClass('is-valid');
10325 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank && (this.getValue().length || this.forceFeedback)){
10327 var feedback = this.el.select('.form-control-feedback', true).first();
10330 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10331 this.el.select('.form-control-feedback', true).first().addClass([this.validFeedbackClass]);
10336 this.fireEvent('valid', this);
10340 * Mark this field as invalid
10341 * @param {String} msg The validation message
10343 markInvalid : function(msg)
10345 if(!this.el || this.preventMark){ // not rendered
10349 this.el.removeClass([this.invalidClass, this.validClass]);
10350 this.inputEl().removeClass(['is-valid', 'is-invalid']);
10352 var feedback = this.el.select('.form-control-feedback', true).first();
10355 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10358 if(this.disabled || this.allowBlank){
10362 var label = this.el.select('label', true).first();
10363 var icon = this.el.select('i.fa-star', true).first();
10365 if(!this.getValue().length && label && !icon){
10366 this.el.createChild({
10368 cls : 'text-danger fa fa-lg fa-star',
10369 tooltip : 'This field is required',
10370 style : 'margin-right:5px;'
10374 if (Roo.bootstrap.version == 3) {
10375 this.el.addClass(this.invalidClass);
10377 this.inputEl().addClass('is-invalid');
10380 // fixme ... this may be depricated need to test..
10381 if(this.hasFeedback && this.inputType != 'hidden' && !this.allowBlank){
10383 var feedback = this.el.select('.form-control-feedback', true).first();
10386 this.el.select('.form-control-feedback', true).first().removeClass([this.invalidFeedbackClass, this.validFeedbackClass]);
10388 if(this.getValue().length || this.forceFeedback){
10389 this.el.select('.form-control-feedback', true).first().addClass([this.invalidFeedbackClass]);
10396 this.fireEvent('invalid', this, msg);
10404 * trigger field - base class for combo..
10409 * @class Roo.bootstrap.TriggerField
10410 * @extends Roo.bootstrap.Input
10411 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
10412 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
10413 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
10414 * for which you can provide a custom implementation. For example:
10416 var trigger = new Roo.bootstrap.TriggerField();
10417 trigger.onTriggerClick = myTriggerFn;
10418 trigger.applyTo('my-field');
10421 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
10422 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
10423 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
10424 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
10425 * @cfg {String} caret (search|calendar) a fontawesome for the trigger icon see http://fortawesome.github.io/Font-Awesome/icons/
10428 * Create a new TriggerField.
10429 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
10430 * to the base TextField)
10432 Roo.bootstrap.TriggerField = function(config){
10433 this.mimicing = false;
10434 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
10437 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
10439 * @cfg {String} triggerClass A CSS class to apply to the trigger
10442 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
10447 * @cfg {Boolean} removable (true|false) special filter default false
10451 /** @cfg {Boolean} grow @hide */
10452 /** @cfg {Number} growMin @hide */
10453 /** @cfg {Number} growMax @hide */
10459 autoSize: Roo.emptyFn,
10463 deferHeight : true,
10466 actionMode : 'wrap',
10471 getAutoCreate : function(){
10473 var align = this.labelAlign || this.parentLabelAlign();
10478 cls: 'form-group' //input-group
10485 type : this.inputType,
10486 cls : 'form-control',
10487 autocomplete: 'new-password',
10488 placeholder : this.placeholder || ''
10492 input.name = this.name;
10495 input.cls += ' input-' + this.size;
10498 if (this.disabled) {
10499 input.disabled=true;
10502 var inputblock = input;
10504 if(this.hasFeedback && !this.allowBlank){
10508 cls: 'glyphicon form-control-feedback'
10511 if(this.removable && !this.editable && !this.tickable){
10513 cls : 'has-feedback',
10519 cls : 'roo-combo-removable-btn close'
10526 cls : 'has-feedback',
10535 if(this.removable && !this.editable && !this.tickable){
10537 cls : 'roo-removable',
10543 cls : 'roo-combo-removable-btn close'
10550 if (this.before || this.after) {
10553 cls : 'input-group',
10557 inputblock.cn.push({
10559 cls : 'input-group-addon input-group-prepend input-group-text',
10564 inputblock.cn.push(input);
10566 if(this.hasFeedback && !this.allowBlank){
10567 inputblock.cls += ' has-feedback';
10568 inputblock.cn.push(feedback);
10572 inputblock.cn.push({
10574 cls : 'input-group-addon input-group-append input-group-text',
10583 var ibwrap = inputblock;
10588 cls: 'roo-select2-choices',
10592 cls: 'roo-select2-search-field',
10604 cls: 'roo-select2-container input-group',
10609 cls: 'form-hidden-field'
10615 if(!this.multiple && this.showToggleBtn){
10621 if (this.caret != false) {
10624 cls: 'fa fa-' + this.caret
10631 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
10636 cls: 'combobox-clear',
10650 combobox.cls += ' roo-select2-container-multi';
10654 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
10655 tooltip : 'This field is required'
10657 if (Roo.bootstrap.version == 4) {
10660 style : 'display:none'
10665 if (align ==='left' && this.fieldLabel.length) {
10667 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
10674 cls : 'control-label',
10675 html : this.fieldLabel
10687 var labelCfg = cfg.cn[1];
10688 var contentCfg = cfg.cn[2];
10690 if(this.indicatorpos == 'right'){
10695 cls : 'control-label',
10699 html : this.fieldLabel
10713 labelCfg = cfg.cn[0];
10714 contentCfg = cfg.cn[1];
10717 if(this.labelWidth > 12){
10718 labelCfg.style = "width: " + this.labelWidth + 'px';
10721 if(this.labelWidth < 13 && this.labelmd == 0){
10722 this.labelmd = this.labelWidth;
10725 if(this.labellg > 0){
10726 labelCfg.cls += ' col-lg-' + this.labellg;
10727 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
10730 if(this.labelmd > 0){
10731 labelCfg.cls += ' col-md-' + this.labelmd;
10732 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
10735 if(this.labelsm > 0){
10736 labelCfg.cls += ' col-sm-' + this.labelsm;
10737 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
10740 if(this.labelxs > 0){
10741 labelCfg.cls += ' col-xs-' + this.labelxs;
10742 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
10745 } else if ( this.fieldLabel.length) {
10746 // Roo.log(" label");
10751 //cls : 'input-group-addon',
10752 html : this.fieldLabel
10760 if(this.indicatorpos == 'right'){
10768 html : this.fieldLabel
10782 // Roo.log(" no label && no align");
10789 ['xs','sm','md','lg'].map(function(size){
10790 if (settings[size]) {
10791 cfg.cls += ' col-' + size + '-' + settings[size];
10802 onResize : function(w, h){
10803 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
10804 // if(typeof w == 'number'){
10805 // var x = w - this.trigger.getWidth();
10806 // this.inputEl().setWidth(this.adjustWidth('input', x));
10807 // this.trigger.setStyle('left', x+'px');
10812 adjustSize : Roo.BoxComponent.prototype.adjustSize,
10815 getResizeEl : function(){
10816 return this.inputEl();
10820 getPositionEl : function(){
10821 return this.inputEl();
10825 alignErrorIcon : function(){
10826 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
10830 initEvents : function(){
10834 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
10835 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
10836 if(!this.multiple && this.showToggleBtn){
10837 this.trigger = this.el.select('span.dropdown-toggle',true).first();
10838 if(this.hideTrigger){
10839 this.trigger.setDisplayed(false);
10841 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
10845 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
10848 if(this.removable && !this.editable && !this.tickable){
10849 var close = this.closeTriggerEl();
10852 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
10853 close.on('click', this.removeBtnClick, this, close);
10857 //this.trigger.addClassOnOver('x-form-trigger-over');
10858 //this.trigger.addClassOnClick('x-form-trigger-click');
10861 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
10865 closeTriggerEl : function()
10867 var close = this.el.select('.roo-combo-removable-btn', true).first();
10868 return close ? close : false;
10871 removeBtnClick : function(e, h, el)
10873 e.preventDefault();
10875 if(this.fireEvent("remove", this) !== false){
10877 this.fireEvent("afterremove", this)
10881 createList : function()
10883 this.list = Roo.get(document.body).createChild({
10884 tag: Roo.bootstrap.version == 4 ? 'div' : 'ul',
10885 cls: 'typeahead typeahead-long dropdown-menu',
10886 style: 'display:none'
10889 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';;
10894 initTrigger : function(){
10899 onDestroy : function(){
10901 this.trigger.removeAllListeners();
10902 // this.trigger.remove();
10905 // this.wrap.remove();
10907 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
10911 onFocus : function(){
10912 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
10914 if(!this.mimicing){
10915 this.wrap.addClass('x-trigger-wrap-focus');
10916 this.mimicing = true;
10917 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
10918 if(this.monitorTab){
10919 this.el.on("keydown", this.checkTab, this);
10926 checkTab : function(e){
10927 if(e.getKey() == e.TAB){
10928 this.triggerBlur();
10933 onBlur : function(){
10938 mimicBlur : function(e, t){
10940 if(!this.wrap.contains(t) && this.validateBlur()){
10941 this.triggerBlur();
10947 triggerBlur : function(){
10948 this.mimicing = false;
10949 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
10950 if(this.monitorTab){
10951 this.el.un("keydown", this.checkTab, this);
10953 //this.wrap.removeClass('x-trigger-wrap-focus');
10954 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
10958 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
10959 validateBlur : function(e, t){
10964 onDisable : function(){
10965 this.inputEl().dom.disabled = true;
10966 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
10968 // this.wrap.addClass('x-item-disabled');
10973 onEnable : function(){
10974 this.inputEl().dom.disabled = false;
10975 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
10977 // this.el.removeClass('x-item-disabled');
10982 onShow : function(){
10983 var ae = this.getActionEl();
10986 ae.dom.style.display = '';
10987 ae.dom.style.visibility = 'visible';
10993 onHide : function(){
10994 var ae = this.getActionEl();
10995 ae.dom.style.display = 'none';
10999 * The function that should handle the trigger's click event. This method does nothing by default until overridden
11000 * by an implementing function.
11002 * @param {EventObject} e
11004 onTriggerClick : Roo.emptyFn
11008 * Ext JS Library 1.1.1
11009 * Copyright(c) 2006-2007, Ext JS, LLC.
11011 * Originally Released Under LGPL - original licence link has changed is not relivant.
11014 * <script type="text/javascript">
11019 * @class Roo.data.SortTypes
11021 * Defines the default sorting (casting?) comparison functions used when sorting data.
11023 Roo.data.SortTypes = {
11025 * Default sort that does nothing
11026 * @param {Mixed} s The value being converted
11027 * @return {Mixed} The comparison value
11029 none : function(s){
11034 * The regular expression used to strip tags
11038 stripTagsRE : /<\/?[^>]+>/gi,
11041 * Strips all HTML tags to sort on text only
11042 * @param {Mixed} s The value being converted
11043 * @return {String} The comparison value
11045 asText : function(s){
11046 return String(s).replace(this.stripTagsRE, "");
11050 * Strips all HTML tags to sort on text only - Case insensitive
11051 * @param {Mixed} s The value being converted
11052 * @return {String} The comparison value
11054 asUCText : function(s){
11055 return String(s).toUpperCase().replace(this.stripTagsRE, "");
11059 * Case insensitive string
11060 * @param {Mixed} s The value being converted
11061 * @return {String} The comparison value
11063 asUCString : function(s) {
11064 return String(s).toUpperCase();
11069 * @param {Mixed} s The value being converted
11070 * @return {Number} The comparison value
11072 asDate : function(s) {
11076 if(s instanceof Date){
11077 return s.getTime();
11079 return Date.parse(String(s));
11084 * @param {Mixed} s The value being converted
11085 * @return {Float} The comparison value
11087 asFloat : function(s) {
11088 var val = parseFloat(String(s).replace(/,/g, ""));
11097 * @param {Mixed} s The value being converted
11098 * @return {Number} The comparison value
11100 asInt : function(s) {
11101 var val = parseInt(String(s).replace(/,/g, ""));
11109 * Ext JS Library 1.1.1
11110 * Copyright(c) 2006-2007, Ext JS, LLC.
11112 * Originally Released Under LGPL - original licence link has changed is not relivant.
11115 * <script type="text/javascript">
11119 * @class Roo.data.Record
11120 * Instances of this class encapsulate both record <em>definition</em> information, and record
11121 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
11122 * to access Records cached in an {@link Roo.data.Store} object.<br>
11124 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
11125 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
11128 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
11130 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
11131 * {@link #create}. The parameters are the same.
11132 * @param {Array} data An associative Array of data values keyed by the field name.
11133 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
11134 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
11135 * not specified an integer id is generated.
11137 Roo.data.Record = function(data, id){
11138 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
11143 * Generate a constructor for a specific record layout.
11144 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
11145 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
11146 * Each field definition object may contain the following properties: <ul>
11147 * <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,
11148 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
11149 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
11150 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
11151 * is being used, then this is a string containing the javascript expression to reference the data relative to
11152 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
11153 * to the data item relative to the record element. If the mapping expression is the same as the field name,
11154 * this may be omitted.</p></li>
11155 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
11156 * <ul><li>auto (Default, implies no conversion)</li>
11161 * <li>date</li></ul></p></li>
11162 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
11163 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
11164 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
11165 * by the Reader into an object that will be stored in the Record. It is passed the
11166 * following parameters:<ul>
11167 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
11169 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
11171 * <br>usage:<br><pre><code>
11172 var TopicRecord = Roo.data.Record.create(
11173 {name: 'title', mapping: 'topic_title'},
11174 {name: 'author', mapping: 'username'},
11175 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
11176 {name: 'lastPost', mapping: 'post_time', type: 'date'},
11177 {name: 'lastPoster', mapping: 'user2'},
11178 {name: 'excerpt', mapping: 'post_text'}
11181 var myNewRecord = new TopicRecord({
11182 title: 'Do my job please',
11185 lastPost: new Date(),
11186 lastPoster: 'Animal',
11187 excerpt: 'No way dude!'
11189 myStore.add(myNewRecord);
11194 Roo.data.Record.create = function(o){
11195 var f = function(){
11196 f.superclass.constructor.apply(this, arguments);
11198 Roo.extend(f, Roo.data.Record);
11199 var p = f.prototype;
11200 p.fields = new Roo.util.MixedCollection(false, function(field){
11203 for(var i = 0, len = o.length; i < len; i++){
11204 p.fields.add(new Roo.data.Field(o[i]));
11206 f.getField = function(name){
11207 return p.fields.get(name);
11212 Roo.data.Record.AUTO_ID = 1000;
11213 Roo.data.Record.EDIT = 'edit';
11214 Roo.data.Record.REJECT = 'reject';
11215 Roo.data.Record.COMMIT = 'commit';
11217 Roo.data.Record.prototype = {
11219 * Readonly flag - true if this record has been modified.
11228 join : function(store){
11229 this.store = store;
11233 * Set the named field to the specified value.
11234 * @param {String} name The name of the field to set.
11235 * @param {Object} value The value to set the field to.
11237 set : function(name, value){
11238 if(this.data[name] == value){
11242 if(!this.modified){
11243 this.modified = {};
11245 if(typeof this.modified[name] == 'undefined'){
11246 this.modified[name] = this.data[name];
11248 this.data[name] = value;
11249 if(!this.editing && this.store){
11250 this.store.afterEdit(this);
11255 * Get the value of the named field.
11256 * @param {String} name The name of the field to get the value of.
11257 * @return {Object} The value of the field.
11259 get : function(name){
11260 return this.data[name];
11264 beginEdit : function(){
11265 this.editing = true;
11266 this.modified = {};
11270 cancelEdit : function(){
11271 this.editing = false;
11272 delete this.modified;
11276 endEdit : function(){
11277 this.editing = false;
11278 if(this.dirty && this.store){
11279 this.store.afterEdit(this);
11284 * Usually called by the {@link Roo.data.Store} which owns the Record.
11285 * Rejects all changes made to the Record since either creation, or the last commit operation.
11286 * Modified fields are reverted to their original values.
11288 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11289 * of reject operations.
11291 reject : function(){
11292 var m = this.modified;
11294 if(typeof m[n] != "function"){
11295 this.data[n] = m[n];
11298 this.dirty = false;
11299 delete this.modified;
11300 this.editing = false;
11302 this.store.afterReject(this);
11307 * Usually called by the {@link Roo.data.Store} which owns the Record.
11308 * Commits all changes made to the Record since either creation, or the last commit operation.
11310 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
11311 * of commit operations.
11313 commit : function(){
11314 this.dirty = false;
11315 delete this.modified;
11316 this.editing = false;
11318 this.store.afterCommit(this);
11323 hasError : function(){
11324 return this.error != null;
11328 clearError : function(){
11333 * Creates a copy of this record.
11334 * @param {String} id (optional) A new record id if you don't want to use this record's id
11337 copy : function(newId) {
11338 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
11342 * Ext JS Library 1.1.1
11343 * Copyright(c) 2006-2007, Ext JS, LLC.
11345 * Originally Released Under LGPL - original licence link has changed is not relivant.
11348 * <script type="text/javascript">
11354 * @class Roo.data.Store
11355 * @extends Roo.util.Observable
11356 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
11357 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
11359 * 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
11360 * has no knowledge of the format of the data returned by the Proxy.<br>
11362 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
11363 * instances from the data object. These records are cached and made available through accessor functions.
11365 * Creates a new Store.
11366 * @param {Object} config A config object containing the objects needed for the Store to access data,
11367 * and read the data into Records.
11369 Roo.data.Store = function(config){
11370 this.data = new Roo.util.MixedCollection(false);
11371 this.data.getKey = function(o){
11374 this.baseParams = {};
11376 this.paramNames = {
11381 "multisort" : "_multisort"
11384 if(config && config.data){
11385 this.inlineData = config.data;
11386 delete config.data;
11389 Roo.apply(this, config);
11391 if(this.reader){ // reader passed
11392 this.reader = Roo.factory(this.reader, Roo.data);
11393 this.reader.xmodule = this.xmodule || false;
11394 if(!this.recordType){
11395 this.recordType = this.reader.recordType;
11397 if(this.reader.onMetaChange){
11398 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
11402 if(this.recordType){
11403 this.fields = this.recordType.prototype.fields;
11405 this.modified = [];
11409 * @event datachanged
11410 * Fires when the data cache has changed, and a widget which is using this Store
11411 * as a Record cache should refresh its view.
11412 * @param {Store} this
11414 datachanged : true,
11416 * @event metachange
11417 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
11418 * @param {Store} this
11419 * @param {Object} meta The JSON metadata
11424 * Fires when Records have been added to the Store
11425 * @param {Store} this
11426 * @param {Roo.data.Record[]} records The array of Records added
11427 * @param {Number} index The index at which the record(s) were added
11432 * Fires when a Record has been removed from the Store
11433 * @param {Store} this
11434 * @param {Roo.data.Record} record The Record that was removed
11435 * @param {Number} index The index at which the record was removed
11440 * Fires when a Record has been updated
11441 * @param {Store} this
11442 * @param {Roo.data.Record} record The Record that was updated
11443 * @param {String} operation The update operation being performed. Value may be one of:
11445 Roo.data.Record.EDIT
11446 Roo.data.Record.REJECT
11447 Roo.data.Record.COMMIT
11453 * Fires when the data cache has been cleared.
11454 * @param {Store} this
11458 * @event beforeload
11459 * Fires before a request is made for a new data object. If the beforeload handler returns false
11460 * the load action will be canceled.
11461 * @param {Store} this
11462 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11466 * @event beforeloadadd
11467 * Fires after a new set of Records has been loaded.
11468 * @param {Store} this
11469 * @param {Roo.data.Record[]} records The Records that were loaded
11470 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11472 beforeloadadd : true,
11475 * Fires after a new set of Records has been loaded, before they are added to the store.
11476 * @param {Store} this
11477 * @param {Roo.data.Record[]} records The Records that were loaded
11478 * @param {Object} options The loading options that were specified (see {@link #load} for details)
11479 * @params {Object} return from reader
11483 * @event loadexception
11484 * Fires if an exception occurs in the Proxy during loading.
11485 * Called with the signature of the Proxy's "loadexception" event.
11486 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
11489 * @param {Object} return from JsonData.reader() - success, totalRecords, records
11490 * @param {Object} load options
11491 * @param {Object} jsonData from your request (normally this contains the Exception)
11493 loadexception : true
11497 this.proxy = Roo.factory(this.proxy, Roo.data);
11498 this.proxy.xmodule = this.xmodule || false;
11499 this.relayEvents(this.proxy, ["loadexception"]);
11501 this.sortToggle = {};
11502 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
11504 Roo.data.Store.superclass.constructor.call(this);
11506 if(this.inlineData){
11507 this.loadData(this.inlineData);
11508 delete this.inlineData;
11512 Roo.extend(Roo.data.Store, Roo.util.Observable, {
11514 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
11515 * without a remote query - used by combo/forms at present.
11519 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
11522 * @cfg {Array} data Inline data to be loaded when the store is initialized.
11525 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
11526 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
11529 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
11530 * on any HTTP request
11533 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
11536 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
11540 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
11541 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
11543 remoteSort : false,
11546 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
11547 * loaded or when a record is removed. (defaults to false).
11549 pruneModifiedRecords : false,
11552 lastOptions : null,
11555 * Add Records to the Store and fires the add event.
11556 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11558 add : function(records){
11559 records = [].concat(records);
11560 for(var i = 0, len = records.length; i < len; i++){
11561 records[i].join(this);
11563 var index = this.data.length;
11564 this.data.addAll(records);
11565 this.fireEvent("add", this, records, index);
11569 * Remove a Record from the Store and fires the remove event.
11570 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
11572 remove : function(record){
11573 var index = this.data.indexOf(record);
11574 this.data.removeAt(index);
11576 if(this.pruneModifiedRecords){
11577 this.modified.remove(record);
11579 this.fireEvent("remove", this, record, index);
11583 * Remove all Records from the Store and fires the clear event.
11585 removeAll : function(){
11587 if(this.pruneModifiedRecords){
11588 this.modified = [];
11590 this.fireEvent("clear", this);
11594 * Inserts Records to the Store at the given index and fires the add event.
11595 * @param {Number} index The start index at which to insert the passed Records.
11596 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
11598 insert : function(index, records){
11599 records = [].concat(records);
11600 for(var i = 0, len = records.length; i < len; i++){
11601 this.data.insert(index, records[i]);
11602 records[i].join(this);
11604 this.fireEvent("add", this, records, index);
11608 * Get the index within the cache of the passed Record.
11609 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
11610 * @return {Number} The index of the passed Record. Returns -1 if not found.
11612 indexOf : function(record){
11613 return this.data.indexOf(record);
11617 * Get the index within the cache of the Record with the passed id.
11618 * @param {String} id The id of the Record to find.
11619 * @return {Number} The index of the Record. Returns -1 if not found.
11621 indexOfId : function(id){
11622 return this.data.indexOfKey(id);
11626 * Get the Record with the specified id.
11627 * @param {String} id The id of the Record to find.
11628 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
11630 getById : function(id){
11631 return this.data.key(id);
11635 * Get the Record at the specified index.
11636 * @param {Number} index The index of the Record to find.
11637 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
11639 getAt : function(index){
11640 return this.data.itemAt(index);
11644 * Returns a range of Records between specified indices.
11645 * @param {Number} startIndex (optional) The starting index (defaults to 0)
11646 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
11647 * @return {Roo.data.Record[]} An array of Records
11649 getRange : function(start, end){
11650 return this.data.getRange(start, end);
11654 storeOptions : function(o){
11655 o = Roo.apply({}, o);
11658 this.lastOptions = o;
11662 * Loads the Record cache from the configured Proxy using the configured Reader.
11664 * If using remote paging, then the first load call must specify the <em>start</em>
11665 * and <em>limit</em> properties in the options.params property to establish the initial
11666 * position within the dataset, and the number of Records to cache on each read from the Proxy.
11668 * <strong>It is important to note that for remote data sources, loading is asynchronous,
11669 * and this call will return before the new data has been loaded. Perform any post-processing
11670 * in a callback function, or in a "load" event handler.</strong>
11672 * @param {Object} options An object containing properties which control loading options:<ul>
11673 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
11674 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
11675 * passed the following arguments:<ul>
11676 * <li>r : Roo.data.Record[]</li>
11677 * <li>options: Options object from the load call</li>
11678 * <li>success: Boolean success indicator</li></ul></li>
11679 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
11680 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
11683 load : function(options){
11684 options = options || {};
11685 if(this.fireEvent("beforeload", this, options) !== false){
11686 this.storeOptions(options);
11687 var p = Roo.apply(options.params || {}, this.baseParams);
11688 // if meta was not loaded from remote source.. try requesting it.
11689 if (!this.reader.metaFromRemote) {
11690 p._requestMeta = 1;
11692 if(this.sortInfo && this.remoteSort){
11693 var pn = this.paramNames;
11694 p[pn["sort"]] = this.sortInfo.field;
11695 p[pn["dir"]] = this.sortInfo.direction;
11697 if (this.multiSort) {
11698 var pn = this.paramNames;
11699 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
11702 this.proxy.load(p, this.reader, this.loadRecords, this, options);
11707 * Reloads the Record cache from the configured Proxy using the configured Reader and
11708 * the options from the last load operation performed.
11709 * @param {Object} options (optional) An object containing properties which may override the options
11710 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
11711 * the most recently used options are reused).
11713 reload : function(options){
11714 this.load(Roo.applyIf(options||{}, this.lastOptions));
11718 // Called as a callback by the Reader during a load operation.
11719 loadRecords : function(o, options, success){
11720 if(!o || success === false){
11721 if(success !== false){
11722 this.fireEvent("load", this, [], options, o);
11724 if(options.callback){
11725 options.callback.call(options.scope || this, [], options, false);
11729 // if data returned failure - throw an exception.
11730 if (o.success === false) {
11731 // show a message if no listener is registered.
11732 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
11733 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
11735 // loadmask wil be hooked into this..
11736 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
11739 var r = o.records, t = o.totalRecords || r.length;
11741 this.fireEvent("beforeloadadd", this, r, options, o);
11743 if(!options || options.add !== true){
11744 if(this.pruneModifiedRecords){
11745 this.modified = [];
11747 for(var i = 0, len = r.length; i < len; i++){
11751 this.data = this.snapshot;
11752 delete this.snapshot;
11755 this.data.addAll(r);
11756 this.totalLength = t;
11758 this.fireEvent("datachanged", this);
11760 this.totalLength = Math.max(t, this.data.length+r.length);
11764 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
11766 var e = new Roo.data.Record({});
11768 e.set(this.parent.displayField, this.parent.emptyTitle);
11769 e.set(this.parent.valueField, '');
11774 this.fireEvent("load", this, r, options, o);
11775 if(options.callback){
11776 options.callback.call(options.scope || this, r, options, true);
11782 * Loads data from a passed data block. A Reader which understands the format of the data
11783 * must have been configured in the constructor.
11784 * @param {Object} data The data block from which to read the Records. The format of the data expected
11785 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
11786 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
11788 loadData : function(o, append){
11789 var r = this.reader.readRecords(o);
11790 this.loadRecords(r, {add: append}, true);
11794 * Gets the number of cached records.
11796 * <em>If using paging, this may not be the total size of the dataset. If the data object
11797 * used by the Reader contains the dataset size, then the getTotalCount() function returns
11798 * the data set size</em>
11800 getCount : function(){
11801 return this.data.length || 0;
11805 * Gets the total number of records in the dataset as returned by the server.
11807 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
11808 * the dataset size</em>
11810 getTotalCount : function(){
11811 return this.totalLength || 0;
11815 * Returns the sort state of the Store as an object with two properties:
11817 field {String} The name of the field by which the Records are sorted
11818 direction {String} The sort order, "ASC" or "DESC"
11821 getSortState : function(){
11822 return this.sortInfo;
11826 applySort : function(){
11827 if(this.sortInfo && !this.remoteSort){
11828 var s = this.sortInfo, f = s.field;
11829 var st = this.fields.get(f).sortType;
11830 var fn = function(r1, r2){
11831 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
11832 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
11834 this.data.sort(s.direction, fn);
11835 if(this.snapshot && this.snapshot != this.data){
11836 this.snapshot.sort(s.direction, fn);
11842 * Sets the default sort column and order to be used by the next load operation.
11843 * @param {String} fieldName The name of the field to sort by.
11844 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11846 setDefaultSort : function(field, dir){
11847 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
11851 * Sort the Records.
11852 * If remote sorting is used, the sort is performed on the server, and the cache is
11853 * reloaded. If local sorting is used, the cache is sorted internally.
11854 * @param {String} fieldName The name of the field to sort by.
11855 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
11857 sort : function(fieldName, dir){
11858 var f = this.fields.get(fieldName);
11860 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
11862 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
11863 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
11868 this.sortToggle[f.name] = dir;
11869 this.sortInfo = {field: f.name, direction: dir};
11870 if(!this.remoteSort){
11872 this.fireEvent("datachanged", this);
11874 this.load(this.lastOptions);
11879 * Calls the specified function for each of the Records in the cache.
11880 * @param {Function} fn The function to call. The Record is passed as the first parameter.
11881 * Returning <em>false</em> aborts and exits the iteration.
11882 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
11884 each : function(fn, scope){
11885 this.data.each(fn, scope);
11889 * Gets all records modified since the last commit. Modified records are persisted across load operations
11890 * (e.g., during paging).
11891 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
11893 getModifiedRecords : function(){
11894 return this.modified;
11898 createFilterFn : function(property, value, anyMatch){
11899 if(!value.exec){ // not a regex
11900 value = String(value);
11901 if(value.length == 0){
11904 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
11906 return function(r){
11907 return value.test(r.data[property]);
11912 * Sums the value of <i>property</i> for each record between start and end and returns the result.
11913 * @param {String} property A field on your records
11914 * @param {Number} start The record index to start at (defaults to 0)
11915 * @param {Number} end The last record index to include (defaults to length - 1)
11916 * @return {Number} The sum
11918 sum : function(property, start, end){
11919 var rs = this.data.items, v = 0;
11920 start = start || 0;
11921 end = (end || end === 0) ? end : rs.length-1;
11923 for(var i = start; i <= end; i++){
11924 v += (rs[i].data[property] || 0);
11930 * Filter the records by a specified property.
11931 * @param {String} field A field on your records
11932 * @param {String/RegExp} value Either a string that the field
11933 * should start with or a RegExp to test against the field
11934 * @param {Boolean} anyMatch True to match any part not just the beginning
11936 filter : function(property, value, anyMatch){
11937 var fn = this.createFilterFn(property, value, anyMatch);
11938 return fn ? this.filterBy(fn) : this.clearFilter();
11942 * Filter 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,
11944 * otherwise it is filtered.
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)
11948 filterBy : function(fn, scope){
11949 this.snapshot = this.snapshot || this.data;
11950 this.data = this.queryBy(fn, scope||this);
11951 this.fireEvent("datachanged", this);
11955 * Query the records by a specified property.
11956 * @param {String} field A field on your records
11957 * @param {String/RegExp} value Either a string that the field
11958 * should start with or a RegExp to test against the field
11959 * @param {Boolean} anyMatch True to match any part not just the beginning
11960 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11962 query : function(property, value, anyMatch){
11963 var fn = this.createFilterFn(property, value, anyMatch);
11964 return fn ? this.queryBy(fn) : this.data.clone();
11968 * Query by a function. The specified function will be called with each
11969 * record in this data source. If the function returns true the record is included
11971 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
11972 * @param {Object} scope (optional) The scope of the function (defaults to this)
11973 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
11975 queryBy : function(fn, scope){
11976 var data = this.snapshot || this.data;
11977 return data.filterBy(fn, scope||this);
11981 * Collects unique values for a particular dataIndex from this store.
11982 * @param {String} dataIndex The property to collect
11983 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
11984 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
11985 * @return {Array} An array of the unique values
11987 collect : function(dataIndex, allowNull, bypassFilter){
11988 var d = (bypassFilter === true && this.snapshot) ?
11989 this.snapshot.items : this.data.items;
11990 var v, sv, r = [], l = {};
11991 for(var i = 0, len = d.length; i < len; i++){
11992 v = d[i].data[dataIndex];
11994 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
12003 * Revert to a view of the Record cache with no filtering applied.
12004 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
12006 clearFilter : function(suppressEvent){
12007 if(this.snapshot && this.snapshot != this.data){
12008 this.data = this.snapshot;
12009 delete this.snapshot;
12010 if(suppressEvent !== true){
12011 this.fireEvent("datachanged", this);
12017 afterEdit : function(record){
12018 if(this.modified.indexOf(record) == -1){
12019 this.modified.push(record);
12021 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
12025 afterReject : function(record){
12026 this.modified.remove(record);
12027 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
12031 afterCommit : function(record){
12032 this.modified.remove(record);
12033 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
12037 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
12038 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
12040 commitChanges : function(){
12041 var m = this.modified.slice(0);
12042 this.modified = [];
12043 for(var i = 0, len = m.length; i < len; i++){
12049 * Cancel outstanding changes on all changed records.
12051 rejectChanges : function(){
12052 var m = this.modified.slice(0);
12053 this.modified = [];
12054 for(var i = 0, len = m.length; i < len; i++){
12059 onMetaChange : function(meta, rtype, o){
12060 this.recordType = rtype;
12061 this.fields = rtype.prototype.fields;
12062 delete this.snapshot;
12063 this.sortInfo = meta.sortInfo || this.sortInfo;
12064 this.modified = [];
12065 this.fireEvent('metachange', this, this.reader.meta);
12068 moveIndex : function(data, type)
12070 var index = this.indexOf(data);
12072 var newIndex = index + type;
12076 this.insert(newIndex, data);
12081 * Ext JS Library 1.1.1
12082 * Copyright(c) 2006-2007, Ext JS, LLC.
12084 * Originally Released Under LGPL - original licence link has changed is not relivant.
12087 * <script type="text/javascript">
12091 * @class Roo.data.SimpleStore
12092 * @extends Roo.data.Store
12093 * Small helper class to make creating Stores from Array data easier.
12094 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
12095 * @cfg {Array} fields An array of field definition objects, or field name strings.
12096 * @cfg {Array} data The multi-dimensional array of data
12098 * @param {Object} config
12100 Roo.data.SimpleStore = function(config){
12101 Roo.data.SimpleStore.superclass.constructor.call(this, {
12103 reader: new Roo.data.ArrayReader({
12106 Roo.data.Record.create(config.fields)
12108 proxy : new Roo.data.MemoryProxy(config.data)
12112 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
12114 * Ext JS Library 1.1.1
12115 * Copyright(c) 2006-2007, Ext JS, LLC.
12117 * Originally Released Under LGPL - original licence link has changed is not relivant.
12120 * <script type="text/javascript">
12125 * @extends Roo.data.Store
12126 * @class Roo.data.JsonStore
12127 * Small helper class to make creating Stores for JSON data easier. <br/>
12129 var store = new Roo.data.JsonStore({
12130 url: 'get-images.php',
12132 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
12135 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
12136 * JsonReader and HttpProxy (unless inline data is provided).</b>
12137 * @cfg {Array} fields An array of field definition objects, or field name strings.
12139 * @param {Object} config
12141 Roo.data.JsonStore = function(c){
12142 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
12143 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
12144 reader: new Roo.data.JsonReader(c, c.fields)
12147 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
12149 * Ext JS Library 1.1.1
12150 * Copyright(c) 2006-2007, Ext JS, LLC.
12152 * Originally Released Under LGPL - original licence link has changed is not relivant.
12155 * <script type="text/javascript">
12159 Roo.data.Field = function(config){
12160 if(typeof config == "string"){
12161 config = {name: config};
12163 Roo.apply(this, config);
12166 this.type = "auto";
12169 var st = Roo.data.SortTypes;
12170 // named sortTypes are supported, here we look them up
12171 if(typeof this.sortType == "string"){
12172 this.sortType = st[this.sortType];
12175 // set default sortType for strings and dates
12176 if(!this.sortType){
12179 this.sortType = st.asUCString;
12182 this.sortType = st.asDate;
12185 this.sortType = st.none;
12190 var stripRe = /[\$,%]/g;
12192 // prebuilt conversion function for this field, instead of
12193 // switching every time we're reading a value
12195 var cv, dateFormat = this.dateFormat;
12200 cv = function(v){ return v; };
12203 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
12207 return v !== undefined && v !== null && v !== '' ?
12208 parseInt(String(v).replace(stripRe, ""), 10) : '';
12213 return v !== undefined && v !== null && v !== '' ?
12214 parseFloat(String(v).replace(stripRe, ""), 10) : '';
12219 cv = function(v){ return v === true || v === "true" || v == 1; };
12226 if(v instanceof Date){
12230 if(dateFormat == "timestamp"){
12231 return new Date(v*1000);
12233 return Date.parseDate(v, dateFormat);
12235 var parsed = Date.parse(v);
12236 return parsed ? new Date(parsed) : null;
12245 Roo.data.Field.prototype = {
12253 * Ext JS Library 1.1.1
12254 * Copyright(c) 2006-2007, Ext JS, LLC.
12256 * Originally Released Under LGPL - original licence link has changed is not relivant.
12259 * <script type="text/javascript">
12262 // Base class for reading structured data from a data source. This class is intended to be
12263 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
12266 * @class Roo.data.DataReader
12267 * Base class for reading structured data from a data source. This class is intended to be
12268 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
12271 Roo.data.DataReader = function(meta, recordType){
12275 this.recordType = recordType instanceof Array ?
12276 Roo.data.Record.create(recordType) : recordType;
12279 Roo.data.DataReader.prototype = {
12281 * Create an empty record
12282 * @param {Object} data (optional) - overlay some values
12283 * @return {Roo.data.Record} record created.
12285 newRow : function(d) {
12287 this.recordType.prototype.fields.each(function(c) {
12289 case 'int' : da[c.name] = 0; break;
12290 case 'date' : da[c.name] = new Date(); break;
12291 case 'float' : da[c.name] = 0.0; break;
12292 case 'boolean' : da[c.name] = false; break;
12293 default : da[c.name] = ""; break;
12297 return new this.recordType(Roo.apply(da, d));
12302 * Ext JS Library 1.1.1
12303 * Copyright(c) 2006-2007, Ext JS, LLC.
12305 * Originally Released Under LGPL - original licence link has changed is not relivant.
12308 * <script type="text/javascript">
12312 * @class Roo.data.DataProxy
12313 * @extends Roo.data.Observable
12314 * This class is an abstract base class for implementations which provide retrieval of
12315 * unformatted data objects.<br>
12317 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
12318 * (of the appropriate type which knows how to parse the data object) to provide a block of
12319 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
12321 * Custom implementations must implement the load method as described in
12322 * {@link Roo.data.HttpProxy#load}.
12324 Roo.data.DataProxy = function(){
12327 * @event beforeload
12328 * Fires before a network request is made to retrieve a data object.
12329 * @param {Object} This DataProxy object.
12330 * @param {Object} params The params parameter to the load function.
12335 * Fires before the load method's callback is called.
12336 * @param {Object} This DataProxy object.
12337 * @param {Object} o The data object.
12338 * @param {Object} arg The callback argument object passed to the load function.
12342 * @event loadexception
12343 * Fires if an Exception occurs during data retrieval.
12344 * @param {Object} This DataProxy object.
12345 * @param {Object} o The data object.
12346 * @param {Object} arg The callback argument object passed to the load function.
12347 * @param {Object} e The Exception.
12349 loadexception : true
12351 Roo.data.DataProxy.superclass.constructor.call(this);
12354 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
12357 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
12361 * Ext JS Library 1.1.1
12362 * Copyright(c) 2006-2007, Ext JS, LLC.
12364 * Originally Released Under LGPL - original licence link has changed is not relivant.
12367 * <script type="text/javascript">
12370 * @class Roo.data.MemoryProxy
12371 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
12372 * to the Reader when its load method is called.
12374 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
12376 Roo.data.MemoryProxy = function(data){
12380 Roo.data.MemoryProxy.superclass.constructor.call(this);
12384 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
12387 * Load data from the requested source (in this case an in-memory
12388 * data object passed to the constructor), read the data object into
12389 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12390 * process that block using the passed callback.
12391 * @param {Object} params This parameter is not used by the MemoryProxy class.
12392 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12393 * object into a block of Roo.data.Records.
12394 * @param {Function} callback The function into which to pass the block of Roo.data.records.
12395 * The function must be passed <ul>
12396 * <li>The Record block object</li>
12397 * <li>The "arg" argument from the load function</li>
12398 * <li>A boolean success indicator</li>
12400 * @param {Object} scope The scope in which to call the callback
12401 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12403 load : function(params, reader, callback, scope, arg){
12404 params = params || {};
12407 result = reader.readRecords(params.data ? params.data :this.data);
12409 this.fireEvent("loadexception", this, arg, null, e);
12410 callback.call(scope, null, arg, false);
12413 callback.call(scope, result, arg, true);
12417 update : function(params, records){
12422 * Ext JS Library 1.1.1
12423 * Copyright(c) 2006-2007, Ext JS, LLC.
12425 * Originally Released Under LGPL - original licence link has changed is not relivant.
12428 * <script type="text/javascript">
12431 * @class Roo.data.HttpProxy
12432 * @extends Roo.data.DataProxy
12433 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
12434 * configured to reference a certain URL.<br><br>
12436 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
12437 * from which the running page was served.<br><br>
12439 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
12441 * Be aware that to enable the browser to parse an XML document, the server must set
12442 * the Content-Type header in the HTTP response to "text/xml".
12444 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
12445 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
12446 * will be used to make the request.
12448 Roo.data.HttpProxy = function(conn){
12449 Roo.data.HttpProxy.superclass.constructor.call(this);
12450 // is conn a conn config or a real conn?
12452 this.useAjax = !conn || !conn.events;
12456 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
12457 // thse are take from connection...
12460 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
12463 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
12464 * extra parameters to each request made by this object. (defaults to undefined)
12467 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
12468 * to each request made by this object. (defaults to undefined)
12471 * @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)
12474 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12477 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
12483 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12487 * Return the {@link Roo.data.Connection} object being used by this Proxy.
12488 * @return {Connection} The Connection object. This object may be used to subscribe to events on
12489 * a finer-grained basis than the DataProxy events.
12491 getConnection : function(){
12492 return this.useAjax ? Roo.Ajax : this.conn;
12496 * Load data from the configured {@link Roo.data.Connection}, read the data object into
12497 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
12498 * process that block using the passed callback.
12499 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12500 * for the request to the remote server.
12501 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12502 * object into a block of Roo.data.Records.
12503 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12504 * The function must be passed <ul>
12505 * <li>The Record block object</li>
12506 * <li>The "arg" argument from the load function</li>
12507 * <li>A boolean success indicator</li>
12509 * @param {Object} scope The scope in which to call the callback
12510 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12512 load : function(params, reader, callback, scope, arg){
12513 if(this.fireEvent("beforeload", this, params) !== false){
12515 params : params || {},
12517 callback : callback,
12522 callback : this.loadResponse,
12526 Roo.applyIf(o, this.conn);
12527 if(this.activeRequest){
12528 Roo.Ajax.abort(this.activeRequest);
12530 this.activeRequest = Roo.Ajax.request(o);
12532 this.conn.request(o);
12535 callback.call(scope||this, null, arg, false);
12540 loadResponse : function(o, success, response){
12541 delete this.activeRequest;
12543 this.fireEvent("loadexception", this, o, response);
12544 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12549 result = o.reader.read(response);
12551 this.fireEvent("loadexception", this, o, response, e);
12552 o.request.callback.call(o.request.scope, null, o.request.arg, false);
12556 this.fireEvent("load", this, o, o.request.arg);
12557 o.request.callback.call(o.request.scope, result, o.request.arg, true);
12561 update : function(dataSet){
12566 updateResponse : function(dataSet){
12571 * Ext JS Library 1.1.1
12572 * Copyright(c) 2006-2007, Ext JS, LLC.
12574 * Originally Released Under LGPL - original licence link has changed is not relivant.
12577 * <script type="text/javascript">
12581 * @class Roo.data.ScriptTagProxy
12582 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
12583 * other than the originating domain of the running page.<br><br>
12585 * <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
12586 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
12588 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
12589 * source code that is used as the source inside a <script> tag.<br><br>
12591 * In order for the browser to process the returned data, the server must wrap the data object
12592 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
12593 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
12594 * depending on whether the callback name was passed:
12597 boolean scriptTag = false;
12598 String cb = request.getParameter("callback");
12601 response.setContentType("text/javascript");
12603 response.setContentType("application/x-json");
12605 Writer out = response.getWriter();
12607 out.write(cb + "(");
12609 out.print(dataBlock.toJsonString());
12616 * @param {Object} config A configuration object.
12618 Roo.data.ScriptTagProxy = function(config){
12619 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
12620 Roo.apply(this, config);
12621 this.head = document.getElementsByTagName("head")[0];
12624 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
12626 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
12628 * @cfg {String} url The URL from which to request the data object.
12631 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
12635 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
12636 * the server the name of the callback function set up by the load call to process the returned data object.
12637 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
12638 * javascript output which calls this named function passing the data object as its only parameter.
12640 callbackParam : "callback",
12642 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
12643 * name to the request.
12648 * Load data from the configured URL, read the data object into
12649 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
12650 * process that block using the passed callback.
12651 * @param {Object} params An object containing properties which are to be used as HTTP parameters
12652 * for the request to the remote server.
12653 * @param {Roo.data.DataReader} reader The Reader object which converts the data
12654 * object into a block of Roo.data.Records.
12655 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
12656 * The function must be passed <ul>
12657 * <li>The Record block object</li>
12658 * <li>The "arg" argument from the load function</li>
12659 * <li>A boolean success indicator</li>
12661 * @param {Object} scope The scope in which to call the callback
12662 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
12664 load : function(params, reader, callback, scope, arg){
12665 if(this.fireEvent("beforeload", this, params) !== false){
12667 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
12669 var url = this.url;
12670 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
12672 url += "&_dc=" + (new Date().getTime());
12674 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
12677 cb : "stcCallback"+transId,
12678 scriptId : "stcScript"+transId,
12682 callback : callback,
12688 window[trans.cb] = function(o){
12689 conn.handleResponse(o, trans);
12692 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
12694 if(this.autoAbort !== false){
12698 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
12700 var script = document.createElement("script");
12701 script.setAttribute("src", url);
12702 script.setAttribute("type", "text/javascript");
12703 script.setAttribute("id", trans.scriptId);
12704 this.head.appendChild(script);
12706 this.trans = trans;
12708 callback.call(scope||this, null, arg, false);
12713 isLoading : function(){
12714 return this.trans ? true : false;
12718 * Abort the current server request.
12720 abort : function(){
12721 if(this.isLoading()){
12722 this.destroyTrans(this.trans);
12727 destroyTrans : function(trans, isLoaded){
12728 this.head.removeChild(document.getElementById(trans.scriptId));
12729 clearTimeout(trans.timeoutId);
12731 window[trans.cb] = undefined;
12733 delete window[trans.cb];
12736 // if hasn't been loaded, wait for load to remove it to prevent script error
12737 window[trans.cb] = function(){
12738 window[trans.cb] = undefined;
12740 delete window[trans.cb];
12747 handleResponse : function(o, trans){
12748 this.trans = false;
12749 this.destroyTrans(trans, true);
12752 result = trans.reader.readRecords(o);
12754 this.fireEvent("loadexception", this, o, trans.arg, e);
12755 trans.callback.call(trans.scope||window, null, trans.arg, false);
12758 this.fireEvent("load", this, o, trans.arg);
12759 trans.callback.call(trans.scope||window, result, trans.arg, true);
12763 handleFailure : function(trans){
12764 this.trans = false;
12765 this.destroyTrans(trans, false);
12766 this.fireEvent("loadexception", this, null, trans.arg);
12767 trans.callback.call(trans.scope||window, null, trans.arg, false);
12771 * Ext JS Library 1.1.1
12772 * Copyright(c) 2006-2007, Ext JS, LLC.
12774 * Originally Released Under LGPL - original licence link has changed is not relivant.
12777 * <script type="text/javascript">
12781 * @class Roo.data.JsonReader
12782 * @extends Roo.data.DataReader
12783 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
12784 * based on mappings in a provided Roo.data.Record constructor.
12786 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
12787 * in the reply previously.
12792 var RecordDef = Roo.data.Record.create([
12793 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
12794 {name: 'occupation'} // This field will use "occupation" as the mapping.
12796 var myReader = new Roo.data.JsonReader({
12797 totalProperty: "results", // The property which contains the total dataset size (optional)
12798 root: "rows", // The property which contains an Array of row objects
12799 id: "id" // The property within each row object that provides an ID for the record (optional)
12803 * This would consume a JSON file like this:
12805 { 'results': 2, 'rows': [
12806 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
12807 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
12810 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
12811 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
12812 * paged from the remote server.
12813 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
12814 * @cfg {String} root name of the property which contains the Array of row objects.
12815 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
12816 * @cfg {Array} fields Array of field definition objects
12818 * Create a new JsonReader
12819 * @param {Object} meta Metadata configuration options
12820 * @param {Object} recordType Either an Array of field definition objects,
12821 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
12823 Roo.data.JsonReader = function(meta, recordType){
12826 // set some defaults:
12827 Roo.applyIf(meta, {
12828 totalProperty: 'total',
12829 successProperty : 'success',
12834 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
12836 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
12839 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
12840 * Used by Store query builder to append _requestMeta to params.
12843 metaFromRemote : false,
12845 * This method is only used by a DataProxy which has retrieved data from a remote server.
12846 * @param {Object} response The XHR object which contains the JSON data in its responseText.
12847 * @return {Object} data A data block which is used by an Roo.data.Store object as
12848 * a cache of Roo.data.Records.
12850 read : function(response){
12851 var json = response.responseText;
12853 var o = /* eval:var:o */ eval("("+json+")");
12855 throw {message: "JsonReader.read: Json object not found"};
12861 this.metaFromRemote = true;
12862 this.meta = o.metaData;
12863 this.recordType = Roo.data.Record.create(o.metaData.fields);
12864 this.onMetaChange(this.meta, this.recordType, o);
12866 return this.readRecords(o);
12869 // private function a store will implement
12870 onMetaChange : function(meta, recordType, o){
12877 simpleAccess: function(obj, subsc) {
12884 getJsonAccessor: function(){
12886 return function(expr) {
12888 return(re.test(expr))
12889 ? new Function("obj", "return obj." + expr)
12894 return Roo.emptyFn;
12899 * Create a data block containing Roo.data.Records from an XML document.
12900 * @param {Object} o An object which contains an Array of row objects in the property specified
12901 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
12902 * which contains the total size of the dataset.
12903 * @return {Object} data A data block which is used by an Roo.data.Store object as
12904 * a cache of Roo.data.Records.
12906 readRecords : function(o){
12908 * After any data loads, the raw JSON data is available for further custom processing.
12912 var s = this.meta, Record = this.recordType,
12913 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
12915 // Generate extraction functions for the totalProperty, the root, the id, and for each field
12917 if(s.totalProperty) {
12918 this.getTotal = this.getJsonAccessor(s.totalProperty);
12920 if(s.successProperty) {
12921 this.getSuccess = this.getJsonAccessor(s.successProperty);
12923 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
12925 var g = this.getJsonAccessor(s.id);
12926 this.getId = function(rec) {
12928 return (r === undefined || r === "") ? null : r;
12931 this.getId = function(){return null;};
12934 for(var jj = 0; jj < fl; jj++){
12936 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
12937 this.ef[jj] = this.getJsonAccessor(map);
12941 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
12942 if(s.totalProperty){
12943 var vt = parseInt(this.getTotal(o), 10);
12948 if(s.successProperty){
12949 var vs = this.getSuccess(o);
12950 if(vs === false || vs === 'false'){
12955 for(var i = 0; i < c; i++){
12958 var id = this.getId(n);
12959 for(var j = 0; j < fl; j++){
12961 var v = this.ef[j](n);
12963 Roo.log('missing convert for ' + f.name);
12967 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
12969 var record = new Record(values, id);
12971 records[i] = record;
12977 totalRecords : totalRecords
12982 * Ext JS Library 1.1.1
12983 * Copyright(c) 2006-2007, Ext JS, LLC.
12985 * Originally Released Under LGPL - original licence link has changed is not relivant.
12988 * <script type="text/javascript">
12992 * @class Roo.data.ArrayReader
12993 * @extends Roo.data.DataReader
12994 * Data reader class to create an Array of Roo.data.Record objects from an Array.
12995 * Each element of that Array represents a row of data fields. The
12996 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
12997 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
13001 var RecordDef = Roo.data.Record.create([
13002 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
13003 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
13005 var myReader = new Roo.data.ArrayReader({
13006 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
13010 * This would consume an Array like this:
13012 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
13016 * Create a new JsonReader
13017 * @param {Object} meta Metadata configuration options.
13018 * @param {Object|Array} recordType Either an Array of field definition objects
13020 * @cfg {Array} fields Array of field definition objects
13021 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
13022 * as specified to {@link Roo.data.Record#create},
13023 * or an {@link Roo.data.Record} object
13026 * created using {@link Roo.data.Record#create}.
13028 Roo.data.ArrayReader = function(meta, recordType){
13031 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
13034 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
13036 * Create a data block containing Roo.data.Records from an XML document.
13037 * @param {Object} o An Array of row objects which represents the dataset.
13038 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
13039 * a cache of Roo.data.Records.
13041 readRecords : function(o){
13042 var sid = this.meta ? this.meta.id : null;
13043 var recordType = this.recordType, fields = recordType.prototype.fields;
13046 for(var i = 0; i < root.length; i++){
13049 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
13050 for(var j = 0, jlen = fields.length; j < jlen; j++){
13051 var f = fields.items[j];
13052 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
13053 var v = n[k] !== undefined ? n[k] : f.defaultValue;
13055 values[f.name] = v;
13057 var record = new recordType(values, id);
13059 records[records.length] = record;
13063 totalRecords : records.length
13072 * @class Roo.bootstrap.ComboBox
13073 * @extends Roo.bootstrap.TriggerField
13074 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
13075 * @cfg {Boolean} append (true|false) default false
13076 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
13077 * @cfg {Boolean} tickable ComboBox with tickable selections (true|false), default false
13078 * @cfg {Boolean} triggerList trigger show the list or not (true|false) default true
13079 * @cfg {Boolean} showToggleBtn show toggle button or not (true|false) default true
13080 * @cfg {String} btnPosition set the position of the trigger button (left | right) default right
13081 * @cfg {Boolean} animate default true
13082 * @cfg {Boolean} emptyResultText only for touch device
13083 * @cfg {String} triggerText multiple combobox trigger button text default 'Select'
13084 * @cfg {String} emptyTitle default ''
13086 * Create a new ComboBox.
13087 * @param {Object} config Configuration options
13089 Roo.bootstrap.ComboBox = function(config){
13090 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
13094 * Fires when the dropdown list is expanded
13095 * @param {Roo.bootstrap.ComboBox} combo This combo box
13100 * Fires when the dropdown list is collapsed
13101 * @param {Roo.bootstrap.ComboBox} combo This combo box
13105 * @event beforeselect
13106 * Fires before a list item is selected. Return false to cancel the selection.
13107 * @param {Roo.bootstrap.ComboBox} combo This combo box
13108 * @param {Roo.data.Record} record The data record returned from the underlying store
13109 * @param {Number} index The index of the selected item in the dropdown list
13111 'beforeselect' : true,
13114 * Fires when a list item is selected
13115 * @param {Roo.bootstrap.ComboBox} combo This combo box
13116 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
13117 * @param {Number} index The index of the selected item in the dropdown list
13121 * @event beforequery
13122 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
13123 * The event object passed has these properties:
13124 * @param {Roo.bootstrap.ComboBox} combo This combo box
13125 * @param {String} query The query
13126 * @param {Boolean} forceAll true to force "all" query
13127 * @param {Boolean} cancel true to cancel the query
13128 * @param {Object} e The query event object
13130 'beforequery': true,
13133 * Fires when the 'add' icon is pressed (add a listener to enable add button)
13134 * @param {Roo.bootstrap.ComboBox} combo This combo box
13139 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
13140 * @param {Roo.bootstrap.ComboBox} combo This combo box
13141 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
13146 * Fires when the remove value from the combobox array
13147 * @param {Roo.bootstrap.ComboBox} combo This combo box
13151 * @event afterremove
13152 * Fires when the remove value from the combobox array
13153 * @param {Roo.bootstrap.ComboBox} combo This combo box
13155 'afterremove' : true,
13157 * @event specialfilter
13158 * Fires when specialfilter
13159 * @param {Roo.bootstrap.ComboBox} combo This combo box
13161 'specialfilter' : true,
13164 * Fires when tick the element
13165 * @param {Roo.bootstrap.ComboBox} combo This combo box
13169 * @event touchviewdisplay
13170 * Fires when touch view require special display (default is using displayField)
13171 * @param {Roo.bootstrap.ComboBox} combo This combo box
13172 * @param {Object} cfg set html .
13174 'touchviewdisplay' : true
13179 this.tickItems = [];
13181 this.selectedIndex = -1;
13182 if(this.mode == 'local'){
13183 if(config.queryDelay === undefined){
13184 this.queryDelay = 10;
13186 if(config.minChars === undefined){
13192 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
13195 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
13196 * rendering into an Roo.Editor, defaults to false)
13199 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
13200 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
13203 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
13206 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
13207 * the dropdown list (defaults to undefined, with no header element)
13211 * @cfg {String/Roo.Template} tpl The template to use to render the output
13215 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
13217 listWidth: undefined,
13219 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
13220 * mode = 'remote' or 'text' if mode = 'local')
13222 displayField: undefined,
13225 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
13226 * mode = 'remote' or 'value' if mode = 'local').
13227 * Note: use of a valueField requires the user make a selection
13228 * in order for a value to be mapped.
13230 valueField: undefined,
13232 * @cfg {String} modalTitle The title of the dialog that pops up on mobile views.
13237 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
13238 * field's data value (defaults to the underlying DOM element's name)
13240 hiddenName: undefined,
13242 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
13246 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
13248 selectedClass: 'active',
13251 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
13255 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
13256 * anchor positions (defaults to 'tl-bl')
13258 listAlign: 'tl-bl?',
13260 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
13264 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
13265 * query specified by the allQuery config option (defaults to 'query')
13267 triggerAction: 'query',
13269 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
13270 * (defaults to 4, does not apply if editable = false)
13274 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
13275 * delay (typeAheadDelay) if it matches a known value (defaults to false)
13279 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
13280 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
13284 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
13285 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
13289 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
13290 * when editable = true (defaults to false)
13292 selectOnFocus:false,
13294 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
13296 queryParam: 'query',
13298 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
13299 * when mode = 'remote' (defaults to 'Loading...')
13301 loadingText: 'Loading...',
13303 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
13307 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
13311 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
13312 * traditional select (defaults to true)
13316 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
13320 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
13324 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
13325 * listWidth has a higher value)
13329 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
13330 * allow the user to set arbitrary text into the field (defaults to false)
13332 forceSelection:false,
13334 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
13335 * if typeAhead = true (defaults to 250)
13337 typeAheadDelay : 250,
13339 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
13340 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
13342 valueNotFoundText : undefined,
13344 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
13346 blockFocus : false,
13349 * @cfg {Boolean} disableClear Disable showing of clear button.
13351 disableClear : false,
13353 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
13355 alwaysQuery : false,
13358 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
13363 * @cfg {String} invalidClass DEPRICATED - uses BS4 is-valid now
13365 invalidClass : "has-warning",
13368 * @cfg {String} validClass DEPRICATED - uses BS4 is-valid now
13370 validClass : "has-success",
13373 * @cfg {Boolean} specialFilter (true|false) special filter default false
13375 specialFilter : false,
13378 * @cfg {Boolean} mobileTouchView (true|false) show mobile touch view when using a mobile default true
13380 mobileTouchView : true,
13383 * @cfg {Boolean} useNativeIOS (true|false) render it as classic select for ios, not support dynamic load data (default false)
13385 useNativeIOS : false,
13388 * @cfg {Boolean} mobile_restrict_height (true|false) restrict height for touch view
13390 mobile_restrict_height : false,
13392 ios_options : false,
13404 btnPosition : 'right',
13405 triggerList : true,
13406 showToggleBtn : true,
13408 emptyResultText: 'Empty',
13409 triggerText : 'Select',
13412 // element that contains real text value.. (when hidden is used..)
13414 getAutoCreate : function()
13419 * Render classic select for iso
13422 if(Roo.isIOS && this.useNativeIOS){
13423 cfg = this.getAutoCreateNativeIOS();
13431 if(Roo.isTouch && this.mobileTouchView){
13432 cfg = this.getAutoCreateTouchView();
13439 if(!this.tickable){
13440 cfg = Roo.bootstrap.ComboBox.superclass.getAutoCreate.call(this);
13445 * ComboBox with tickable selections
13448 var align = this.labelAlign || this.parentLabelAlign();
13451 cls : 'form-group roo-combobox-tickable' //input-group
13454 var btn_text_select = '';
13455 var btn_text_done = '';
13456 var btn_text_cancel = '';
13458 if (this.btn_text_show) {
13459 btn_text_select = 'Select';
13460 btn_text_done = 'Done';
13461 btn_text_cancel = 'Cancel';
13466 cls : 'tickable-buttons',
13471 cls : 'btn btn-link btn-edit pull-' + this.btnPosition,
13472 //html : this.triggerText
13473 html: btn_text_select
13479 cls : 'btn btn-link btn-ok pull-' + this.btnPosition,
13481 html: btn_text_done
13487 cls : 'btn btn-link btn-cancel pull-' + this.btnPosition,
13489 html: btn_text_cancel
13495 buttons.cn.unshift({
13497 cls: 'roo-select2-search-field-input'
13503 Roo.each(buttons.cn, function(c){
13505 c.cls += ' btn-' + _this.size;
13508 if (_this.disabled) {
13515 style : 'display: contents',
13520 cls: 'form-hidden-field'
13524 cls: 'roo-select2-choices',
13528 cls: 'roo-select2-search-field',
13539 cls: 'roo-select2-container input-group roo-select2-container-multi',
13545 // cls: 'typeahead typeahead-long dropdown-menu',
13546 // style: 'display:none; max-height:' + this.maxHeight + 'px;'
13551 if(this.hasFeedback && !this.allowBlank){
13555 cls: 'glyphicon form-control-feedback'
13558 combobox.cn.push(feedback);
13563 cls : 'roo-required-indicator ' + (this.indicatorpos == 'right' ? 'right' : 'left') +'-indicator text-danger fa fa-lg fa-star',
13564 tooltip : 'This field is required'
13566 if (Roo.bootstrap.version == 4) {
13569 style : 'display:none'
13572 if (align ==='left' && this.fieldLabel.length) {
13574 cfg.cls += ' roo-form-group-label-left' + (Roo.bootstrap.version == 4 ? ' row' : '');
13581 cls : 'control-label col-form-label',
13582 html : this.fieldLabel
13594 var labelCfg = cfg.cn[1];
13595 var contentCfg = cfg.cn[2];
13598 if(this.indicatorpos == 'right'){
13604 cls : 'control-label col-form-label',
13608 html : this.fieldLabel
13624 labelCfg = cfg.cn[0];
13625 contentCfg = cfg.cn[1];
13629 if(this.labelWidth > 12){
13630 labelCfg.style = "width: " + this.labelWidth + 'px';
13633 if(this.labelWidth < 13 && this.labelmd == 0){
13634 this.labelmd = this.labelWidth;
13637 if(this.labellg > 0){
13638 labelCfg.cls += ' col-lg-' + this.labellg;
13639 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
13642 if(this.labelmd > 0){
13643 labelCfg.cls += ' col-md-' + this.labelmd;
13644 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
13647 if(this.labelsm > 0){
13648 labelCfg.cls += ' col-sm-' + this.labelsm;
13649 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
13652 if(this.labelxs > 0){
13653 labelCfg.cls += ' col-xs-' + this.labelxs;
13654 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
13658 } else if ( this.fieldLabel.length) {
13659 // Roo.log(" label");
13664 //cls : 'input-group-addon',
13665 html : this.fieldLabel
13670 if(this.indicatorpos == 'right'){
13674 //cls : 'input-group-addon',
13675 html : this.fieldLabel
13685 // Roo.log(" no label && no align");
13692 ['xs','sm','md','lg'].map(function(size){
13693 if (settings[size]) {
13694 cfg.cls += ' col-' + size + '-' + settings[size];
13702 _initEventsCalled : false,
13705 initEvents: function()
13707 if (this._initEventsCalled) { // as we call render... prevent looping...
13710 this._initEventsCalled = true;
13713 throw "can not find store for combo";
13716 this.indicator = this.indicatorEl();
13718 this.store = Roo.factory(this.store, Roo.data);
13719 this.store.parent = this;
13721 // if we are building from html. then this element is so complex, that we can not really
13722 // use the rendered HTML.
13723 // so we have to trash and replace the previous code.
13724 if (Roo.XComponent.build_from_html) {
13725 // remove this element....
13726 var e = this.el.dom, k=0;
13727 while (e ) { e = e.previousSibling; ++k;}
13732 this.rendered = false;
13734 this.render(this.parent().getChildContainer(true), k);
13737 if(Roo.isIOS && this.useNativeIOS){
13738 this.initIOSView();
13746 if(Roo.isTouch && this.mobileTouchView){
13747 this.initTouchView();
13752 this.initTickableEvents();
13756 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
13758 if(this.hiddenName){
13760 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13762 this.hiddenField.dom.value =
13763 this.hiddenValue !== undefined ? this.hiddenValue :
13764 this.value !== undefined ? this.value : '';
13766 // prevent input submission
13767 this.el.dom.removeAttribute('name');
13768 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13773 // this.el.dom.setAttribute('autocomplete', 'off');
13776 var cls = 'x-combo-list';
13778 //this.list = new Roo.Layer({
13779 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
13785 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
13786 _this.list.setWidth(lw);
13789 this.list.on('mouseover', this.onViewOver, this);
13790 this.list.on('mousemove', this.onViewMove, this);
13791 this.list.on('scroll', this.onViewScroll, this);
13794 this.list.swallowEvent('mousewheel');
13795 this.assetHeight = 0;
13798 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
13799 this.assetHeight += this.header.getHeight();
13802 this.innerList = this.list.createChild({cls:cls+'-inner'});
13803 this.innerList.on('mouseover', this.onViewOver, this);
13804 this.innerList.on('mousemove', this.onViewMove, this);
13805 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
13807 if(this.allowBlank && !this.pageSize && !this.disableClear){
13808 this.footer = this.list.createChild({cls:cls+'-ft'});
13809 this.pageTb = new Roo.Toolbar(this.footer);
13813 this.footer = this.list.createChild({cls:cls+'-ft'});
13814 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
13815 {pageSize: this.pageSize});
13819 if (this.pageTb && this.allowBlank && !this.disableClear) {
13821 this.pageTb.add(new Roo.Toolbar.Fill(), {
13822 cls: 'x-btn-icon x-btn-clear',
13824 handler: function()
13827 _this.clearValue();
13828 _this.onSelect(false, -1);
13833 this.assetHeight += this.footer.getHeight();
13838 this.tpl = Roo.bootstrap.version == 4 ?
13839 '<a class="dropdown-item" href="#">{' + this.displayField + '}</a>' : // 4 does not need <li> and it get's really confisued.
13840 '<li><a class="dropdown-item" href="#">{' + this.displayField + '}</a></li>';
13843 this.view = new Roo.View(this.list, this.tpl, {
13844 singleSelect:true, store: this.store, selectedClass: this.selectedClass
13846 //this.view.wrapEl.setDisplayed(false);
13847 this.view.on('click', this.onViewClick, this);
13850 this.store.on('beforeload', this.onBeforeLoad, this);
13851 this.store.on('load', this.onLoad, this);
13852 this.store.on('loadexception', this.onLoadException, this);
13854 if(this.resizable){
13855 this.resizer = new Roo.Resizable(this.list, {
13856 pinned:true, handles:'se'
13858 this.resizer.on('resize', function(r, w, h){
13859 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
13860 this.listWidth = w;
13861 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
13862 this.restrictHeight();
13864 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
13867 if(!this.editable){
13868 this.editable = true;
13869 this.setEditable(false);
13874 if (typeof(this.events.add.listeners) != 'undefined') {
13876 this.addicon = this.wrap.createChild(
13877 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
13879 this.addicon.on('click', function(e) {
13880 this.fireEvent('add', this);
13883 if (typeof(this.events.edit.listeners) != 'undefined') {
13885 this.editicon = this.wrap.createChild(
13886 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
13887 if (this.addicon) {
13888 this.editicon.setStyle('margin-left', '40px');
13890 this.editicon.on('click', function(e) {
13892 // we fire even if inothing is selected..
13893 this.fireEvent('edit', this, this.lastData );
13899 this.keyNav = new Roo.KeyNav(this.inputEl(), {
13900 "up" : function(e){
13901 this.inKeyMode = true;
13905 "down" : function(e){
13906 if(!this.isExpanded()){
13907 this.onTriggerClick();
13909 this.inKeyMode = true;
13914 "enter" : function(e){
13915 // this.onViewClick();
13919 if(this.fireEvent("specialkey", this, e)){
13920 this.onViewClick(false);
13926 "esc" : function(e){
13930 "tab" : function(e){
13933 if(this.fireEvent("specialkey", this, e)){
13934 this.onViewClick(false);
13942 doRelay : function(foo, bar, hname){
13943 if(hname == 'down' || this.scope.isExpanded()){
13944 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
13953 this.queryDelay = Math.max(this.queryDelay || 10,
13954 this.mode == 'local' ? 10 : 250);
13957 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
13959 if(this.typeAhead){
13960 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
13962 if(this.editable !== false){
13963 this.inputEl().on("keyup", this.onKeyUp, this);
13965 if(this.forceSelection){
13966 this.inputEl().on('blur', this.doForce, this);
13970 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13971 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13975 initTickableEvents: function()
13979 if(this.hiddenName){
13981 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
13983 this.hiddenField.dom.value =
13984 this.hiddenValue !== undefined ? this.hiddenValue :
13985 this.value !== undefined ? this.value : '';
13987 // prevent input submission
13988 this.el.dom.removeAttribute('name');
13989 this.hiddenField.dom.setAttribute('name', this.hiddenName);
13994 // this.list = this.el.select('ul.dropdown-menu',true).first();
13996 this.choices = this.el.select('ul.roo-select2-choices', true).first();
13997 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
13998 if(this.triggerList){
13999 this.searchField.on("click", this.onSearchFieldClick, this, {preventDefault:true});
14002 this.trigger = this.el.select('.tickable-buttons > .btn-edit', true).first();
14003 this.trigger.on("click", this.onTickableTriggerClick, this, {preventDefault:true});
14005 this.okBtn = this.el.select('.tickable-buttons > .btn-ok', true).first();
14006 this.cancelBtn = this.el.select('.tickable-buttons > .btn-cancel', true).first();
14008 this.okBtn.on('click', this.onTickableFooterButtonClick, this, this.okBtn);
14009 this.cancelBtn.on('click', this.onTickableFooterButtonClick, this, this.cancelBtn);
14011 this.trigger.setVisibilityMode(Roo.Element.DISPLAY);
14012 this.okBtn.setVisibilityMode(Roo.Element.DISPLAY);
14013 this.cancelBtn.setVisibilityMode(Roo.Element.DISPLAY);
14016 this.cancelBtn.hide();
14021 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
14022 _this.list.setWidth(lw);
14025 this.list.on('mouseover', this.onViewOver, this);
14026 this.list.on('mousemove', this.onViewMove, this);
14028 this.list.on('scroll', this.onViewScroll, this);
14031 this.tpl = '<li class="roo-select2-result"><div class="checkbox"><input id="{roo-id}"' +
14032 'type="checkbox" {roo-data-checked}><label for="{roo-id}"><b>{' + this.displayField + '}</b></label></div></li>';
14035 this.view = new Roo.View(this.list, this.tpl, {
14040 selectedClass: this.selectedClass
14043 //this.view.wrapEl.setDisplayed(false);
14044 this.view.on('click', this.onViewClick, this);
14048 this.store.on('beforeload', this.onBeforeLoad, this);
14049 this.store.on('load', this.onLoad, this);
14050 this.store.on('loadexception', this.onLoadException, this);
14053 this.keyNav = new Roo.KeyNav(this.tickableInputEl(), {
14054 "up" : function(e){
14055 this.inKeyMode = true;
14059 "down" : function(e){
14060 this.inKeyMode = true;
14064 "enter" : function(e){
14065 if(this.fireEvent("specialkey", this, e)){
14066 this.onViewClick(false);
14072 "esc" : function(e){
14073 this.onTickableFooterButtonClick(e, false, false);
14076 "tab" : function(e){
14077 this.fireEvent("specialkey", this, e);
14079 this.onTickableFooterButtonClick(e, false, false);
14086 doRelay : function(e, fn, key){
14087 if(this.scope.isExpanded()){
14088 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
14097 this.queryDelay = Math.max(this.queryDelay || 10,
14098 this.mode == 'local' ? 10 : 250);
14101 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
14103 if(this.typeAhead){
14104 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
14107 if(this.editable !== false){
14108 this.tickableInputEl().on("keyup", this.onKeyUp, this);
14111 this.indicator = this.indicatorEl();
14113 if(this.indicator){
14114 this.indicator.setVisibilityMode(Roo.Element.DISPLAY);
14115 this.indicator.hide();
14120 onDestroy : function(){
14122 this.view.setStore(null);
14123 this.view.el.removeAllListeners();
14124 this.view.el.remove();
14125 this.view.purgeListeners();
14128 this.list.dom.innerHTML = '';
14132 this.store.un('beforeload', this.onBeforeLoad, this);
14133 this.store.un('load', this.onLoad, this);
14134 this.store.un('loadexception', this.onLoadException, this);
14136 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
14140 fireKey : function(e){
14141 if(e.isNavKeyPress() && !this.list.isVisible()){
14142 this.fireEvent("specialkey", this, e);
14147 onResize: function(w, h){
14148 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
14150 // if(typeof w != 'number'){
14151 // // we do not handle it!?!?
14154 // var tw = this.trigger.getWidth();
14155 // // tw += this.addicon ? this.addicon.getWidth() : 0;
14156 // // tw += this.editicon ? this.editicon.getWidth() : 0;
14158 // this.inputEl().setWidth( this.adjustWidth('input', x));
14160 // //this.trigger.setStyle('left', x+'px');
14162 // if(this.list && this.listWidth === undefined){
14163 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
14164 // this.list.setWidth(lw);
14165 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
14173 * Allow or prevent the user from directly editing the field text. If false is passed,
14174 * the user will only be able to select from the items defined in the dropdown list. This method
14175 * is the runtime equivalent of setting the 'editable' config option at config time.
14176 * @param {Boolean} value True to allow the user to directly edit the field text
14178 setEditable : function(value){
14179 if(value == this.editable){
14182 this.editable = value;
14184 this.inputEl().dom.setAttribute('readOnly', true);
14185 this.inputEl().on('mousedown', this.onTriggerClick, this);
14186 this.inputEl().addClass('x-combo-noedit');
14188 this.inputEl().dom.setAttribute('readOnly', false);
14189 this.inputEl().un('mousedown', this.onTriggerClick, this);
14190 this.inputEl().removeClass('x-combo-noedit');
14196 onBeforeLoad : function(combo,opts){
14197 if(!this.hasFocus){
14201 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
14203 this.restrictHeight();
14204 this.selectedIndex = -1;
14208 onLoad : function(){
14210 this.hasQuery = false;
14212 if(!this.hasFocus){
14216 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14217 this.loading.hide();
14220 if(this.store.getCount() > 0){
14223 this.restrictHeight();
14224 if(this.lastQuery == this.allQuery){
14225 if(this.editable && !this.tickable){
14226 this.inputEl().dom.select();
14230 !this.selectByValue(this.value, true) &&
14233 !this.store.lastOptions ||
14234 typeof(this.store.lastOptions.add) == 'undefined' ||
14235 this.store.lastOptions.add != true
14238 this.select(0, true);
14241 if(this.autoFocus){
14244 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
14245 this.taTask.delay(this.typeAheadDelay);
14249 this.onEmptyResults();
14255 onLoadException : function()
14257 this.hasQuery = false;
14259 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
14260 this.loading.hide();
14263 if(this.tickable && this.editable){
14268 // only causes errors at present
14269 //Roo.log(this.store.reader.jsonData);
14270 //if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
14272 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
14278 onTypeAhead : function(){
14279 if(this.store.getCount() > 0){
14280 var r = this.store.getAt(0);
14281 var newValue = r.data[this.displayField];
14282 var len = newValue.length;
14283 var selStart = this.getRawValue().length;
14285 if(selStart != len){
14286 this.setRawValue(newValue);
14287 this.selectText(selStart, newValue.length);
14293 onSelect : function(record, index){
14295 if(this.fireEvent('beforeselect', this, record, index) !== false){
14297 this.setFromData(index > -1 ? record.data : false);
14300 this.fireEvent('select', this, record, index);
14305 * Returns the currently selected field value or empty string if no value is set.
14306 * @return {String} value The selected value
14308 getValue : function()
14310 if(Roo.isIOS && this.useNativeIOS){
14311 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.valueField];
14315 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
14318 if(this.valueField){
14319 return typeof this.value != 'undefined' ? this.value : '';
14321 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
14325 getRawValue : function()
14327 if(Roo.isIOS && this.useNativeIOS){
14328 return this.ios_options[this.inputEl().dom.selectedIndex].data[this.displayField];
14331 var v = this.inputEl().getValue();
14337 * Clears any text/value currently set in the field
14339 clearValue : function(){
14341 if(this.hiddenField){
14342 this.hiddenField.dom.value = '';
14345 this.setRawValue('');
14346 this.lastSelectionText = '';
14347 this.lastData = false;
14349 var close = this.closeTriggerEl();
14360 * Sets the specified value into the field. If the value finds a match, the corresponding record text
14361 * will be displayed in the field. If the value does not match the data value of an existing item,
14362 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
14363 * Otherwise the field will be blank (although the value will still be set).
14364 * @param {String} value The value to match
14366 setValue : function(v)
14368 if(Roo.isIOS && this.useNativeIOS){
14369 this.setIOSValue(v);
14379 if(this.valueField){
14380 var r = this.findRecord(this.valueField, v);
14382 text = r.data[this.displayField];
14383 }else if(this.valueNotFoundText !== undefined){
14384 text = this.valueNotFoundText;
14387 this.lastSelectionText = text;
14388 if(this.hiddenField){
14389 this.hiddenField.dom.value = v;
14391 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
14394 var close = this.closeTriggerEl();
14397 (v && (v.length || v * 1 > 0)) ? close.show() : close.hide();
14403 * @property {Object} the last set data for the element
14408 * Sets the value of the field based on a object which is related to the record format for the store.
14409 * @param {Object} value the value to set as. or false on reset?
14411 setFromData : function(o){
14418 var dv = ''; // display value
14419 var vv = ''; // value value..
14421 if (this.displayField) {
14422 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
14424 // this is an error condition!!!
14425 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
14428 if(this.valueField){
14429 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
14432 var close = this.closeTriggerEl();
14435 if(dv.length || vv * 1 > 0){
14437 this.blockFocus=true;
14443 if(this.hiddenField){
14444 this.hiddenField.dom.value = vv;
14446 this.lastSelectionText = dv;
14447 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14451 // no hidden field.. - we store the value in 'value', but still display
14452 // display field!!!!
14453 this.lastSelectionText = dv;
14454 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
14461 reset : function(){
14462 // overridden so that last data is reset..
14469 this.setValue(this.originalValue);
14470 //this.clearInvalid();
14471 this.lastData = false;
14473 this.view.clearSelections();
14479 findRecord : function(prop, value){
14481 if(this.store.getCount() > 0){
14482 this.store.each(function(r){
14483 if(r.data[prop] == value){
14493 getName: function()
14495 // returns hidden if it's set..
14496 if (!this.rendered) {return ''};
14497 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
14501 onViewMove : function(e, t){
14502 this.inKeyMode = false;
14506 onViewOver : function(e, t){
14507 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
14510 var item = this.view.findItemFromChild(t);
14513 var index = this.view.indexOf(item);
14514 this.select(index, false);
14519 onViewClick : function(view, doFocus, el, e)
14521 var index = this.view.getSelectedIndexes()[0];
14523 var r = this.store.getAt(index);
14527 if(typeof(e) != 'undefined' && e.getTarget().nodeName.toLowerCase() != 'input'){
14534 Roo.each(this.tickItems, function(v,k){
14536 if(typeof(v) != 'undefined' && v[_this.valueField] == r.data[_this.valueField]){
14538 _this.tickItems.splice(k, 1);
14540 if(typeof(e) == 'undefined' && view == false){
14541 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = false;
14553 if(this.fireEvent('tick', this, r, index, Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked) !== false){
14554 this.tickItems.push(r.data);
14557 if(typeof(e) == 'undefined' && view == false){
14558 Roo.get(_this.view.getNodes(index, index)[0]).select('input', true).first().dom.checked = true;
14565 this.onSelect(r, index);
14567 if(doFocus !== false && !this.blockFocus){
14568 this.inputEl().focus();
14573 restrictHeight : function(){
14574 //this.innerList.dom.style.height = '';
14575 //var inner = this.innerList.dom;
14576 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
14577 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
14578 //this.list.beginUpdate();
14579 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
14580 this.list.alignTo(this.inputEl(), this.listAlign);
14581 this.list.alignTo(this.inputEl(), this.listAlign);
14582 //this.list.endUpdate();
14586 onEmptyResults : function(){
14588 if(this.tickable && this.editable){
14589 this.hasFocus = false;
14590 this.restrictHeight();
14598 * Returns true if the dropdown list is expanded, else false.
14600 isExpanded : function(){
14601 return this.list.isVisible();
14605 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
14606 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14607 * @param {String} value The data value of the item to select
14608 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14609 * selected item if it is not currently in view (defaults to true)
14610 * @return {Boolean} True if the value matched an item in the list, else false
14612 selectByValue : function(v, scrollIntoView){
14613 if(v !== undefined && v !== null){
14614 var r = this.findRecord(this.valueField || this.displayField, v);
14616 this.select(this.store.indexOf(r), scrollIntoView);
14624 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
14625 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
14626 * @param {Number} index The zero-based index of the list item to select
14627 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
14628 * selected item if it is not currently in view (defaults to true)
14630 select : function(index, scrollIntoView){
14631 this.selectedIndex = index;
14632 this.view.select(index);
14633 if(scrollIntoView !== false){
14634 var el = this.view.getNode(index);
14636 * el && !this.multiple && !this.tickable // not sure why we disable multiple before..
14639 this.list.scrollChildIntoView(el, false);
14645 selectNext : function(){
14646 var ct = this.store.getCount();
14648 if(this.selectedIndex == -1){
14650 }else if(this.selectedIndex < ct-1){
14651 this.select(this.selectedIndex+1);
14657 selectPrev : function(){
14658 var ct = this.store.getCount();
14660 if(this.selectedIndex == -1){
14662 }else if(this.selectedIndex != 0){
14663 this.select(this.selectedIndex-1);
14669 onKeyUp : function(e){
14670 if(this.editable !== false && !e.isSpecialKey()){
14671 this.lastKey = e.getKey();
14672 this.dqTask.delay(this.queryDelay);
14677 validateBlur : function(){
14678 return !this.list || !this.list.isVisible();
14682 initQuery : function(){
14684 var v = this.getRawValue();
14686 if(this.tickable && this.editable){
14687 v = this.tickableInputEl().getValue();
14694 doForce : function(){
14695 if(this.inputEl().dom.value.length > 0){
14696 this.inputEl().dom.value =
14697 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
14703 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
14704 * query allowing the query action to be canceled if needed.
14705 * @param {String} query The SQL query to execute
14706 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
14707 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
14708 * saved in the current store (defaults to false)
14710 doQuery : function(q, forceAll){
14712 if(q === undefined || q === null){
14717 forceAll: forceAll,
14721 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
14726 forceAll = qe.forceAll;
14727 if(forceAll === true || (q.length >= this.minChars)){
14729 this.hasQuery = true;
14731 if(this.lastQuery != q || this.alwaysQuery){
14732 this.lastQuery = q;
14733 if(this.mode == 'local'){
14734 this.selectedIndex = -1;
14736 this.store.clearFilter();
14739 if(this.specialFilter){
14740 this.fireEvent('specialfilter', this);
14745 this.store.filter(this.displayField, q);
14748 this.store.fireEvent("datachanged", this.store);
14755 this.store.baseParams[this.queryParam] = q;
14757 var options = {params : this.getParams(q)};
14760 options.add = true;
14761 options.params.start = this.page * this.pageSize;
14764 this.store.load(options);
14767 * this code will make the page width larger, at the beginning, the list not align correctly,
14768 * we should expand the list on onLoad
14769 * so command out it
14774 this.selectedIndex = -1;
14779 this.loadNext = false;
14783 getParams : function(q){
14785 //p[this.queryParam] = q;
14789 p.limit = this.pageSize;
14795 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
14797 collapse : function(){
14798 if(!this.isExpanded()){
14804 this.hasFocus = false;
14808 this.cancelBtn.hide();
14809 this.trigger.show();
14812 this.tickableInputEl().dom.value = '';
14813 this.tickableInputEl().blur();
14818 Roo.get(document).un('mousedown', this.collapseIf, this);
14819 Roo.get(document).un('mousewheel', this.collapseIf, this);
14820 if (!this.editable) {
14821 Roo.get(document).un('keydown', this.listKeyPress, this);
14823 this.fireEvent('collapse', this);
14829 collapseIf : function(e){
14830 var in_combo = e.within(this.el);
14831 var in_list = e.within(this.list);
14832 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
14834 if (in_combo || in_list || is_list) {
14835 //e.stopPropagation();
14840 this.onTickableFooterButtonClick(e, false, false);
14848 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
14850 expand : function(){
14852 if(this.isExpanded() || !this.hasFocus){
14856 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
14857 this.list.setWidth(lw);
14863 this.restrictHeight();
14867 this.tickItems = Roo.apply([], this.item);
14870 this.cancelBtn.show();
14871 this.trigger.hide();
14874 this.tickableInputEl().focus();
14879 Roo.get(document).on('mousedown', this.collapseIf, this);
14880 Roo.get(document).on('mousewheel', this.collapseIf, this);
14881 if (!this.editable) {
14882 Roo.get(document).on('keydown', this.listKeyPress, this);
14885 this.fireEvent('expand', this);
14889 // Implements the default empty TriggerField.onTriggerClick function
14890 onTriggerClick : function(e)
14892 Roo.log('trigger click');
14894 if(this.disabled || !this.triggerList){
14899 this.loadNext = false;
14901 if(this.isExpanded()){
14903 if (!this.blockFocus) {
14904 this.inputEl().focus();
14908 this.hasFocus = true;
14909 if(this.triggerAction == 'all') {
14910 this.doQuery(this.allQuery, true);
14912 this.doQuery(this.getRawValue());
14914 if (!this.blockFocus) {
14915 this.inputEl().focus();
14920 onTickableTriggerClick : function(e)
14927 this.loadNext = false;
14928 this.hasFocus = true;
14930 if(this.triggerAction == 'all') {
14931 this.doQuery(this.allQuery, true);
14933 this.doQuery(this.getRawValue());
14937 onSearchFieldClick : function(e)
14939 if(this.hasFocus && !this.disabled && e.getTarget().nodeName.toLowerCase() != 'button'){
14940 this.onTickableFooterButtonClick(e, false, false);
14944 if(this.hasFocus || this.disabled || e.getTarget().nodeName.toLowerCase() == 'button'){
14949 this.loadNext = false;
14950 this.hasFocus = true;
14952 if(this.triggerAction == 'all') {
14953 this.doQuery(this.allQuery, true);
14955 this.doQuery(this.getRawValue());
14959 listKeyPress : function(e)
14961 //Roo.log('listkeypress');
14962 // scroll to first matching element based on key pres..
14963 if (e.isSpecialKey()) {
14966 var k = String.fromCharCode(e.getKey()).toUpperCase();
14969 var csel = this.view.getSelectedNodes();
14970 var cselitem = false;
14972 var ix = this.view.indexOf(csel[0]);
14973 cselitem = this.store.getAt(ix);
14974 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
14980 this.store.each(function(v) {
14982 // start at existing selection.
14983 if (cselitem.id == v.id) {
14989 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
14990 match = this.store.indexOf(v);
14996 if (match === false) {
14997 return true; // no more action?
15000 this.view.select(match);
15001 var sn = Roo.get(this.view.getSelectedNodes()[0]);
15002 sn.scrollIntoView(sn.dom.parentNode, false);
15005 onViewScroll : function(e, t){
15007 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){
15011 this.hasQuery = true;
15013 this.loading = this.list.select('.loading', true).first();
15015 if(this.loading === null){
15016 this.list.createChild({
15018 cls: 'loading roo-select2-more-results roo-select2-active',
15019 html: 'Loading more results...'
15022 this.loading = this.list.select('.loading', true).first();
15024 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
15026 this.loading.hide();
15029 this.loading.show();
15034 this.loadNext = true;
15036 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
15041 addItem : function(o)
15043 var dv = ''; // display value
15045 if (this.displayField) {
15046 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
15048 // this is an error condition!!!
15049 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
15056 var choice = this.choices.createChild({
15058 cls: 'roo-select2-search-choice',
15067 cls: 'roo-select2-search-choice-close fa fa-times',
15072 }, this.searchField);
15074 var close = choice.select('a.roo-select2-search-choice-close', true).first();
15076 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
15084 this.inputEl().dom.value = '';
15089 onRemoveItem : function(e, _self, o)
15091 e.preventDefault();
15093 this.lastItem = Roo.apply([], this.item);
15095 var index = this.item.indexOf(o.data) * 1;
15098 Roo.log('not this item?!');
15102 this.item.splice(index, 1);
15107 this.fireEvent('remove', this, e);
15113 syncValue : function()
15115 if(!this.item.length){
15122 Roo.each(this.item, function(i){
15123 if(_this.valueField){
15124 value.push(i[_this.valueField]);
15131 this.value = value.join(',');
15133 if(this.hiddenField){
15134 this.hiddenField.dom.value = this.value;
15137 this.store.fireEvent("datachanged", this.store);
15142 clearItem : function()
15144 if(!this.multiple){
15150 Roo.each(this.choices.select('>li.roo-select2-search-choice', true).elements, function(c){
15158 if(this.tickable && !Roo.isTouch){
15159 this.view.refresh();
15163 inputEl: function ()
15165 if(Roo.isIOS && this.useNativeIOS){
15166 return this.el.select('select.roo-ios-select', true).first();
15169 if(Roo.isTouch && this.mobileTouchView){
15170 return this.el.select('input.form-control',true).first();
15174 return this.searchField;
15177 return this.el.select('input.form-control',true).first();
15180 onTickableFooterButtonClick : function(e, btn, el)
15182 e.preventDefault();
15184 this.lastItem = Roo.apply([], this.item);
15186 if(btn && btn.name == 'cancel'){
15187 this.tickItems = Roo.apply([], this.item);
15196 Roo.each(this.tickItems, function(o){
15204 validate : function()
15206 if(this.getVisibilityEl().hasClass('hidden')){
15210 var v = this.getRawValue();
15213 v = this.getValue();
15216 if(this.disabled || this.allowBlank || v.length){
15221 this.markInvalid();
15225 tickableInputEl : function()
15227 if(!this.tickable || !this.editable){
15228 return this.inputEl();
15231 return this.inputEl().select('.roo-select2-search-field-input', true).first();
15235 getAutoCreateTouchView : function()
15240 cls: 'form-group' //input-group
15246 type : this.inputType,
15247 cls : 'form-control x-combo-noedit',
15248 autocomplete: 'new-password',
15249 placeholder : this.placeholder || '',
15254 input.name = this.name;
15258 input.cls += ' input-' + this.size;
15261 if (this.disabled) {
15262 input.disabled = true;
15273 inputblock.cls += ' input-group';
15275 inputblock.cn.unshift({
15277 cls : 'input-group-addon input-group-prepend input-group-text',
15282 if(this.removable && !this.multiple){
15283 inputblock.cls += ' roo-removable';
15285 inputblock.cn.push({
15288 cls : 'roo-combo-removable-btn close'
15292 if(this.hasFeedback && !this.allowBlank){
15294 inputblock.cls += ' has-feedback';
15296 inputblock.cn.push({
15298 cls: 'glyphicon form-control-feedback'
15305 inputblock.cls += (this.before) ? '' : ' input-group';
15307 inputblock.cn.push({
15309 cls : 'input-group-addon input-group-append input-group-text',
15315 var ibwrap = inputblock;
15320 cls: 'roo-select2-choices',
15324 cls: 'roo-select2-search-field',
15337 cls: 'roo-select2-container input-group roo-touchview-combobox ',
15342 cls: 'form-hidden-field'
15348 if(!this.multiple && this.showToggleBtn){
15355 if (this.caret != false) {
15358 cls: 'fa fa-' + this.caret
15365 cls : 'input-group-addon input-group-append input-group-text btn dropdown-toggle',
15370 cls: 'combobox-clear',
15384 combobox.cls += ' roo-select2-container-multi';
15387 var align = this.labelAlign || this.parentLabelAlign();
15389 if (align ==='left' && this.fieldLabel.length) {
15394 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15395 tooltip : 'This field is required'
15399 cls : 'control-label col-form-label',
15400 html : this.fieldLabel
15411 var labelCfg = cfg.cn[1];
15412 var contentCfg = cfg.cn[2];
15415 if(this.indicatorpos == 'right'){
15420 cls : 'control-label col-form-label',
15424 html : this.fieldLabel
15428 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15429 tooltip : 'This field is required'
15442 labelCfg = cfg.cn[0];
15443 contentCfg = cfg.cn[1];
15448 if(this.labelWidth > 12){
15449 labelCfg.style = "width: " + this.labelWidth + 'px';
15452 if(this.labelWidth < 13 && this.labelmd == 0){
15453 this.labelmd = this.labelWidth;
15456 if(this.labellg > 0){
15457 labelCfg.cls += ' col-lg-' + this.labellg;
15458 contentCfg.cls += ' col-lg-' + (12 - this.labellg);
15461 if(this.labelmd > 0){
15462 labelCfg.cls += ' col-md-' + this.labelmd;
15463 contentCfg.cls += ' col-md-' + (12 - this.labelmd);
15466 if(this.labelsm > 0){
15467 labelCfg.cls += ' col-sm-' + this.labelsm;
15468 contentCfg.cls += ' col-sm-' + (12 - this.labelsm);
15471 if(this.labelxs > 0){
15472 labelCfg.cls += ' col-xs-' + this.labelxs;
15473 contentCfg.cls += ' col-xs-' + (12 - this.labelxs);
15477 } else if ( this.fieldLabel.length) {
15481 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
15482 tooltip : 'This field is required'
15486 cls : 'control-label',
15487 html : this.fieldLabel
15498 if(this.indicatorpos == 'right'){
15502 cls : 'control-label',
15503 html : this.fieldLabel,
15507 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
15508 tooltip : 'This field is required'
15525 var settings = this;
15527 ['xs','sm','md','lg'].map(function(size){
15528 if (settings[size]) {
15529 cfg.cls += ' col-' + size + '-' + settings[size];
15536 initTouchView : function()
15538 this.renderTouchView();
15540 this.touchViewEl.on('scroll', function(){
15541 this.el.dom.scrollTop = 0;
15544 this.originalValue = this.getValue();
15546 this.triggerEl = this.el.select('span.dropdown-toggle',true).first();
15548 this.inputEl().on("click", this.showTouchView, this);
15549 if (this.triggerEl) {
15550 this.triggerEl.on("click", this.showTouchView, this);
15554 this.touchViewFooterEl.select('.roo-touch-view-cancel', true).first().on('click', this.hideTouchView, this);
15555 this.touchViewFooterEl.select('.roo-touch-view-ok', true).first().on('click', this.setTouchViewValue, this);
15557 this.maskEl = new Roo.LoadMask(this.touchViewEl, { store : this.store, msgCls: 'roo-el-mask-msg' });
15559 this.store.on('beforeload', this.onTouchViewBeforeLoad, this);
15560 this.store.on('load', this.onTouchViewLoad, this);
15561 this.store.on('loadexception', this.onTouchViewLoadException, this);
15563 if(this.hiddenName){
15565 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
15567 this.hiddenField.dom.value =
15568 this.hiddenValue !== undefined ? this.hiddenValue :
15569 this.value !== undefined ? this.value : '';
15571 this.el.dom.removeAttribute('name');
15572 this.hiddenField.dom.setAttribute('name', this.hiddenName);
15576 this.choices = this.el.select('ul.roo-select2-choices', true).first();
15577 this.searchField = this.el.select('ul li.roo-select2-search-field', true).first();
15580 if(this.removable && !this.multiple){
15581 var close = this.closeTriggerEl();
15583 close.setVisibilityMode(Roo.Element.DISPLAY).hide();
15584 close.on('click', this.removeBtnClick, this, close);
15588 * fix the bug in Safari iOS8
15590 this.inputEl().on("focus", function(e){
15591 document.activeElement.blur();
15594 this._touchViewMask = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
15601 renderTouchView : function()
15603 this.touchViewEl = Roo.get(document.body).createChild(Roo.bootstrap.ComboBox.touchViewTemplate);
15604 this.touchViewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15606 this.touchViewHeaderEl = this.touchViewEl.select('.modal-header', true).first();
15607 this.touchViewHeaderEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15609 this.touchViewBodyEl = this.touchViewEl.select('.modal-body', true).first();
15610 this.touchViewBodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15611 this.touchViewBodyEl.setStyle('overflow', 'auto');
15613 this.touchViewListGroup = this.touchViewBodyEl.select('.list-group', true).first();
15614 this.touchViewListGroup.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15616 this.touchViewFooterEl = this.touchViewEl.select('.modal-footer', true).first();
15617 this.touchViewFooterEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
15621 showTouchView : function()
15627 this.touchViewHeaderEl.hide();
15629 if(this.modalTitle.length){
15630 this.touchViewHeaderEl.dom.innerHTML = this.modalTitle;
15631 this.touchViewHeaderEl.show();
15634 this.touchViewEl.setStyle('z-index', Roo.bootstrap.Modal.zIndex++);
15635 this.touchViewEl.show();
15637 this.touchViewEl.select('.modal-dialog', true).first().setStyle({ margin : '0px', width : '100%'});
15639 //this.touchViewEl.select('.modal-dialog > .modal-content', true).first().setSize(
15640 // Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15642 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15644 if(this.modalTitle.length){
15645 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15648 this.touchViewBodyEl.setHeight(bodyHeight);
15652 (function(){ _this.touchViewEl.addClass('in'); }).defer(50);
15654 this.touchViewEl.addClass('in');
15657 if(this._touchViewMask){
15658 Roo.get(document.body).addClass("x-body-masked");
15659 this._touchViewMask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15660 this._touchViewMask.setStyle('z-index', 10000);
15661 this._touchViewMask.addClass('show');
15664 this.doTouchViewQuery();
15668 hideTouchView : function()
15670 this.touchViewEl.removeClass('in');
15674 (function(){ _this.touchViewEl.setStyle('display', 'none'); }).defer(150);
15676 this.touchViewEl.setStyle('display', 'none');
15679 if(this._touchViewMask){
15680 this._touchViewMask.removeClass('show');
15681 Roo.get(document.body).removeClass("x-body-masked");
15685 setTouchViewValue : function()
15692 Roo.each(this.tickItems, function(o){
15697 this.hideTouchView();
15700 doTouchViewQuery : function()
15709 if(this.fireEvent('beforequery', qe) ===false || qe.cancel){
15713 if(!this.alwaysQuery || this.mode == 'local'){
15714 this.onTouchViewLoad();
15721 onTouchViewBeforeLoad : function(combo,opts)
15727 onTouchViewLoad : function()
15729 if(this.store.getCount() < 1){
15730 this.onTouchViewEmptyResults();
15734 this.clearTouchView();
15736 var rawValue = this.getRawValue();
15738 var template = (this.multiple) ? Roo.bootstrap.ComboBox.listItemCheckbox : Roo.bootstrap.ComboBox.listItemRadio;
15740 this.tickItems = [];
15742 this.store.data.each(function(d, rowIndex){
15743 var row = this.touchViewListGroup.createChild(template);
15745 if(typeof(d.data.cls) != 'undefined' && d.data.cls.length){
15746 row.addClass(d.data.cls);
15749 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15752 html : d.data[this.displayField]
15755 if(this.fireEvent('touchviewdisplay', this, cfg) !== false){
15756 row.select('.roo-combobox-list-group-item-value', true).first().dom.innerHTML = cfg.html;
15759 row.removeClass('selected');
15760 if(!this.multiple && this.valueField &&
15761 typeof(d.data[this.valueField]) != 'undefined' && d.data[this.valueField] == this.getValue())
15764 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15765 row.addClass('selected');
15768 if(this.multiple && this.valueField &&
15769 typeof(d.data[this.valueField]) != 'undefined' && this.getValue().indexOf(d.data[this.valueField]) != -1)
15773 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15774 this.tickItems.push(d.data);
15777 row.on('click', this.onTouchViewClick, this, {row : row, rowIndex : rowIndex});
15781 var firstChecked = this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).first();
15783 var bodyHeight = Roo.lib.Dom.getViewHeight() - this.touchViewFooterEl.getHeight() + this.touchViewBodyEl.getPadding('tb');
15785 if(this.modalTitle.length){
15786 bodyHeight = bodyHeight - this.touchViewHeaderEl.getHeight();
15789 var listHeight = this.touchViewListGroup.getHeight() + this.touchViewBodyEl.getPadding('tb') * 2;
15791 if(this.mobile_restrict_height && listHeight < bodyHeight){
15792 this.touchViewBodyEl.setHeight(listHeight);
15797 if(firstChecked && listHeight > bodyHeight){
15798 (function() { firstChecked.findParent('li').scrollIntoView(_this.touchViewListGroup.dom); }).defer(500);
15803 onTouchViewLoadException : function()
15805 this.hideTouchView();
15808 onTouchViewEmptyResults : function()
15810 this.clearTouchView();
15812 this.touchViewListGroup.createChild(Roo.bootstrap.ComboBox.emptyResult);
15814 this.touchViewListGroup.select('.roo-combobox-touch-view-empty-result', true).first().dom.innerHTML = this.emptyResultText;
15818 clearTouchView : function()
15820 this.touchViewListGroup.dom.innerHTML = '';
15823 onTouchViewClick : function(e, el, o)
15825 e.preventDefault();
15828 var rowIndex = o.rowIndex;
15830 var r = this.store.getAt(rowIndex);
15832 if(this.fireEvent('beforeselect', this, r, rowIndex) !== false){
15834 if(!this.multiple){
15835 Roo.each(this.touchViewListGroup.select('.list-group-item > .roo-combobox-list-group-item-box > input:checked', true).elements, function(c){
15836 c.dom.removeAttribute('checked');
15839 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15841 this.setFromData(r.data);
15843 var close = this.closeTriggerEl();
15849 this.hideTouchView();
15851 this.fireEvent('select', this, r, rowIndex);
15856 if(this.valueField && typeof(r.data[this.valueField]) != 'undefined' && this.getValue().indexOf(r.data[this.valueField]) != -1){
15857 row.select('.roo-combobox-list-group-item-box > input', true).first().dom.removeAttribute('checked');
15858 this.tickItems.splice(this.tickItems.indexOf(r.data), 1);
15862 row.select('.roo-combobox-list-group-item-box > input', true).first().attr('checked', true);
15863 this.addItem(r.data);
15864 this.tickItems.push(r.data);
15868 getAutoCreateNativeIOS : function()
15871 cls: 'form-group' //input-group,
15876 cls : 'roo-ios-select'
15880 combobox.name = this.name;
15883 if (this.disabled) {
15884 combobox.disabled = true;
15887 var settings = this;
15889 ['xs','sm','md','lg'].map(function(size){
15890 if (settings[size]) {
15891 cfg.cls += ' col-' + size + '-' + settings[size];
15901 initIOSView : function()
15903 this.store.on('load', this.onIOSViewLoad, this);
15908 onIOSViewLoad : function()
15910 if(this.store.getCount() < 1){
15914 this.clearIOSView();
15916 if(this.allowBlank) {
15918 var default_text = '-- SELECT --';
15920 if(this.placeholder.length){
15921 default_text = this.placeholder;
15924 if(this.emptyTitle.length){
15925 default_text += ' - ' + this.emptyTitle + ' -';
15928 var opt = this.inputEl().createChild({
15931 html : default_text
15935 o[this.valueField] = 0;
15936 o[this.displayField] = default_text;
15938 this.ios_options.push({
15945 this.store.data.each(function(d, rowIndex){
15949 if(this.displayField && typeof(d.data[this.displayField]) != 'undefined'){
15950 html = d.data[this.displayField];
15955 if(this.valueField && typeof(d.data[this.valueField]) != 'undefined'){
15956 value = d.data[this.valueField];
15965 if(this.value == d.data[this.valueField]){
15966 option['selected'] = true;
15969 var opt = this.inputEl().createChild(option);
15971 this.ios_options.push({
15978 this.inputEl().on('change', function(){
15979 this.fireEvent('select', this);
15984 clearIOSView: function()
15986 this.inputEl().dom.innerHTML = '';
15988 this.ios_options = [];
15991 setIOSValue: function(v)
15995 if(!this.ios_options){
15999 Roo.each(this.ios_options, function(opts){
16001 opts.el.dom.removeAttribute('selected');
16003 if(opts.data[this.valueField] != v){
16007 opts.el.dom.setAttribute('selected', true);
16013 * @cfg {Boolean} grow
16017 * @cfg {Number} growMin
16021 * @cfg {Number} growMax
16030 Roo.apply(Roo.bootstrap.ComboBox, {
16034 cls: 'modal-header',
16056 cls: 'list-group-item',
16060 cls: 'roo-combobox-list-group-item-value'
16064 cls: 'roo-combobox-list-group-item-box pull-xs-right radio-inline radio radio-info',
16078 listItemCheckbox : {
16080 cls: 'list-group-item',
16084 cls: 'roo-combobox-list-group-item-value'
16088 cls: 'roo-combobox-list-group-item-box pull-xs-right checkbox-inline checkbox checkbox-info',
16104 cls: 'alert alert-danger roo-combobox-touch-view-empty-result'
16109 cls: 'modal-footer',
16117 cls: 'col-xs-6 text-left',
16120 cls: 'btn btn-danger roo-touch-view-cancel',
16126 cls: 'col-xs-6 text-right',
16129 cls: 'btn btn-success roo-touch-view-ok',
16140 Roo.apply(Roo.bootstrap.ComboBox, {
16142 touchViewTemplate : {
16144 cls: 'modal fade roo-combobox-touch-view',
16148 cls: 'modal-dialog',
16149 style : 'position:fixed', // we have to fix position....
16153 cls: 'modal-content',
16155 Roo.bootstrap.ComboBox.header,
16156 Roo.bootstrap.ComboBox.body,
16157 Roo.bootstrap.ComboBox.footer
16166 * Ext JS Library 1.1.1
16167 * Copyright(c) 2006-2007, Ext JS, LLC.
16169 * Originally Released Under LGPL - original licence link has changed is not relivant.
16172 * <script type="text/javascript">
16177 * @extends Roo.util.Observable
16178 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
16179 * This class also supports single and multi selection modes. <br>
16180 * Create a data model bound view:
16182 var store = new Roo.data.Store(...);
16184 var view = new Roo.View({
16186 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
16188 singleSelect: true,
16189 selectedClass: "ydataview-selected",
16193 // listen for node click?
16194 view.on("click", function(vw, index, node, e){
16195 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
16199 dataModel.load("foobar.xml");
16201 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
16203 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
16204 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
16206 * Note: old style constructor is still suported (container, template, config)
16209 * Create a new View
16210 * @param {Object} config The config object
16213 Roo.View = function(config, depreciated_tpl, depreciated_config){
16215 this.parent = false;
16217 if (typeof(depreciated_tpl) == 'undefined') {
16218 // new way.. - universal constructor.
16219 Roo.apply(this, config);
16220 this.el = Roo.get(this.el);
16223 this.el = Roo.get(config);
16224 this.tpl = depreciated_tpl;
16225 Roo.apply(this, depreciated_config);
16227 this.wrapEl = this.el.wrap().wrap();
16228 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
16231 if(typeof(this.tpl) == "string"){
16232 this.tpl = new Roo.Template(this.tpl);
16234 // support xtype ctors..
16235 this.tpl = new Roo.factory(this.tpl, Roo);
16239 this.tpl.compile();
16244 * @event beforeclick
16245 * Fires before a click is processed. Returns false to cancel the default action.
16246 * @param {Roo.View} this
16247 * @param {Number} index The index of the target node
16248 * @param {HTMLElement} node The target node
16249 * @param {Roo.EventObject} e The raw event object
16251 "beforeclick" : true,
16254 * Fires when a template node is clicked.
16255 * @param {Roo.View} this
16256 * @param {Number} index The index of the target node
16257 * @param {HTMLElement} node The target node
16258 * @param {Roo.EventObject} e The raw event object
16263 * Fires when a template node is double clicked.
16264 * @param {Roo.View} this
16265 * @param {Number} index The index of the target node
16266 * @param {HTMLElement} node The target node
16267 * @param {Roo.EventObject} e The raw event object
16271 * @event contextmenu
16272 * Fires when a template node is right clicked.
16273 * @param {Roo.View} this
16274 * @param {Number} index The index of the target node
16275 * @param {HTMLElement} node The target node
16276 * @param {Roo.EventObject} e The raw event object
16278 "contextmenu" : true,
16280 * @event selectionchange
16281 * Fires when the selected nodes change.
16282 * @param {Roo.View} this
16283 * @param {Array} selections Array of the selected nodes
16285 "selectionchange" : true,
16288 * @event beforeselect
16289 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
16290 * @param {Roo.View} this
16291 * @param {HTMLElement} node The node to be selected
16292 * @param {Array} selections Array of currently selected nodes
16294 "beforeselect" : true,
16296 * @event preparedata
16297 * Fires on every row to render, to allow you to change the data.
16298 * @param {Roo.View} this
16299 * @param {Object} data to be rendered (change this)
16301 "preparedata" : true
16309 "click": this.onClick,
16310 "dblclick": this.onDblClick,
16311 "contextmenu": this.onContextMenu,
16315 this.selections = [];
16317 this.cmp = new Roo.CompositeElementLite([]);
16319 this.store = Roo.factory(this.store, Roo.data);
16320 this.setStore(this.store, true);
16323 if ( this.footer && this.footer.xtype) {
16325 var fctr = this.wrapEl.appendChild(document.createElement("div"));
16327 this.footer.dataSource = this.store;
16328 this.footer.container = fctr;
16329 this.footer = Roo.factory(this.footer, Roo);
16330 fctr.insertFirst(this.el);
16332 // this is a bit insane - as the paging toolbar seems to detach the el..
16333 // dom.parentNode.parentNode.parentNode
16334 // they get detached?
16338 Roo.View.superclass.constructor.call(this);
16343 Roo.extend(Roo.View, Roo.util.Observable, {
16346 * @cfg {Roo.data.Store} store Data store to load data from.
16351 * @cfg {String|Roo.Element} el The container element.
16356 * @cfg {String|Roo.Template} tpl The template used by this View
16360 * @cfg {String} dataName the named area of the template to use as the data area
16361 * Works with domtemplates roo-name="name"
16365 * @cfg {String} selectedClass The css class to add to selected nodes
16367 selectedClass : "x-view-selected",
16369 * @cfg {String} emptyText The empty text to show when nothing is loaded.
16374 * @cfg {String} text to display on mask (default Loading)
16378 * @cfg {Boolean} multiSelect Allow multiple selection
16380 multiSelect : false,
16382 * @cfg {Boolean} singleSelect Allow single selection
16384 singleSelect: false,
16387 * @cfg {Boolean} toggleSelect - selecting
16389 toggleSelect : false,
16392 * @cfg {Boolean} tickable - selecting
16397 * Returns the element this view is bound to.
16398 * @return {Roo.Element}
16400 getEl : function(){
16401 return this.wrapEl;
16407 * Refreshes the view. - called by datachanged on the store. - do not call directly.
16409 refresh : function(){
16410 //Roo.log('refresh');
16413 // if we are using something like 'domtemplate', then
16414 // the what gets used is:
16415 // t.applySubtemplate(NAME, data, wrapping data..)
16416 // the outer template then get' applied with
16417 // the store 'extra data'
16418 // and the body get's added to the
16419 // roo-name="data" node?
16420 // <span class='roo-tpl-{name}'></span> ?????
16424 this.clearSelections();
16425 this.el.update("");
16427 var records = this.store.getRange();
16428 if(records.length < 1) {
16430 // is this valid?? = should it render a template??
16432 this.el.update(this.emptyText);
16436 if (this.dataName) {
16437 this.el.update(t.apply(this.store.meta)); //????
16438 el = this.el.child('.roo-tpl-' + this.dataName);
16441 for(var i = 0, len = records.length; i < len; i++){
16442 var data = this.prepareData(records[i].data, i, records[i]);
16443 this.fireEvent("preparedata", this, data, i, records[i]);
16445 var d = Roo.apply({}, data);
16448 Roo.apply(d, {'roo-id' : Roo.id()});
16452 Roo.each(this.parent.item, function(item){
16453 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
16456 Roo.apply(d, {'roo-data-checked' : 'checked'});
16460 html[html.length] = Roo.util.Format.trim(
16462 t.applySubtemplate(this.dataName, d, this.store.meta) :
16469 el.update(html.join(""));
16470 this.nodes = el.dom.childNodes;
16471 this.updateIndexes(0);
16476 * Function to override to reformat the data that is sent to
16477 * the template for each node.
16478 * DEPRICATED - use the preparedata event handler.
16479 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
16480 * a JSON object for an UpdateManager bound view).
16482 prepareData : function(data, index, record)
16484 this.fireEvent("preparedata", this, data, index, record);
16488 onUpdate : function(ds, record){
16489 // Roo.log('on update');
16490 this.clearSelections();
16491 var index = this.store.indexOf(record);
16492 var n = this.nodes[index];
16493 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
16494 n.parentNode.removeChild(n);
16495 this.updateIndexes(index, index);
16501 onAdd : function(ds, records, index)
16503 //Roo.log(['on Add', ds, records, index] );
16504 this.clearSelections();
16505 if(this.nodes.length == 0){
16509 var n = this.nodes[index];
16510 for(var i = 0, len = records.length; i < len; i++){
16511 var d = this.prepareData(records[i].data, i, records[i]);
16513 this.tpl.insertBefore(n, d);
16516 this.tpl.append(this.el, d);
16519 this.updateIndexes(index);
16522 onRemove : function(ds, record, index){
16523 // Roo.log('onRemove');
16524 this.clearSelections();
16525 var el = this.dataName ?
16526 this.el.child('.roo-tpl-' + this.dataName) :
16529 el.dom.removeChild(this.nodes[index]);
16530 this.updateIndexes(index);
16534 * Refresh an individual node.
16535 * @param {Number} index
16537 refreshNode : function(index){
16538 this.onUpdate(this.store, this.store.getAt(index));
16541 updateIndexes : function(startIndex, endIndex){
16542 var ns = this.nodes;
16543 startIndex = startIndex || 0;
16544 endIndex = endIndex || ns.length - 1;
16545 for(var i = startIndex; i <= endIndex; i++){
16546 ns[i].nodeIndex = i;
16551 * Changes the data store this view uses and refresh the view.
16552 * @param {Store} store
16554 setStore : function(store, initial){
16555 if(!initial && this.store){
16556 this.store.un("datachanged", this.refresh);
16557 this.store.un("add", this.onAdd);
16558 this.store.un("remove", this.onRemove);
16559 this.store.un("update", this.onUpdate);
16560 this.store.un("clear", this.refresh);
16561 this.store.un("beforeload", this.onBeforeLoad);
16562 this.store.un("load", this.onLoad);
16563 this.store.un("loadexception", this.onLoad);
16567 store.on("datachanged", this.refresh, this);
16568 store.on("add", this.onAdd, this);
16569 store.on("remove", this.onRemove, this);
16570 store.on("update", this.onUpdate, this);
16571 store.on("clear", this.refresh, this);
16572 store.on("beforeload", this.onBeforeLoad, this);
16573 store.on("load", this.onLoad, this);
16574 store.on("loadexception", this.onLoad, this);
16582 * onbeforeLoad - masks the loading area.
16585 onBeforeLoad : function(store,opts)
16587 //Roo.log('onBeforeLoad');
16589 this.el.update("");
16591 this.el.mask(this.mask ? this.mask : "Loading" );
16593 onLoad : function ()
16600 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
16601 * @param {HTMLElement} node
16602 * @return {HTMLElement} The template node
16604 findItemFromChild : function(node){
16605 var el = this.dataName ?
16606 this.el.child('.roo-tpl-' + this.dataName,true) :
16609 if(!node || node.parentNode == el){
16612 var p = node.parentNode;
16613 while(p && p != el){
16614 if(p.parentNode == el){
16623 onClick : function(e){
16624 var item = this.findItemFromChild(e.getTarget());
16626 var index = this.indexOf(item);
16627 if(this.onItemClick(item, index, e) !== false){
16628 this.fireEvent("click", this, index, item, e);
16631 this.clearSelections();
16636 onContextMenu : function(e){
16637 var item = this.findItemFromChild(e.getTarget());
16639 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
16644 onDblClick : function(e){
16645 var item = this.findItemFromChild(e.getTarget());
16647 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
16651 onItemClick : function(item, index, e)
16653 if(this.fireEvent("beforeclick", this, index, item, e) === false){
16656 if (this.toggleSelect) {
16657 var m = this.isSelected(item) ? 'unselect' : 'select';
16660 _t[m](item, true, false);
16663 if(this.multiSelect || this.singleSelect){
16664 if(this.multiSelect && e.shiftKey && this.lastSelection){
16665 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
16667 this.select(item, this.multiSelect && e.ctrlKey);
16668 this.lastSelection = item;
16671 if(!this.tickable){
16672 e.preventDefault();
16680 * Get the number of selected nodes.
16683 getSelectionCount : function(){
16684 return this.selections.length;
16688 * Get the currently selected nodes.
16689 * @return {Array} An array of HTMLElements
16691 getSelectedNodes : function(){
16692 return this.selections;
16696 * Get the indexes of the selected nodes.
16699 getSelectedIndexes : function(){
16700 var indexes = [], s = this.selections;
16701 for(var i = 0, len = s.length; i < len; i++){
16702 indexes.push(s[i].nodeIndex);
16708 * Clear all selections
16709 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
16711 clearSelections : function(suppressEvent){
16712 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
16713 this.cmp.elements = this.selections;
16714 this.cmp.removeClass(this.selectedClass);
16715 this.selections = [];
16716 if(!suppressEvent){
16717 this.fireEvent("selectionchange", this, this.selections);
16723 * Returns true if the passed node is selected
16724 * @param {HTMLElement/Number} node The node or node index
16725 * @return {Boolean}
16727 isSelected : function(node){
16728 var s = this.selections;
16732 node = this.getNode(node);
16733 return s.indexOf(node) !== -1;
16738 * @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
16739 * @param {Boolean} keepExisting (optional) true to keep existing selections
16740 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16742 select : function(nodeInfo, keepExisting, suppressEvent){
16743 if(nodeInfo instanceof Array){
16745 this.clearSelections(true);
16747 for(var i = 0, len = nodeInfo.length; i < len; i++){
16748 this.select(nodeInfo[i], true, true);
16752 var node = this.getNode(nodeInfo);
16753 if(!node || this.isSelected(node)){
16754 return; // already selected.
16757 this.clearSelections(true);
16760 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
16761 Roo.fly(node).addClass(this.selectedClass);
16762 this.selections.push(node);
16763 if(!suppressEvent){
16764 this.fireEvent("selectionchange", this, this.selections);
16772 * @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
16773 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
16774 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
16776 unselect : function(nodeInfo, keepExisting, suppressEvent)
16778 if(nodeInfo instanceof Array){
16779 Roo.each(this.selections, function(s) {
16780 this.unselect(s, nodeInfo);
16784 var node = this.getNode(nodeInfo);
16785 if(!node || !this.isSelected(node)){
16786 //Roo.log("not selected");
16787 return; // not selected.
16791 Roo.each(this.selections, function(s) {
16793 Roo.fly(node).removeClass(this.selectedClass);
16800 this.selections= ns;
16801 this.fireEvent("selectionchange", this, this.selections);
16805 * Gets a template node.
16806 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16807 * @return {HTMLElement} The node or null if it wasn't found
16809 getNode : function(nodeInfo){
16810 if(typeof nodeInfo == "string"){
16811 return document.getElementById(nodeInfo);
16812 }else if(typeof nodeInfo == "number"){
16813 return this.nodes[nodeInfo];
16819 * Gets a range template nodes.
16820 * @param {Number} startIndex
16821 * @param {Number} endIndex
16822 * @return {Array} An array of nodes
16824 getNodes : function(start, end){
16825 var ns = this.nodes;
16826 start = start || 0;
16827 end = typeof end == "undefined" ? ns.length - 1 : end;
16830 for(var i = start; i <= end; i++){
16834 for(var i = start; i >= end; i--){
16842 * Finds the index of the passed node
16843 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
16844 * @return {Number} The index of the node or -1
16846 indexOf : function(node){
16847 node = this.getNode(node);
16848 if(typeof node.nodeIndex == "number"){
16849 return node.nodeIndex;
16851 var ns = this.nodes;
16852 for(var i = 0, len = ns.length; i < len; i++){
16863 * based on jquery fullcalendar
16867 Roo.bootstrap = Roo.bootstrap || {};
16869 * @class Roo.bootstrap.Calendar
16870 * @extends Roo.bootstrap.Component
16871 * Bootstrap Calendar class
16872 * @cfg {Boolean} loadMask (true|false) default false
16873 * @cfg {Object} header generate the user specific header of the calendar, default false
16876 * Create a new Container
16877 * @param {Object} config The config object
16882 Roo.bootstrap.Calendar = function(config){
16883 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
16887 * Fires when a date is selected
16888 * @param {DatePicker} this
16889 * @param {Date} date The selected date
16893 * @event monthchange
16894 * Fires when the displayed month changes
16895 * @param {DatePicker} this
16896 * @param {Date} date The selected month
16898 'monthchange': true,
16900 * @event evententer
16901 * Fires when mouse over an event
16902 * @param {Calendar} this
16903 * @param {event} Event
16905 'evententer': true,
16907 * @event eventleave
16908 * Fires when the mouse leaves an
16909 * @param {Calendar} this
16912 'eventleave': true,
16914 * @event eventclick
16915 * Fires when the mouse click an
16916 * @param {Calendar} this
16925 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
16928 * @cfg {Number} startDay
16929 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
16937 getAutoCreate : function(){
16940 var fc_button = function(name, corner, style, content ) {
16941 return Roo.apply({},{
16943 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
16945 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
16948 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
16959 style : 'width:100%',
16966 cls : 'fc-header-left',
16968 fc_button('prev', 'left', 'arrow', '‹' ),
16969 fc_button('next', 'right', 'arrow', '›' ),
16970 { tag: 'span', cls: 'fc-header-space' },
16971 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
16979 cls : 'fc-header-center',
16983 cls: 'fc-header-title',
16986 html : 'month / year'
16994 cls : 'fc-header-right',
16996 /* fc_button('month', 'left', '', 'month' ),
16997 fc_button('week', '', '', 'week' ),
16998 fc_button('day', 'right', '', 'day' )
17010 header = this.header;
17013 var cal_heads = function() {
17015 // fixme - handle this.
17017 for (var i =0; i < Date.dayNames.length; i++) {
17018 var d = Date.dayNames[i];
17021 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
17022 html : d.substring(0,3)
17026 ret[0].cls += ' fc-first';
17027 ret[6].cls += ' fc-last';
17030 var cal_cell = function(n) {
17033 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
17038 cls: 'fc-day-number',
17042 cls: 'fc-day-content',
17046 style: 'position: relative;' // height: 17px;
17058 var cal_rows = function() {
17061 for (var r = 0; r < 6; r++) {
17068 for (var i =0; i < Date.dayNames.length; i++) {
17069 var d = Date.dayNames[i];
17070 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
17073 row.cn[0].cls+=' fc-first';
17074 row.cn[0].cn[0].style = 'min-height:90px';
17075 row.cn[6].cls+=' fc-last';
17079 ret[0].cls += ' fc-first';
17080 ret[4].cls += ' fc-prev-last';
17081 ret[5].cls += ' fc-last';
17088 cls: 'fc-border-separate',
17089 style : 'width:100%',
17097 cls : 'fc-first fc-last',
17115 cls : 'fc-content',
17116 style : "position: relative;",
17119 cls : 'fc-view fc-view-month fc-grid',
17120 style : 'position: relative',
17121 unselectable : 'on',
17124 cls : 'fc-event-container',
17125 style : 'position:absolute;z-index:8;top:0;left:0;'
17143 initEvents : function()
17146 throw "can not find store for calendar";
17152 style: "text-align:center",
17156 style: "background-color:white;width:50%;margin:250 auto",
17160 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
17171 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
17173 var size = this.el.select('.fc-content', true).first().getSize();
17174 this.maskEl.setSize(size.width, size.height);
17175 this.maskEl.enableDisplayMode("block");
17176 if(!this.loadMask){
17177 this.maskEl.hide();
17180 this.store = Roo.factory(this.store, Roo.data);
17181 this.store.on('load', this.onLoad, this);
17182 this.store.on('beforeload', this.onBeforeLoad, this);
17186 this.cells = this.el.select('.fc-day',true);
17187 //Roo.log(this.cells);
17188 this.textNodes = this.el.query('.fc-day-number');
17189 this.cells.addClassOnOver('fc-state-hover');
17191 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
17192 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
17193 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
17194 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
17196 this.on('monthchange', this.onMonthChange, this);
17198 this.update(new Date().clearTime());
17201 resize : function() {
17202 var sz = this.el.getSize();
17204 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
17205 this.el.select('.fc-day-content div',true).setHeight(34);
17210 showPrevMonth : function(e){
17211 this.update(this.activeDate.add("mo", -1));
17213 showToday : function(e){
17214 this.update(new Date().clearTime());
17217 showNextMonth : function(e){
17218 this.update(this.activeDate.add("mo", 1));
17222 showPrevYear : function(){
17223 this.update(this.activeDate.add("y", -1));
17227 showNextYear : function(){
17228 this.update(this.activeDate.add("y", 1));
17233 update : function(date)
17235 var vd = this.activeDate;
17236 this.activeDate = date;
17237 // if(vd && this.el){
17238 // var t = date.getTime();
17239 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
17240 // Roo.log('using add remove');
17242 // this.fireEvent('monthchange', this, date);
17244 // this.cells.removeClass("fc-state-highlight");
17245 // this.cells.each(function(c){
17246 // if(c.dateValue == t){
17247 // c.addClass("fc-state-highlight");
17248 // setTimeout(function(){
17249 // try{c.dom.firstChild.focus();}catch(e){}
17259 var days = date.getDaysInMonth();
17261 var firstOfMonth = date.getFirstDateOfMonth();
17262 var startingPos = firstOfMonth.getDay()-this.startDay;
17264 if(startingPos < this.startDay){
17268 var pm = date.add(Date.MONTH, -1);
17269 var prevStart = pm.getDaysInMonth()-startingPos;
17271 this.cells = this.el.select('.fc-day',true);
17272 this.textNodes = this.el.query('.fc-day-number');
17273 this.cells.addClassOnOver('fc-state-hover');
17275 var cells = this.cells.elements;
17276 var textEls = this.textNodes;
17278 Roo.each(cells, function(cell){
17279 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
17282 days += startingPos;
17284 // convert everything to numbers so it's fast
17285 var day = 86400000;
17286 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
17289 //Roo.log(prevStart);
17291 var today = new Date().clearTime().getTime();
17292 var sel = date.clearTime().getTime();
17293 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
17294 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
17295 var ddMatch = this.disabledDatesRE;
17296 var ddText = this.disabledDatesText;
17297 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
17298 var ddaysText = this.disabledDaysText;
17299 var format = this.format;
17301 var setCellClass = function(cal, cell){
17305 //Roo.log('set Cell Class');
17307 var t = d.getTime();
17311 cell.dateValue = t;
17313 cell.className += " fc-today";
17314 cell.className += " fc-state-highlight";
17315 cell.title = cal.todayText;
17318 // disable highlight in other month..
17319 //cell.className += " fc-state-highlight";
17324 cell.className = " fc-state-disabled";
17325 cell.title = cal.minText;
17329 cell.className = " fc-state-disabled";
17330 cell.title = cal.maxText;
17334 if(ddays.indexOf(d.getDay()) != -1){
17335 cell.title = ddaysText;
17336 cell.className = " fc-state-disabled";
17339 if(ddMatch && format){
17340 var fvalue = d.dateFormat(format);
17341 if(ddMatch.test(fvalue)){
17342 cell.title = ddText.replace("%0", fvalue);
17343 cell.className = " fc-state-disabled";
17347 if (!cell.initialClassName) {
17348 cell.initialClassName = cell.dom.className;
17351 cell.dom.className = cell.initialClassName + ' ' + cell.className;
17356 for(; i < startingPos; i++) {
17357 textEls[i].innerHTML = (++prevStart);
17358 d.setDate(d.getDate()+1);
17360 cells[i].className = "fc-past fc-other-month";
17361 setCellClass(this, cells[i]);
17366 for(; i < days; i++){
17367 intDay = i - startingPos + 1;
17368 textEls[i].innerHTML = (intDay);
17369 d.setDate(d.getDate()+1);
17371 cells[i].className = ''; // "x-date-active";
17372 setCellClass(this, cells[i]);
17376 for(; i < 42; i++) {
17377 textEls[i].innerHTML = (++extraDays);
17378 d.setDate(d.getDate()+1);
17380 cells[i].className = "fc-future fc-other-month";
17381 setCellClass(this, cells[i]);
17384 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
17386 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
17388 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
17389 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
17391 if(totalRows != 6){
17392 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
17393 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
17396 this.fireEvent('monthchange', this, date);
17400 if(!this.internalRender){
17401 var main = this.el.dom.firstChild;
17402 var w = main.offsetWidth;
17403 this.el.setWidth(w + this.el.getBorderWidth("lr"));
17404 Roo.fly(main).setWidth(w);
17405 this.internalRender = true;
17406 // opera does not respect the auto grow header center column
17407 // then, after it gets a width opera refuses to recalculate
17408 // without a second pass
17409 if(Roo.isOpera && !this.secondPass){
17410 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
17411 this.secondPass = true;
17412 this.update.defer(10, this, [date]);
17419 findCell : function(dt) {
17420 dt = dt.clearTime().getTime();
17422 this.cells.each(function(c){
17423 //Roo.log("check " +c.dateValue + '?=' + dt);
17424 if(c.dateValue == dt){
17434 findCells : function(ev) {
17435 var s = ev.start.clone().clearTime().getTime();
17437 var e= ev.end.clone().clearTime().getTime();
17440 this.cells.each(function(c){
17441 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
17443 if(c.dateValue > e){
17446 if(c.dateValue < s){
17455 // findBestRow: function(cells)
17459 // for (var i =0 ; i < cells.length;i++) {
17460 // ret = Math.max(cells[i].rows || 0,ret);
17467 addItem : function(ev)
17469 // look for vertical location slot in
17470 var cells = this.findCells(ev);
17472 // ev.row = this.findBestRow(cells);
17474 // work out the location.
17478 for(var i =0; i < cells.length; i++) {
17480 cells[i].row = cells[0].row;
17483 cells[i].row = cells[i].row + 1;
17493 if (crow.start.getY() == cells[i].getY()) {
17495 crow.end = cells[i];
17512 cells[0].events.push(ev);
17514 this.calevents.push(ev);
17517 clearEvents: function() {
17519 if(!this.calevents){
17523 Roo.each(this.cells.elements, function(c){
17529 Roo.each(this.calevents, function(e) {
17530 Roo.each(e.els, function(el) {
17531 el.un('mouseenter' ,this.onEventEnter, this);
17532 el.un('mouseleave' ,this.onEventLeave, this);
17537 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
17543 renderEvents: function()
17547 this.cells.each(function(c) {
17556 if(c.row != c.events.length){
17557 r = 4 - (4 - (c.row - c.events.length));
17560 c.events = ev.slice(0, r);
17561 c.more = ev.slice(r);
17563 if(c.more.length && c.more.length == 1){
17564 c.events.push(c.more.pop());
17567 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
17571 this.cells.each(function(c) {
17573 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
17576 for (var e = 0; e < c.events.length; e++){
17577 var ev = c.events[e];
17578 var rows = ev.rows;
17580 for(var i = 0; i < rows.length; i++) {
17582 // how many rows should it span..
17585 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
17586 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
17588 unselectable : "on",
17591 cls: 'fc-event-inner',
17595 // cls: 'fc-event-time',
17596 // html : cells.length > 1 ? '' : ev.time
17600 cls: 'fc-event-title',
17601 html : String.format('{0}', ev.title)
17608 cls: 'ui-resizable-handle ui-resizable-e',
17609 html : '  '
17616 cfg.cls += ' fc-event-start';
17618 if ((i+1) == rows.length) {
17619 cfg.cls += ' fc-event-end';
17622 var ctr = _this.el.select('.fc-event-container',true).first();
17623 var cg = ctr.createChild(cfg);
17625 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
17626 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
17628 var r = (c.more.length) ? 1 : 0;
17629 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
17630 cg.setWidth(ebox.right - sbox.x -2);
17632 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
17633 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
17634 cg.on('click', _this.onEventClick, _this, ev);
17645 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
17646 style : 'position: absolute',
17647 unselectable : "on",
17650 cls: 'fc-event-inner',
17654 cls: 'fc-event-title',
17662 cls: 'ui-resizable-handle ui-resizable-e',
17663 html : '  '
17669 var ctr = _this.el.select('.fc-event-container',true).first();
17670 var cg = ctr.createChild(cfg);
17672 var sbox = c.select('.fc-day-content',true).first().getBox();
17673 var ebox = c.select('.fc-day-content',true).first().getBox();
17675 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
17676 cg.setWidth(ebox.right - sbox.x -2);
17678 cg.on('click', _this.onMoreEventClick, _this, c.more);
17688 onEventEnter: function (e, el,event,d) {
17689 this.fireEvent('evententer', this, el, event);
17692 onEventLeave: function (e, el,event,d) {
17693 this.fireEvent('eventleave', this, el, event);
17696 onEventClick: function (e, el,event,d) {
17697 this.fireEvent('eventclick', this, el, event);
17700 onMonthChange: function () {
17704 onMoreEventClick: function(e, el, more)
17708 this.calpopover.placement = 'right';
17709 this.calpopover.setTitle('More');
17711 this.calpopover.setContent('');
17713 var ctr = this.calpopover.el.select('.popover-content', true).first();
17715 Roo.each(more, function(m){
17717 cls : 'fc-event-hori fc-event-draggable',
17720 var cg = ctr.createChild(cfg);
17722 cg.on('click', _this.onEventClick, _this, m);
17725 this.calpopover.show(el);
17730 onLoad: function ()
17732 this.calevents = [];
17735 if(this.store.getCount() > 0){
17736 this.store.data.each(function(d){
17739 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
17740 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
17741 time : d.data.start_time,
17742 title : d.data.title,
17743 description : d.data.description,
17744 venue : d.data.venue
17749 this.renderEvents();
17751 if(this.calevents.length && this.loadMask){
17752 this.maskEl.hide();
17756 onBeforeLoad: function()
17758 this.clearEvents();
17760 this.maskEl.show();
17774 * @class Roo.bootstrap.Popover
17775 * @extends Roo.bootstrap.Component
17776 * Bootstrap Popover class
17777 * @cfg {String} html contents of the popover (or false to use children..)
17778 * @cfg {String} title of popover (or false to hide)
17779 * @cfg {String} placement how it is placed
17780 * @cfg {String} trigger click || hover (or false to trigger manually)
17781 * @cfg {String} over what (parent or false to trigger manually.)
17782 * @cfg {Number} delay - delay before showing
17785 * Create a new Popover
17786 * @param {Object} config The config object
17789 Roo.bootstrap.Popover = function(config){
17790 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
17796 * After the popover show
17798 * @param {Roo.bootstrap.Popover} this
17803 * After the popover hide
17805 * @param {Roo.bootstrap.Popover} this
17811 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
17813 title: 'Fill in a title',
17816 placement : 'right',
17817 trigger : 'hover', // hover
17823 can_build_overlaid : false,
17825 getChildContainer : function()
17827 return this.el.select('.popover-content',true).first();
17830 getAutoCreate : function(){
17833 cls : 'popover roo-dynamic',
17834 style: 'display:block',
17840 cls : 'popover-inner',
17844 cls: 'popover-title popover-header',
17848 cls : 'popover-content popover-body',
17859 setTitle: function(str)
17862 this.el.select('.popover-title',true).first().dom.innerHTML = str;
17864 setContent: function(str)
17867 this.el.select('.popover-content',true).first().dom.innerHTML = str;
17869 // as it get's added to the bottom of the page.
17870 onRender : function(ct, position)
17872 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17874 var cfg = Roo.apply({}, this.getAutoCreate());
17878 cfg.cls += ' ' + this.cls;
17881 cfg.style = this.style;
17883 //Roo.log("adding to ");
17884 this.el = Roo.get(document.body).createChild(cfg, position);
17885 // Roo.log(this.el);
17890 initEvents : function()
17892 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
17893 this.el.enableDisplayMode('block');
17895 if (this.over === false) {
17898 if (this.triggers === false) {
17901 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17902 var triggers = this.trigger ? this.trigger.split(' ') : [];
17903 Roo.each(triggers, function(trigger) {
17905 if (trigger == 'click') {
17906 on_el.on('click', this.toggle, this);
17907 } else if (trigger != 'manual') {
17908 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin';
17909 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout';
17911 on_el.on(eventIn ,this.enter, this);
17912 on_el.on(eventOut, this.leave, this);
17923 toggle : function () {
17924 this.hoverState == 'in' ? this.leave() : this.enter();
17927 enter : function () {
17929 clearTimeout(this.timeout);
17931 this.hoverState = 'in';
17933 if (!this.delay || !this.delay.show) {
17938 this.timeout = setTimeout(function () {
17939 if (_t.hoverState == 'in') {
17942 }, this.delay.show)
17945 leave : function() {
17946 clearTimeout(this.timeout);
17948 this.hoverState = 'out';
17950 if (!this.delay || !this.delay.hide) {
17955 this.timeout = setTimeout(function () {
17956 if (_t.hoverState == 'out') {
17959 }, this.delay.hide)
17962 show : function (on_el)
17965 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
17969 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
17970 if (this.html !== false) {
17971 this.el.select('.popover-content',true).first().dom.innerHtml = this.html;
17973 this.el.removeClass([
17974 'fade','top','bottom', 'left', 'right','in',
17975 'bs-popover-top','bs-popover-bottom', 'bs-popover-left', 'bs-popover-right'
17977 if (!this.title.length) {
17978 this.el.select('.popover-title',true).hide();
17981 var placement = typeof this.placement == 'function' ?
17982 this.placement.call(this, this.el, on_el) :
17985 var autoToken = /\s?auto?\s?/i;
17986 var autoPlace = autoToken.test(placement);
17988 placement = placement.replace(autoToken, '') || 'top';
17992 //this.el.setXY([0,0]);
17994 this.el.dom.style.display='block';
17995 this.el.addClass(placement);
17997 //this.el.appendTo(on_el);
17999 var p = this.getPosition();
18000 var box = this.el.getBox();
18005 var align = Roo.bootstrap.Popover.alignment[placement];
18008 this.el.alignTo(on_el, align[0],align[1]);
18009 //var arrow = this.el.select('.arrow',true).first();
18010 //arrow.set(align[2],
18012 this.el.addClass('in');
18015 if (this.el.hasClass('fade')) {
18019 this.hoverState = 'in';
18021 this.fireEvent('show', this);
18026 this.el.setXY([0,0]);
18027 this.el.removeClass('in');
18029 this.hoverState = null;
18031 this.fireEvent('hide', this);
18036 Roo.bootstrap.Popover.alignment = {
18037 'left' : ['r-l', [-10,0], 'right bs-popover-right'],
18038 'right' : ['l-r', [10,0], 'left bs-popover-left'],
18039 'bottom' : ['t-b', [0,10], 'top bs-popover-top'],
18040 'top' : [ 'b-t', [0,-10], 'bottom bs-popover-bottom']
18051 * @class Roo.bootstrap.Progress
18052 * @extends Roo.bootstrap.Component
18053 * Bootstrap Progress class
18054 * @cfg {Boolean} striped striped of the progress bar
18055 * @cfg {Boolean} active animated of the progress bar
18059 * Create a new Progress
18060 * @param {Object} config The config object
18063 Roo.bootstrap.Progress = function(config){
18064 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
18067 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
18072 getAutoCreate : function(){
18080 cfg.cls += ' progress-striped';
18084 cfg.cls += ' active';
18103 * @class Roo.bootstrap.ProgressBar
18104 * @extends Roo.bootstrap.Component
18105 * Bootstrap ProgressBar class
18106 * @cfg {Number} aria_valuenow aria-value now
18107 * @cfg {Number} aria_valuemin aria-value min
18108 * @cfg {Number} aria_valuemax aria-value max
18109 * @cfg {String} label label for the progress bar
18110 * @cfg {String} panel (success | info | warning | danger )
18111 * @cfg {String} role role of the progress bar
18112 * @cfg {String} sr_only text
18116 * Create a new ProgressBar
18117 * @param {Object} config The config object
18120 Roo.bootstrap.ProgressBar = function(config){
18121 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
18124 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
18128 aria_valuemax : 100,
18134 getAutoCreate : function()
18139 cls: 'progress-bar',
18140 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
18152 cfg.role = this.role;
18155 if(this.aria_valuenow){
18156 cfg['aria-valuenow'] = this.aria_valuenow;
18159 if(this.aria_valuemin){
18160 cfg['aria-valuemin'] = this.aria_valuemin;
18163 if(this.aria_valuemax){
18164 cfg['aria-valuemax'] = this.aria_valuemax;
18167 if(this.label && !this.sr_only){
18168 cfg.html = this.label;
18172 cfg.cls += ' progress-bar-' + this.panel;
18178 update : function(aria_valuenow)
18180 this.aria_valuenow = aria_valuenow;
18182 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
18197 * @class Roo.bootstrap.TabGroup
18198 * @extends Roo.bootstrap.Column
18199 * Bootstrap Column class
18200 * @cfg {String} navId the navigation id (for use with navbars) - will be auto generated if it does not exist..
18201 * @cfg {Boolean} carousel true to make the group behave like a carousel
18202 * @cfg {Boolean} bullets show bullets for the panels
18203 * @cfg {Boolean} autoslide (true|false) auto slide .. default false
18204 * @cfg {Number} timer auto slide timer .. default 0 millisecond
18205 * @cfg {Boolean} showarrow (true|false) show arrow default true
18208 * Create a new TabGroup
18209 * @param {Object} config The config object
18212 Roo.bootstrap.TabGroup = function(config){
18213 Roo.bootstrap.TabGroup.superclass.constructor.call(this, config);
18215 this.navId = Roo.id();
18218 Roo.bootstrap.TabGroup.register(this);
18222 Roo.extend(Roo.bootstrap.TabGroup, Roo.bootstrap.Column, {
18225 transition : false,
18230 slideOnTouch : false,
18233 getAutoCreate : function()
18235 var cfg = Roo.apply({}, Roo.bootstrap.TabGroup.superclass.getAutoCreate.call(this));
18237 cfg.cls += ' tab-content';
18239 if (this.carousel) {
18240 cfg.cls += ' carousel slide';
18243 cls : 'carousel-inner',
18247 if(this.bullets && !Roo.isTouch){
18250 cls : 'carousel-bullets',
18254 if(this.bullets_cls){
18255 bullets.cls = bullets.cls + ' ' + this.bullets_cls;
18262 cfg.cn[0].cn.push(bullets);
18265 if(this.showarrow){
18266 cfg.cn[0].cn.push({
18268 class : 'carousel-arrow',
18272 class : 'carousel-prev',
18276 class : 'fa fa-chevron-left'
18282 class : 'carousel-next',
18286 class : 'fa fa-chevron-right'
18299 initEvents: function()
18301 // if(Roo.isTouch && this.slideOnTouch && !this.showarrow){
18302 // this.el.on("touchstart", this.onTouchStart, this);
18305 if(this.autoslide){
18308 this.slideFn = window.setInterval(function() {
18309 _this.showPanelNext();
18313 if(this.showarrow){
18314 this.el.select('.carousel-prev', true).first().on('click', this.showPanelPrev, this);
18315 this.el.select('.carousel-next', true).first().on('click', this.showPanelNext, this);
18321 // onTouchStart : function(e, el, o)
18323 // if(!this.slideOnTouch || !Roo.isTouch || Roo.get(e.getTarget()).hasClass('roo-button-text')){
18327 // this.showPanelNext();
18331 getChildContainer : function()
18333 return this.carousel ? this.el.select('.carousel-inner', true).first() : this.el;
18337 * register a Navigation item
18338 * @param {Roo.bootstrap.NavItem} the navitem to add
18340 register : function(item)
18342 this.tabs.push( item);
18343 item.navId = this.navId; // not really needed..
18348 getActivePanel : function()
18351 Roo.each(this.tabs, function(t) {
18361 getPanelByName : function(n)
18364 Roo.each(this.tabs, function(t) {
18365 if (t.tabId == n) {
18373 indexOfPanel : function(p)
18376 Roo.each(this.tabs, function(t,i) {
18377 if (t.tabId == p.tabId) {
18386 * show a specific panel
18387 * @param {Roo.bootstrap.TabPanel|number|string} panel to change to (use the tabId to specify a specific one)
18388 * @return {boolean} false if panel was not shown (invalid entry or beforedeactivate fails.)
18390 showPanel : function (pan)
18392 if(this.transition || typeof(pan) == 'undefined'){
18393 Roo.log("waiting for the transitionend");
18397 if (typeof(pan) == 'number') {
18398 pan = this.tabs[pan];
18401 if (typeof(pan) == 'string') {
18402 pan = this.getPanelByName(pan);
18405 var cur = this.getActivePanel();
18408 Roo.log('pan or acitve pan is undefined');
18412 if (pan.tabId == this.getActivePanel().tabId) {
18416 if (false === cur.fireEvent('beforedeactivate')) {
18420 if(this.bullets > 0 && !Roo.isTouch){
18421 this.setActiveBullet(this.indexOfPanel(pan));
18424 if (this.carousel && typeof(Roo.get(document.body).dom.style.transition) != 'undefined') {
18426 //class="carousel-item carousel-item-next carousel-item-left"
18428 this.transition = true;
18429 var dir = this.indexOfPanel(pan) > this.indexOfPanel(cur) ? 'next' : 'prev';
18430 var lr = dir == 'next' ? 'left' : 'right';
18431 pan.el.addClass(dir); // or prev
18432 pan.el.addClass('carousel-item-' + dir); // or prev
18433 pan.el.dom.offsetWidth; // find the offset with - causing a reflow?
18434 cur.el.addClass(lr); // or right
18435 pan.el.addClass(lr);
18436 cur.el.addClass('carousel-item-' +lr); // or right
18437 pan.el.addClass('carousel-item-' +lr);
18441 cur.el.on('transitionend', function() {
18442 Roo.log("trans end?");
18444 pan.el.removeClass([lr,dir, 'carousel-item-' + lr, 'carousel-item-' + dir]);
18445 pan.setActive(true);
18447 cur.el.removeClass([lr, 'carousel-item-' + lr]);
18448 cur.setActive(false);
18450 _this.transition = false;
18452 }, this, { single: true } );
18457 cur.setActive(false);
18458 pan.setActive(true);
18463 showPanelNext : function()
18465 var i = this.indexOfPanel(this.getActivePanel());
18467 if (i >= this.tabs.length - 1 && !this.autoslide) {
18471 if (i >= this.tabs.length - 1 && this.autoslide) {
18475 this.showPanel(this.tabs[i+1]);
18478 showPanelPrev : function()
18480 var i = this.indexOfPanel(this.getActivePanel());
18482 if (i < 1 && !this.autoslide) {
18486 if (i < 1 && this.autoslide) {
18487 i = this.tabs.length;
18490 this.showPanel(this.tabs[i-1]);
18494 addBullet: function()
18496 if(!this.bullets || Roo.isTouch){
18499 var ctr = this.el.select('.carousel-bullets',true).first();
18500 var i = this.el.select('.carousel-bullets .bullet',true).getCount() ;
18501 var bullet = ctr.createChild({
18502 cls : 'bullet bullet-' + i
18503 },ctr.dom.lastChild);
18508 bullet.on('click', (function(e, el, o, ii, t){
18510 e.preventDefault();
18512 this.showPanel(ii);
18514 if(this.autoslide && this.slideFn){
18515 clearInterval(this.slideFn);
18516 this.slideFn = window.setInterval(function() {
18517 _this.showPanelNext();
18521 }).createDelegate(this, [i, bullet], true));
18526 setActiveBullet : function(i)
18532 Roo.each(this.el.select('.bullet', true).elements, function(el){
18533 el.removeClass('selected');
18536 var bullet = this.el.select('.bullet-' + i, true).first();
18542 bullet.addClass('selected');
18553 Roo.apply(Roo.bootstrap.TabGroup, {
18557 * register a Navigation Group
18558 * @param {Roo.bootstrap.NavGroup} the navgroup to add
18560 register : function(navgrp)
18562 this.groups[navgrp.navId] = navgrp;
18566 * fetch a Navigation Group based on the navigation ID
18567 * if one does not exist , it will get created.
18568 * @param {string} the navgroup to add
18569 * @returns {Roo.bootstrap.NavGroup} the navgroup
18571 get: function(navId) {
18572 if (typeof(this.groups[navId]) == 'undefined') {
18573 this.register(new Roo.bootstrap.TabGroup({ navId : navId }));
18575 return this.groups[navId] ;
18590 * @class Roo.bootstrap.TabPanel
18591 * @extends Roo.bootstrap.Component
18592 * Bootstrap TabPanel class
18593 * @cfg {Boolean} active panel active
18594 * @cfg {String} html panel content
18595 * @cfg {String} tabId unique tab ID (will be autogenerated if not set. - used to match TabItem to Panel)
18596 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
18597 * @cfg {String} href click to link..
18601 * Create a new TabPanel
18602 * @param {Object} config The config object
18605 Roo.bootstrap.TabPanel = function(config){
18606 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
18610 * Fires when the active status changes
18611 * @param {Roo.bootstrap.TabPanel} this
18612 * @param {Boolean} state the new state
18617 * @event beforedeactivate
18618 * Fires before a tab is de-activated - can be used to do validation on a form.
18619 * @param {Roo.bootstrap.TabPanel} this
18620 * @return {Boolean} false if there is an error
18623 'beforedeactivate': true
18626 this.tabId = this.tabId || Roo.id();
18630 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
18638 getAutoCreate : function(){
18643 // item is needed for carousel - not sure if it has any effect otherwise
18644 cls: 'carousel-item tab-pane item' + ((this.href.length) ? ' clickable ' : ''),
18645 html: this.html || ''
18649 cfg.cls += ' active';
18653 cfg.tabId = this.tabId;
18661 initEvents: function()
18663 var p = this.parent();
18665 this.navId = this.navId || p.navId;
18667 if (typeof(this.navId) != 'undefined') {
18668 // not really needed.. but just in case.. parent should be a NavGroup.
18669 var tg = Roo.bootstrap.TabGroup.get(this.navId);
18673 var i = tg.tabs.length - 1;
18675 if(this.active && tg.bullets > 0 && i < tg.bullets){
18676 tg.setActiveBullet(i);
18680 this.el.on('click', this.onClick, this);
18683 this.el.on("touchstart", this.onTouchStart, this);
18684 this.el.on("touchmove", this.onTouchMove, this);
18685 this.el.on("touchend", this.onTouchEnd, this);
18690 onRender : function(ct, position)
18692 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
18695 setActive : function(state)
18697 Roo.log("panel - set active " + this.tabId + "=" + state);
18699 this.active = state;
18701 this.el.removeClass('active');
18703 } else if (!this.el.hasClass('active')) {
18704 this.el.addClass('active');
18707 this.fireEvent('changed', this, state);
18710 onClick : function(e)
18712 e.preventDefault();
18714 if(!this.href.length){
18718 window.location.href = this.href;
18727 onTouchStart : function(e)
18729 this.swiping = false;
18731 this.startX = e.browserEvent.touches[0].clientX;
18732 this.startY = e.browserEvent.touches[0].clientY;
18735 onTouchMove : function(e)
18737 this.swiping = true;
18739 this.endX = e.browserEvent.touches[0].clientX;
18740 this.endY = e.browserEvent.touches[0].clientY;
18743 onTouchEnd : function(e)
18750 var tabGroup = this.parent();
18752 if(this.endX > this.startX){ // swiping right
18753 tabGroup.showPanelPrev();
18757 if(this.startX > this.endX){ // swiping left
18758 tabGroup.showPanelNext();
18777 * @class Roo.bootstrap.DateField
18778 * @extends Roo.bootstrap.Input
18779 * Bootstrap DateField class
18780 * @cfg {Number} weekStart default 0
18781 * @cfg {String} viewMode default empty, (months|years)
18782 * @cfg {String} minViewMode default empty, (months|years)
18783 * @cfg {Number} startDate default -Infinity
18784 * @cfg {Number} endDate default Infinity
18785 * @cfg {Boolean} todayHighlight default false
18786 * @cfg {Boolean} todayBtn default false
18787 * @cfg {Boolean} calendarWeeks default false
18788 * @cfg {Object} daysOfWeekDisabled default empty
18789 * @cfg {Boolean} singleMode default false (true | false)
18791 * @cfg {Boolean} keyboardNavigation default true
18792 * @cfg {String} language default en
18795 * Create a new DateField
18796 * @param {Object} config The config object
18799 Roo.bootstrap.DateField = function(config){
18800 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
18804 * Fires when this field show.
18805 * @param {Roo.bootstrap.DateField} this
18806 * @param {Mixed} date The date value
18811 * Fires when this field hide.
18812 * @param {Roo.bootstrap.DateField} this
18813 * @param {Mixed} date The date value
18818 * Fires when select a date.
18819 * @param {Roo.bootstrap.DateField} this
18820 * @param {Mixed} date The date value
18824 * @event beforeselect
18825 * Fires when before select a date.
18826 * @param {Roo.bootstrap.DateField} this
18827 * @param {Mixed} date The date value
18829 beforeselect : true
18833 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
18836 * @cfg {String} format
18837 * The default date format string which can be overriden for localization support. The format must be
18838 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
18842 * @cfg {String} altFormats
18843 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
18844 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
18846 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
18854 todayHighlight : false,
18860 keyboardNavigation: true,
18862 calendarWeeks: false,
18864 startDate: -Infinity,
18868 daysOfWeekDisabled: [],
18872 singleMode : false,
18874 UTCDate: function()
18876 return new Date(Date.UTC.apply(Date, arguments));
18879 UTCToday: function()
18881 var today = new Date();
18882 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
18885 getDate: function() {
18886 var d = this.getUTCDate();
18887 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
18890 getUTCDate: function() {
18894 setDate: function(d) {
18895 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
18898 setUTCDate: function(d) {
18900 this.setValue(this.formatDate(this.date));
18903 onRender: function(ct, position)
18906 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
18908 this.language = this.language || 'en';
18909 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
18910 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
18912 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
18913 this.format = this.format || 'm/d/y';
18914 this.isInline = false;
18915 this.isInput = true;
18916 this.component = this.el.select('.add-on', true).first() || false;
18917 this.component = (this.component && this.component.length === 0) ? false : this.component;
18918 this.hasInput = this.component && this.inputEl().length;
18920 if (typeof(this.minViewMode === 'string')) {
18921 switch (this.minViewMode) {
18923 this.minViewMode = 1;
18926 this.minViewMode = 2;
18929 this.minViewMode = 0;
18934 if (typeof(this.viewMode === 'string')) {
18935 switch (this.viewMode) {
18948 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.DateField.template);
18950 // this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
18952 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
18954 this.picker().on('mousedown', this.onMousedown, this);
18955 this.picker().on('click', this.onClick, this);
18957 this.picker().addClass('datepicker-dropdown');
18959 this.startViewMode = this.viewMode;
18961 if(this.singleMode){
18962 Roo.each(this.picker().select('thead > tr > th', true).elements, function(v){
18963 v.setVisibilityMode(Roo.Element.DISPLAY);
18967 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
18968 v.setStyle('width', '189px');
18972 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
18973 if(!this.calendarWeeks){
18978 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
18979 v.attr('colspan', function(i, val){
18980 return parseInt(val) + 1;
18985 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
18987 this.setStartDate(this.startDate);
18988 this.setEndDate(this.endDate);
18990 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
18997 if(this.isInline) {
19002 picker : function()
19004 return this.pickerEl;
19005 // return this.el.select('.datepicker', true).first();
19008 fillDow: function()
19010 var dowCnt = this.weekStart;
19019 if(this.calendarWeeks){
19027 while (dowCnt < this.weekStart + 7) {
19031 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
19035 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
19038 fillMonths: function()
19041 var months = this.picker().select('>.datepicker-months td', true).first();
19043 months.dom.innerHTML = '';
19049 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
19052 months.createChild(month);
19059 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;
19061 if (this.date < this.startDate) {
19062 this.viewDate = new Date(this.startDate);
19063 } else if (this.date > this.endDate) {
19064 this.viewDate = new Date(this.endDate);
19066 this.viewDate = new Date(this.date);
19074 var d = new Date(this.viewDate),
19075 year = d.getUTCFullYear(),
19076 month = d.getUTCMonth(),
19077 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
19078 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
19079 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
19080 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
19081 currentDate = this.date && this.date.valueOf(),
19082 today = this.UTCToday();
19084 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
19086 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
19088 // this.picker.select('>tfoot th.today').
19089 // .text(dates[this.language].today)
19090 // .toggle(this.todayBtn !== false);
19092 this.updateNavArrows();
19095 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
19097 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
19099 prevMonth.setUTCDate(day);
19101 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
19103 var nextMonth = new Date(prevMonth);
19105 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
19107 nextMonth = nextMonth.valueOf();
19109 var fillMonths = false;
19111 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
19113 while(prevMonth.valueOf() <= nextMonth) {
19116 if (prevMonth.getUTCDay() === this.weekStart) {
19118 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
19126 if(this.calendarWeeks){
19127 // ISO 8601: First week contains first thursday.
19128 // ISO also states week starts on Monday, but we can be more abstract here.
19130 // Start of current week: based on weekstart/current date
19131 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
19132 // Thursday of this week
19133 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
19134 // First Thursday of year, year from thursday
19135 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
19136 // Calendar week: ms between thursdays, div ms per day, div 7 days
19137 calWeek = (th - yth) / 864e5 / 7 + 1;
19139 fillMonths.cn.push({
19147 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
19149 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
19152 if (this.todayHighlight &&
19153 prevMonth.getUTCFullYear() == today.getFullYear() &&
19154 prevMonth.getUTCMonth() == today.getMonth() &&
19155 prevMonth.getUTCDate() == today.getDate()) {
19156 clsName += ' today';
19159 if (currentDate && prevMonth.valueOf() === currentDate) {
19160 clsName += ' active';
19163 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
19164 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
19165 clsName += ' disabled';
19168 fillMonths.cn.push({
19170 cls: 'day ' + clsName,
19171 html: prevMonth.getDate()
19174 prevMonth.setDate(prevMonth.getDate()+1);
19177 var currentYear = this.date && this.date.getUTCFullYear();
19178 var currentMonth = this.date && this.date.getUTCMonth();
19180 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
19182 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
19183 v.removeClass('active');
19185 if(currentYear === year && k === currentMonth){
19186 v.addClass('active');
19189 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
19190 v.addClass('disabled');
19196 year = parseInt(year/10, 10) * 10;
19198 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
19200 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
19203 for (var i = -1; i < 11; i++) {
19204 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
19206 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
19214 showMode: function(dir)
19217 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
19220 Roo.each(this.picker().select('>div',true).elements, function(v){
19221 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19224 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
19229 if(this.isInline) {
19233 this.picker().removeClass(['bottom', 'top']);
19235 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
19237 * place to the top of element!
19241 this.picker().addClass('top');
19242 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
19247 this.picker().addClass('bottom');
19249 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
19252 parseDate : function(value)
19254 if(!value || value instanceof Date){
19257 var v = Date.parseDate(value, this.format);
19258 if (!v && (this.useIso || value.match(/^(\d{4})-0?(\d+)-0?(\d+)/))) {
19259 v = Date.parseDate(value, 'Y-m-d');
19261 if(!v && this.altFormats){
19262 if(!this.altFormatsArray){
19263 this.altFormatsArray = this.altFormats.split("|");
19265 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
19266 v = Date.parseDate(value, this.altFormatsArray[i]);
19272 formatDate : function(date, fmt)
19274 return (!date || !(date instanceof Date)) ?
19275 date : date.dateFormat(fmt || this.format);
19278 onFocus : function()
19280 Roo.bootstrap.DateField.superclass.onFocus.call(this);
19284 onBlur : function()
19286 Roo.bootstrap.DateField.superclass.onBlur.call(this);
19288 var d = this.inputEl().getValue();
19295 showPopup : function()
19297 this.picker().show();
19301 this.fireEvent('showpopup', this, this.date);
19304 hidePopup : function()
19306 if(this.isInline) {
19309 this.picker().hide();
19310 this.viewMode = this.startViewMode;
19313 this.fireEvent('hidepopup', this, this.date);
19317 onMousedown: function(e)
19319 e.stopPropagation();
19320 e.preventDefault();
19325 Roo.bootstrap.DateField.superclass.keyup.call(this);
19329 setValue: function(v)
19331 if(this.fireEvent('beforeselect', this, v) !== false){
19332 var d = new Date(this.parseDate(v) ).clearTime();
19334 if(isNaN(d.getTime())){
19335 this.date = this.viewDate = '';
19336 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19340 v = this.formatDate(d);
19342 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
19344 this.date = new Date(d.getTime() - d.getTimezoneOffset()*60000);
19348 this.fireEvent('select', this, this.date);
19352 getValue: function()
19354 return this.formatDate(this.date);
19357 fireKey: function(e)
19359 if (!this.picker().isVisible()){
19360 if (e.keyCode == 27) { // allow escape to hide and re-show picker
19366 var dateChanged = false,
19368 newDate, newViewDate;
19373 e.preventDefault();
19377 if (!this.keyboardNavigation) {
19380 dir = e.keyCode == 37 ? -1 : 1;
19383 newDate = this.moveYear(this.date, dir);
19384 newViewDate = this.moveYear(this.viewDate, dir);
19385 } else if (e.shiftKey){
19386 newDate = this.moveMonth(this.date, dir);
19387 newViewDate = this.moveMonth(this.viewDate, dir);
19389 newDate = new Date(this.date);
19390 newDate.setUTCDate(this.date.getUTCDate() + dir);
19391 newViewDate = new Date(this.viewDate);
19392 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
19394 if (this.dateWithinRange(newDate)){
19395 this.date = newDate;
19396 this.viewDate = newViewDate;
19397 this.setValue(this.formatDate(this.date));
19399 e.preventDefault();
19400 dateChanged = true;
19405 if (!this.keyboardNavigation) {
19408 dir = e.keyCode == 38 ? -1 : 1;
19410 newDate = this.moveYear(this.date, dir);
19411 newViewDate = this.moveYear(this.viewDate, dir);
19412 } else if (e.shiftKey){
19413 newDate = this.moveMonth(this.date, dir);
19414 newViewDate = this.moveMonth(this.viewDate, dir);
19416 newDate = new Date(this.date);
19417 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
19418 newViewDate = new Date(this.viewDate);
19419 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
19421 if (this.dateWithinRange(newDate)){
19422 this.date = newDate;
19423 this.viewDate = newViewDate;
19424 this.setValue(this.formatDate(this.date));
19426 e.preventDefault();
19427 dateChanged = true;
19431 this.setValue(this.formatDate(this.date));
19433 e.preventDefault();
19436 this.setValue(this.formatDate(this.date));
19450 onClick: function(e)
19452 e.stopPropagation();
19453 e.preventDefault();
19455 var target = e.getTarget();
19457 if(target.nodeName.toLowerCase() === 'i'){
19458 target = Roo.get(target).dom.parentNode;
19461 var nodeName = target.nodeName;
19462 var className = target.className;
19463 var html = target.innerHTML;
19464 //Roo.log(nodeName);
19466 switch(nodeName.toLowerCase()) {
19468 switch(className) {
19474 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
19475 switch(this.viewMode){
19477 this.viewDate = this.moveMonth(this.viewDate, dir);
19481 this.viewDate = this.moveYear(this.viewDate, dir);
19487 var date = new Date();
19488 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
19490 this.setValue(this.formatDate(this.date));
19497 if (className.indexOf('disabled') < 0) {
19498 this.viewDate.setUTCDate(1);
19499 if (className.indexOf('month') > -1) {
19500 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
19502 var year = parseInt(html, 10) || 0;
19503 this.viewDate.setUTCFullYear(year);
19507 if(this.singleMode){
19508 this.setValue(this.formatDate(this.viewDate));
19519 //Roo.log(className);
19520 if (className.indexOf('day') > -1 && className.indexOf('disabled') < 0 ){
19521 var day = parseInt(html, 10) || 1;
19522 var year = this.viewDate.getUTCFullYear(),
19523 month = this.viewDate.getUTCMonth();
19525 if (className.indexOf('old') > -1) {
19532 } else if (className.indexOf('new') > -1) {
19540 //Roo.log([year,month,day]);
19541 this.date = this.UTCDate(year, month, day,0,0,0,0);
19542 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
19544 //Roo.log(this.formatDate(this.date));
19545 this.setValue(this.formatDate(this.date));
19552 setStartDate: function(startDate)
19554 this.startDate = startDate || -Infinity;
19555 if (this.startDate !== -Infinity) {
19556 this.startDate = this.parseDate(this.startDate);
19559 this.updateNavArrows();
19562 setEndDate: function(endDate)
19564 this.endDate = endDate || Infinity;
19565 if (this.endDate !== Infinity) {
19566 this.endDate = this.parseDate(this.endDate);
19569 this.updateNavArrows();
19572 setDaysOfWeekDisabled: function(daysOfWeekDisabled)
19574 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
19575 if (typeof(this.daysOfWeekDisabled) !== 'object') {
19576 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
19578 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
19579 return parseInt(d, 10);
19582 this.updateNavArrows();
19585 updateNavArrows: function()
19587 if(this.singleMode){
19591 var d = new Date(this.viewDate),
19592 year = d.getUTCFullYear(),
19593 month = d.getUTCMonth();
19595 Roo.each(this.picker().select('.prev', true).elements, function(v){
19597 switch (this.viewMode) {
19600 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
19606 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
19613 Roo.each(this.picker().select('.next', true).elements, function(v){
19615 switch (this.viewMode) {
19618 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
19624 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
19632 moveMonth: function(date, dir)
19637 var new_date = new Date(date.valueOf()),
19638 day = new_date.getUTCDate(),
19639 month = new_date.getUTCMonth(),
19640 mag = Math.abs(dir),
19642 dir = dir > 0 ? 1 : -1;
19645 // If going back one month, make sure month is not current month
19646 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
19648 return new_date.getUTCMonth() == month;
19650 // If going forward one month, make sure month is as expected
19651 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
19653 return new_date.getUTCMonth() != new_month;
19655 new_month = month + dir;
19656 new_date.setUTCMonth(new_month);
19657 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
19658 if (new_month < 0 || new_month > 11) {
19659 new_month = (new_month + 12) % 12;
19662 // For magnitudes >1, move one month at a time...
19663 for (var i=0; i<mag; i++) {
19664 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
19665 new_date = this.moveMonth(new_date, dir);
19667 // ...then reset the day, keeping it in the new month
19668 new_month = new_date.getUTCMonth();
19669 new_date.setUTCDate(day);
19671 return new_month != new_date.getUTCMonth();
19674 // Common date-resetting loop -- if date is beyond end of month, make it
19677 new_date.setUTCDate(--day);
19678 new_date.setUTCMonth(new_month);
19683 moveYear: function(date, dir)
19685 return this.moveMonth(date, dir*12);
19688 dateWithinRange: function(date)
19690 return date >= this.startDate && date <= this.endDate;
19696 this.picker().remove();
19699 validateValue : function(value)
19701 if(this.getVisibilityEl().hasClass('hidden')){
19705 if(value.length < 1) {
19706 if(this.allowBlank){
19712 if(value.length < this.minLength){
19715 if(value.length > this.maxLength){
19719 var vt = Roo.form.VTypes;
19720 if(!vt[this.vtype](value, this)){
19724 if(typeof this.validator == "function"){
19725 var msg = this.validator(value);
19731 if(this.regex && !this.regex.test(value)){
19735 if(typeof(this.parseDate(value)) == 'undefined'){
19739 if (this.endDate !== Infinity && this.parseDate(value).getTime() > this.endDate.getTime()) {
19743 if (this.startDate !== -Infinity && this.parseDate(value).getTime() < this.startDate.getTime()) {
19753 this.date = this.viewDate = '';
19755 Roo.bootstrap.DateField.superclass.setValue.call(this, '');
19760 Roo.apply(Roo.bootstrap.DateField, {
19771 html: '<i class="fa fa-arrow-left"/>'
19781 html: '<i class="fa fa-arrow-right"/>'
19823 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
19824 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
19825 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
19826 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
19827 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
19840 navFnc: 'FullYear',
19845 navFnc: 'FullYear',
19850 Roo.apply(Roo.bootstrap.DateField, {
19854 cls: 'datepicker dropdown-menu roo-dynamic',
19858 cls: 'datepicker-days',
19862 cls: 'table-condensed',
19864 Roo.bootstrap.DateField.head,
19868 Roo.bootstrap.DateField.footer
19875 cls: 'datepicker-months',
19879 cls: 'table-condensed',
19881 Roo.bootstrap.DateField.head,
19882 Roo.bootstrap.DateField.content,
19883 Roo.bootstrap.DateField.footer
19890 cls: 'datepicker-years',
19894 cls: 'table-condensed',
19896 Roo.bootstrap.DateField.head,
19897 Roo.bootstrap.DateField.content,
19898 Roo.bootstrap.DateField.footer
19917 * @class Roo.bootstrap.TimeField
19918 * @extends Roo.bootstrap.Input
19919 * Bootstrap DateField class
19923 * Create a new TimeField
19924 * @param {Object} config The config object
19927 Roo.bootstrap.TimeField = function(config){
19928 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
19932 * Fires when this field show.
19933 * @param {Roo.bootstrap.DateField} thisthis
19934 * @param {Mixed} date The date value
19939 * Fires when this field hide.
19940 * @param {Roo.bootstrap.DateField} this
19941 * @param {Mixed} date The date value
19946 * Fires when select a date.
19947 * @param {Roo.bootstrap.DateField} this
19948 * @param {Mixed} date The date value
19954 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
19957 * @cfg {String} format
19958 * The default time format string which can be overriden for localization support. The format must be
19959 * valid according to {@link Date#parseDate} (defaults to 'H:i').
19963 onRender: function(ct, position)
19966 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
19968 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
19970 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19972 this.pop = this.picker().select('>.datepicker-time',true).first();
19973 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
19975 this.picker().on('mousedown', this.onMousedown, this);
19976 this.picker().on('click', this.onClick, this);
19978 this.picker().addClass('datepicker-dropdown');
19983 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
19984 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
19985 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
19986 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
19987 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
19988 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
19992 fireKey: function(e){
19993 if (!this.picker().isVisible()){
19994 if (e.keyCode == 27) { // allow escape to hide and re-show picker
20000 e.preventDefault();
20008 this.onTogglePeriod();
20011 this.onIncrementMinutes();
20014 this.onDecrementMinutes();
20023 onClick: function(e) {
20024 e.stopPropagation();
20025 e.preventDefault();
20028 picker : function()
20030 return this.el.select('.datepicker', true).first();
20033 fillTime: function()
20035 var time = this.pop.select('tbody', true).first();
20037 time.dom.innerHTML = '';
20052 cls: 'hours-up glyphicon glyphicon-chevron-up'
20072 cls: 'minutes-up glyphicon glyphicon-chevron-up'
20093 cls: 'timepicker-hour',
20108 cls: 'timepicker-minute',
20123 cls: 'btn btn-primary period',
20145 cls: 'hours-down glyphicon glyphicon-chevron-down'
20165 cls: 'minutes-down glyphicon glyphicon-chevron-down'
20183 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
20190 var hours = this.time.getHours();
20191 var minutes = this.time.getMinutes();
20204 hours = hours - 12;
20208 hours = '0' + hours;
20212 minutes = '0' + minutes;
20215 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
20216 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
20217 this.pop.select('button', true).first().dom.innerHTML = period;
20223 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
20225 var cls = ['bottom'];
20227 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
20234 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
20239 this.picker().addClass(cls.join('-'));
20243 Roo.each(cls, function(c){
20245 _this.picker().setTop(_this.inputEl().getHeight());
20249 _this.picker().setTop(0 - _this.picker().getHeight());
20254 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
20258 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
20265 onFocus : function()
20267 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
20271 onBlur : function()
20273 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
20279 this.picker().show();
20284 this.fireEvent('show', this, this.date);
20289 this.picker().hide();
20292 this.fireEvent('hide', this, this.date);
20295 setTime : function()
20298 this.setValue(this.time.format(this.format));
20300 this.fireEvent('select', this, this.date);
20305 onMousedown: function(e){
20306 e.stopPropagation();
20307 e.preventDefault();
20310 onIncrementHours: function()
20312 Roo.log('onIncrementHours');
20313 this.time = this.time.add(Date.HOUR, 1);
20318 onDecrementHours: function()
20320 Roo.log('onDecrementHours');
20321 this.time = this.time.add(Date.HOUR, -1);
20325 onIncrementMinutes: function()
20327 Roo.log('onIncrementMinutes');
20328 this.time = this.time.add(Date.MINUTE, 1);
20332 onDecrementMinutes: function()
20334 Roo.log('onDecrementMinutes');
20335 this.time = this.time.add(Date.MINUTE, -1);
20339 onTogglePeriod: function()
20341 Roo.log('onTogglePeriod');
20342 this.time = this.time.add(Date.HOUR, 12);
20349 Roo.apply(Roo.bootstrap.TimeField, {
20379 cls: 'btn btn-info ok',
20391 Roo.apply(Roo.bootstrap.TimeField, {
20395 cls: 'datepicker dropdown-menu',
20399 cls: 'datepicker-time',
20403 cls: 'table-condensed',
20405 Roo.bootstrap.TimeField.content,
20406 Roo.bootstrap.TimeField.footer
20425 * @class Roo.bootstrap.MonthField
20426 * @extends Roo.bootstrap.Input
20427 * Bootstrap MonthField class
20429 * @cfg {String} language default en
20432 * Create a new MonthField
20433 * @param {Object} config The config object
20436 Roo.bootstrap.MonthField = function(config){
20437 Roo.bootstrap.MonthField.superclass.constructor.call(this, config);
20442 * Fires when this field show.
20443 * @param {Roo.bootstrap.MonthField} this
20444 * @param {Mixed} date The date value
20449 * Fires when this field hide.
20450 * @param {Roo.bootstrap.MonthField} this
20451 * @param {Mixed} date The date value
20456 * Fires when select a date.
20457 * @param {Roo.bootstrap.MonthField} this
20458 * @param {String} oldvalue The old value
20459 * @param {String} newvalue The new value
20465 Roo.extend(Roo.bootstrap.MonthField, Roo.bootstrap.Input, {
20467 onRender: function(ct, position)
20470 Roo.bootstrap.MonthField.superclass.onRender.call(this, ct, position);
20472 this.language = this.language || 'en';
20473 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : this.language.split('-')[0];
20474 this.language = this.language in Roo.bootstrap.MonthField.dates ? this.language : "en";
20476 this.isRTL = Roo.bootstrap.MonthField.dates[this.language].rtl || false;
20477 this.isInline = false;
20478 this.isInput = true;
20479 this.component = this.el.select('.add-on', true).first() || false;
20480 this.component = (this.component && this.component.length === 0) ? false : this.component;
20481 this.hasInput = this.component && this.inputEL().length;
20483 this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.MonthField.template);
20485 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
20487 this.picker().on('mousedown', this.onMousedown, this);
20488 this.picker().on('click', this.onClick, this);
20490 this.picker().addClass('datepicker-dropdown');
20492 Roo.each(this.picker().select('tbody > tr > td', true).elements, function(v){
20493 v.setStyle('width', '189px');
20500 if(this.isInline) {
20506 setValue: function(v, suppressEvent)
20508 var o = this.getValue();
20510 Roo.bootstrap.MonthField.superclass.setValue.call(this, v);
20514 if(suppressEvent !== true){
20515 this.fireEvent('select', this, o, v);
20520 getValue: function()
20525 onClick: function(e)
20527 e.stopPropagation();
20528 e.preventDefault();
20530 var target = e.getTarget();
20532 if(target.nodeName.toLowerCase() === 'i'){
20533 target = Roo.get(target).dom.parentNode;
20536 var nodeName = target.nodeName;
20537 var className = target.className;
20538 var html = target.innerHTML;
20540 if(nodeName.toLowerCase() != 'span' || className.indexOf('disabled') > -1 || className.indexOf('month') == -1){
20544 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].monthsShort.indexOf(html);
20546 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20552 picker : function()
20554 return this.pickerEl;
20557 fillMonths: function()
20560 var months = this.picker().select('>.datepicker-months td', true).first();
20562 months.dom.innerHTML = '';
20568 html: Roo.bootstrap.MonthField.dates[this.language].monthsShort[i++]
20571 months.createChild(month);
20580 if(typeof(this.vIndex) == 'undefined' && this.value.length){
20581 this.vIndex = Roo.bootstrap.MonthField.dates[this.language].months.indexOf(this.value);
20584 Roo.each(this.pickerEl.select('> .datepicker-months tbody > tr > td > span', true).elements, function(e, k){
20585 e.removeClass('active');
20587 if(typeof(_this.vIndex) != 'undefined' && k == _this.vIndex){
20588 e.addClass('active');
20595 if(this.isInline) {
20599 this.picker().removeClass(['bottom', 'top']);
20601 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
20603 * place to the top of element!
20607 this.picker().addClass('top');
20608 this.picker().setTop(this.inputEl().getTop() - this.picker().getHeight()).setLeft(this.inputEl().getLeft());
20613 this.picker().addClass('bottom');
20615 this.picker().setTop(this.inputEl().getBottom()).setLeft(this.inputEl().getLeft());
20618 onFocus : function()
20620 Roo.bootstrap.MonthField.superclass.onFocus.call(this);
20624 onBlur : function()
20626 Roo.bootstrap.MonthField.superclass.onBlur.call(this);
20628 var d = this.inputEl().getValue();
20637 this.picker().show();
20638 this.picker().select('>.datepicker-months', true).first().show();
20642 this.fireEvent('show', this, this.date);
20647 if(this.isInline) {
20650 this.picker().hide();
20651 this.fireEvent('hide', this, this.date);
20655 onMousedown: function(e)
20657 e.stopPropagation();
20658 e.preventDefault();
20663 Roo.bootstrap.MonthField.superclass.keyup.call(this);
20667 fireKey: function(e)
20669 if (!this.picker().isVisible()){
20670 if (e.keyCode == 27) {// allow escape to hide and re-show picker
20681 e.preventDefault();
20685 dir = e.keyCode == 37 ? -1 : 1;
20687 this.vIndex = this.vIndex + dir;
20689 if(this.vIndex < 0){
20693 if(this.vIndex > 11){
20697 if(isNaN(this.vIndex)){
20701 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20707 dir = e.keyCode == 38 ? -1 : 1;
20709 this.vIndex = this.vIndex + dir * 4;
20711 if(this.vIndex < 0){
20715 if(this.vIndex > 11){
20719 if(isNaN(this.vIndex)){
20723 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20728 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20729 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20733 e.preventDefault();
20736 if(typeof(this.vIndex) != 'undefined' && !isNaN(this.vIndex)){
20737 this.setValue(Roo.bootstrap.MonthField.dates[this.language].months[this.vIndex]);
20753 this.picker().remove();
20758 Roo.apply(Roo.bootstrap.MonthField, {
20777 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
20778 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
20783 Roo.apply(Roo.bootstrap.MonthField, {
20787 cls: 'datepicker dropdown-menu roo-dynamic',
20791 cls: 'datepicker-months',
20795 cls: 'table-condensed',
20797 Roo.bootstrap.DateField.content
20817 * @class Roo.bootstrap.CheckBox
20818 * @extends Roo.bootstrap.Input
20819 * Bootstrap CheckBox class
20821 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
20822 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
20823 * @cfg {String} boxLabel The text that appears beside the checkbox
20824 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
20825 * @cfg {Boolean} checked initnal the element
20826 * @cfg {Boolean} inline inline the element (default false)
20827 * @cfg {String} groupId the checkbox group id // normal just use for checkbox
20828 * @cfg {String} tooltip label tooltip
20831 * Create a new CheckBox
20832 * @param {Object} config The config object
20835 Roo.bootstrap.CheckBox = function(config){
20836 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
20841 * Fires when the element is checked or unchecked.
20842 * @param {Roo.bootstrap.CheckBox} this This input
20843 * @param {Boolean} checked The new checked value
20848 * Fires when the element is click.
20849 * @param {Roo.bootstrap.CheckBox} this This input
20856 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
20858 inputType: 'checkbox',
20867 getAutoCreate : function()
20869 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
20875 cfg.cls = 'form-group ' + this.inputType; //input-group
20878 cfg.cls += ' ' + this.inputType + '-inline';
20884 type : this.inputType,
20885 value : this.inputValue,
20886 cls : 'roo-' + this.inputType, //'form-box',
20887 placeholder : this.placeholder || ''
20891 if(this.inputType != 'radio'){
20895 cls : 'roo-hidden-value',
20896 value : this.checked ? this.inputValue : this.valueOff
20901 if (this.weight) { // Validity check?
20902 cfg.cls += " " + this.inputType + "-" + this.weight;
20905 if (this.disabled) {
20906 input.disabled=true;
20910 input.checked = this.checked;
20915 input.name = this.name;
20917 if(this.inputType != 'radio'){
20918 hidden.name = this.name;
20919 input.name = '_hidden_' + this.name;
20924 input.cls += ' input-' + this.size;
20929 ['xs','sm','md','lg'].map(function(size){
20930 if (settings[size]) {
20931 cfg.cls += ' col-' + size + '-' + settings[size];
20935 var inputblock = input;
20937 if (this.before || this.after) {
20940 cls : 'input-group',
20945 inputblock.cn.push({
20947 cls : 'input-group-addon',
20952 inputblock.cn.push(input);
20954 if(this.inputType != 'radio'){
20955 inputblock.cn.push(hidden);
20959 inputblock.cn.push({
20961 cls : 'input-group-addon',
20968 if (align ==='left' && this.fieldLabel.length) {
20969 // Roo.log("left and has label");
20974 cls : 'control-label',
20975 html : this.fieldLabel
20985 if(this.labelWidth > 12){
20986 cfg.cn[0].style = "width: " + this.labelWidth + 'px';
20989 if(this.labelWidth < 13 && this.labelmd == 0){
20990 this.labelmd = this.labelWidth;
20993 if(this.labellg > 0){
20994 cfg.cn[0].cls += ' col-lg-' + this.labellg;
20995 cfg.cn[1].cls += ' col-lg-' + (12 - this.labellg);
20998 if(this.labelmd > 0){
20999 cfg.cn[0].cls += ' col-md-' + this.labelmd;
21000 cfg.cn[1].cls += ' col-md-' + (12 - this.labelmd);
21003 if(this.labelsm > 0){
21004 cfg.cn[0].cls += ' col-sm-' + this.labelsm;
21005 cfg.cn[1].cls += ' col-sm-' + (12 - this.labelsm);
21008 if(this.labelxs > 0){
21009 cfg.cn[0].cls += ' col-xs-' + this.labelxs;
21010 cfg.cn[1].cls += ' col-xs-' + (12 - this.labelxs);
21013 } else if ( this.fieldLabel.length) {
21014 // Roo.log(" label");
21018 tag: this.boxLabel ? 'span' : 'label',
21020 cls: 'control-label box-input-label',
21021 //cls : 'input-group-addon',
21022 html : this.fieldLabel
21031 // Roo.log(" no label && no align");
21032 cfg.cn = [ inputblock ] ;
21038 var boxLabelCfg = {
21040 //'for': id, // box label is handled by onclick - so no for...
21042 html: this.boxLabel
21046 boxLabelCfg.tooltip = this.tooltip;
21049 cfg.cn.push(boxLabelCfg);
21052 if(this.inputType != 'radio'){
21053 cfg.cn.push(hidden);
21061 * return the real input element.
21063 inputEl: function ()
21065 return this.el.select('input.roo-' + this.inputType,true).first();
21067 hiddenEl: function ()
21069 return this.el.select('input.roo-hidden-value',true).first();
21072 labelEl: function()
21074 return this.el.select('label.control-label',true).first();
21076 /* depricated... */
21080 return this.labelEl();
21083 boxLabelEl: function()
21085 return this.el.select('label.box-label',true).first();
21088 initEvents : function()
21090 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
21092 this.inputEl().on('click', this.onClick, this);
21094 if (this.boxLabel) {
21095 this.el.select('label.box-label',true).first().on('click', this.onClick, this);
21098 this.startValue = this.getValue();
21101 Roo.bootstrap.CheckBox.register(this);
21105 onClick : function(e)
21107 if(this.fireEvent('click', this, e) !== false){
21108 this.setChecked(!this.checked);
21113 setChecked : function(state,suppressEvent)
21115 this.startValue = this.getValue();
21117 if(this.inputType == 'radio'){
21119 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21120 e.dom.checked = false;
21123 this.inputEl().dom.checked = true;
21125 this.inputEl().dom.value = this.inputValue;
21127 if(suppressEvent !== true){
21128 this.fireEvent('check', this, true);
21136 this.checked = state;
21138 this.inputEl().dom.checked = state;
21141 this.hiddenEl().dom.value = state ? this.inputValue : this.valueOff;
21143 if(suppressEvent !== true){
21144 this.fireEvent('check', this, state);
21150 getValue : function()
21152 if(this.inputType == 'radio'){
21153 return this.getGroupValue();
21156 return this.hiddenEl().dom.value;
21160 getGroupValue : function()
21162 if(typeof(this.el.up('form').child('input[name='+this.name+']:checked', true)) == 'undefined'){
21166 return this.el.up('form').child('input[name='+this.name+']:checked', true).value;
21169 setValue : function(v,suppressEvent)
21171 if(this.inputType == 'radio'){
21172 this.setGroupValue(v, suppressEvent);
21176 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
21181 setGroupValue : function(v, suppressEvent)
21183 this.startValue = this.getValue();
21185 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21186 e.dom.checked = false;
21188 if(e.dom.value == v){
21189 e.dom.checked = true;
21193 if(suppressEvent !== true){
21194 this.fireEvent('check', this, true);
21202 validate : function()
21204 if(this.getVisibilityEl().hasClass('hidden')){
21210 (this.inputType == 'radio' && this.validateRadio()) ||
21211 (this.inputType == 'checkbox' && this.validateCheckbox())
21217 this.markInvalid();
21221 validateRadio : function()
21223 if(this.getVisibilityEl().hasClass('hidden')){
21227 if(this.allowBlank){
21233 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21234 if(!e.dom.checked){
21246 validateCheckbox : function()
21249 return (this.getValue() == this.inputValue || this.allowBlank) ? true : false;
21250 //return (this.getValue() == this.inputValue) ? true : false;
21253 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21261 for(var i in group){
21262 if(group[i].el.isVisible(true)){
21270 for(var i in group){
21275 r = (group[i].getValue() == group[i].inputValue) ? true : false;
21282 * Mark this field as valid
21284 markValid : function()
21288 this.fireEvent('valid', this);
21290 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21293 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21300 if(this.inputType == 'radio'){
21301 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21302 var fg = e.findParent('.form-group', false, true);
21303 if (Roo.bootstrap.version == 3) {
21304 fg.removeClass([_this.invalidClass, _this.validClass]);
21305 fg.addClass(_this.validClass);
21307 fg.removeClass(['is-valid', 'is-invalid']);
21308 fg.addClass('is-valid');
21316 var fg = this.el.findParent('.form-group', false, true);
21317 if (Roo.bootstrap.version == 3) {
21318 fg.removeClass([this.invalidClass, this.validClass]);
21319 fg.addClass(this.validClass);
21321 fg.removeClass(['is-valid', 'is-invalid']);
21322 fg.addClass('is-valid');
21327 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21333 for(var i in group){
21334 var fg = group[i].el.findParent('.form-group', false, true);
21335 if (Roo.bootstrap.version == 3) {
21336 fg.removeClass([this.invalidClass, this.validClass]);
21337 fg.addClass(this.validClass);
21339 fg.removeClass(['is-valid', 'is-invalid']);
21340 fg.addClass('is-valid');
21346 * Mark this field as invalid
21347 * @param {String} msg The validation message
21349 markInvalid : function(msg)
21351 if(this.allowBlank){
21357 this.fireEvent('invalid', this, msg);
21359 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21362 label = Roo.bootstrap.FieldLabel.get(this.groupId + '-group');
21366 label.markInvalid();
21369 if(this.inputType == 'radio'){
21371 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21372 var fg = e.findParent('.form-group', false, true);
21373 if (Roo.bootstrap.version == 3) {
21374 fg.removeClass([_this.invalidClass, _this.validClass]);
21375 fg.addClass(_this.invalidClass);
21377 fg.removeClass(['is-invalid', 'is-valid']);
21378 fg.addClass('is-invalid');
21386 var fg = this.el.findParent('.form-group', false, true);
21387 if (Roo.bootstrap.version == 3) {
21388 fg.removeClass([_this.invalidClass, _this.validClass]);
21389 fg.addClass(_this.invalidClass);
21391 fg.removeClass(['is-invalid', 'is-valid']);
21392 fg.addClass('is-invalid');
21397 var group = Roo.bootstrap.CheckBox.get(this.groupId);
21403 for(var i in group){
21404 var fg = group[i].el.findParent('.form-group', false, true);
21405 if (Roo.bootstrap.version == 3) {
21406 fg.removeClass([_this.invalidClass, _this.validClass]);
21407 fg.addClass(_this.invalidClass);
21409 fg.removeClass(['is-invalid', 'is-valid']);
21410 fg.addClass('is-invalid');
21416 clearInvalid : function()
21418 Roo.bootstrap.Input.prototype.clearInvalid.call(this);
21420 // this.el.findParent('.form-group', false, true).removeClass([this.invalidClass, this.validClass]);
21422 var label = Roo.bootstrap.FieldLabel.get(this.name + '-group');
21424 if (label && label.iconEl) {
21425 label.iconEl.removeClass([ label.validClass, label.invalidClass ]);
21426 label.iconEl.removeClass(['is-invalid', 'is-valid']);
21430 disable : function()
21432 if(this.inputType != 'radio'){
21433 Roo.bootstrap.CheckBox.superclass.disable.call(this);
21440 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21441 _this.getActionEl().addClass(this.disabledClass);
21442 e.dom.disabled = true;
21446 this.disabled = true;
21447 this.fireEvent("disable", this);
21451 enable : function()
21453 if(this.inputType != 'radio'){
21454 Roo.bootstrap.CheckBox.superclass.enable.call(this);
21461 Roo.each(this.el.up('form').select('input[name='+this.name+']', true).elements, function(e){
21462 _this.getActionEl().removeClass(this.disabledClass);
21463 e.dom.disabled = false;
21467 this.disabled = false;
21468 this.fireEvent("enable", this);
21472 setBoxLabel : function(v)
21477 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21483 Roo.apply(Roo.bootstrap.CheckBox, {
21488 * register a CheckBox Group
21489 * @param {Roo.bootstrap.CheckBox} the CheckBox to add
21491 register : function(checkbox)
21493 if(typeof(this.groups[checkbox.groupId]) == 'undefined'){
21494 this.groups[checkbox.groupId] = {};
21497 if(this.groups[checkbox.groupId].hasOwnProperty(checkbox.name)){
21501 this.groups[checkbox.groupId][checkbox.name] = checkbox;
21505 * fetch a CheckBox Group based on the group ID
21506 * @param {string} the group ID
21507 * @returns {Roo.bootstrap.CheckBox} the CheckBox group
21509 get: function(groupId) {
21510 if (typeof(this.groups[groupId]) == 'undefined') {
21514 return this.groups[groupId] ;
21527 * @class Roo.bootstrap.Radio
21528 * @extends Roo.bootstrap.Component
21529 * Bootstrap Radio class
21530 * @cfg {String} boxLabel - the label associated
21531 * @cfg {String} value - the value of radio
21534 * Create a new Radio
21535 * @param {Object} config The config object
21537 Roo.bootstrap.Radio = function(config){
21538 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
21542 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.Component, {
21548 getAutoCreate : function()
21552 cls : 'form-group radio',
21557 html : this.boxLabel
21565 initEvents : function()
21567 this.parent().register(this);
21569 this.el.on('click', this.onClick, this);
21573 onClick : function(e)
21575 if(this.parent().fireEvent('click', this.parent(), this, e) !== false){
21576 this.setChecked(true);
21580 setChecked : function(state, suppressEvent)
21582 this.parent().setValue(this.value, suppressEvent);
21586 setBoxLabel : function(v)
21591 this.el.select('label.box-label',true).first().dom.innerHTML = (v === null || v === undefined ? '' : v);
21606 * @class Roo.bootstrap.SecurePass
21607 * @extends Roo.bootstrap.Input
21608 * Bootstrap SecurePass class
21612 * Create a new SecurePass
21613 * @param {Object} config The config object
21616 Roo.bootstrap.SecurePass = function (config) {
21617 // these go here, so the translation tool can replace them..
21619 PwdEmpty: "Please type a password, and then retype it to confirm.",
21620 PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21621 PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21622 PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21623 IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21624 FNInPwd: "Your password can't contain your first name. Please type a different password.",
21625 LNInPwd: "Your password can't contain your last name. Please type a different password.",
21626 TooWeak: "Your password is Too Weak."
21628 this.meterLabel = "Password strength:";
21629 this.pwdStrengths = ["Too Weak", "Weak", "Medium", "Strong"];
21630 this.meterClass = [
21631 "roo-password-meter-tooweak",
21632 "roo-password-meter-weak",
21633 "roo-password-meter-medium",
21634 "roo-password-meter-strong",
21635 "roo-password-meter-grey"
21640 Roo.bootstrap.SecurePass.superclass.constructor.call(this, config);
21643 Roo.extend(Roo.bootstrap.SecurePass, Roo.bootstrap.Input, {
21645 * @cfg {String/Object} errors A Error spec, or true for a default spec (defaults to
21647 * PwdEmpty: "Please type a password, and then retype it to confirm.",
21648 * PwdShort: "Your password must be at least 6 characters long. Please type a different password.",
21649 * PwdLong: "Your password can't contain more than 16 characters. Please type a different password.",
21650 * PwdBadChar: "The password contains characters that aren't allowed. Please type a different password.",
21651 * IDInPwd: "Your password can't include the part of your ID. Please type a different password.",
21652 * FNInPwd: "Your password can't contain your first name. Please type a different password.",
21653 * LNInPwd: "Your password can't contain your last name. Please type a different password."
21663 * @cfg {String/Object} Label for the strength meter (defaults to
21664 * 'Password strength:')
21669 * @cfg {String/Object} pwdStrengths A pwdStrengths spec, or true for a default spec (defaults to
21670 * ['Weak', 'Medium', 'Strong'])
21673 pwdStrengths: false,
21686 initEvents: function ()
21688 Roo.bootstrap.SecurePass.superclass.initEvents.call(this);
21690 if (this.el.is('input[type=password]') && Roo.isSafari) {
21691 this.el.on('keydown', this.SafariOnKeyDown, this);
21694 this.el.on('keyup', this.checkStrength, this, {buffer: 50});
21697 onRender: function (ct, position)
21699 Roo.bootstrap.SecurePass.superclass.onRender.call(this, ct, position);
21700 this.wrap = this.el.wrap({cls: 'x-form-field-wrap'});
21701 this.trigger = this.wrap.createChild({tag: 'div', cls: 'StrengthMeter ' + this.triggerClass});
21703 this.trigger.createChild({
21708 cls: 'roo-password-meter-grey col-xs-12',
21711 //width: this.meterWidth + 'px'
21715 cls: 'roo-password-meter-text'
21721 if (this.hideTrigger) {
21722 this.trigger.setDisplayed(false);
21724 this.setSize(this.width || '', this.height || '');
21727 onDestroy: function ()
21729 if (this.trigger) {
21730 this.trigger.removeAllListeners();
21731 this.trigger.remove();
21734 this.wrap.remove();
21736 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
21739 checkStrength: function ()
21741 var pwd = this.inputEl().getValue();
21742 if (pwd == this._lastPwd) {
21747 if (this.ClientSideStrongPassword(pwd)) {
21749 } else if (this.ClientSideMediumPassword(pwd)) {
21751 } else if (this.ClientSideWeakPassword(pwd)) {
21757 Roo.log('strength1: ' + strength);
21759 //var pm = this.trigger.child('div/div/div').dom;
21760 var pm = this.trigger.child('div/div');
21761 pm.removeClass(this.meterClass);
21762 pm.addClass(this.meterClass[strength]);
21765 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21767 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21769 this._lastPwd = pwd;
21773 Roo.bootstrap.SecurePass.superclass.reset.call(this);
21775 this._lastPwd = '';
21777 var pm = this.trigger.child('div/div');
21778 pm.removeClass(this.meterClass);
21779 pm.addClass('roo-password-meter-grey');
21782 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21785 this.inputEl().dom.type='password';
21788 validateValue: function (value)
21791 if (!Roo.bootstrap.SecurePass.superclass.validateValue.call(this, value)) {
21794 if (value.length == 0) {
21795 if (this.allowBlank) {
21796 this.clearInvalid();
21800 this.markInvalid(this.errors.PwdEmpty);
21801 this.errorMsg = this.errors.PwdEmpty;
21809 if ('[\x21-\x7e]*'.match(value)) {
21810 this.markInvalid(this.errors.PwdBadChar);
21811 this.errorMsg = this.errors.PwdBadChar;
21814 if (value.length < 6) {
21815 this.markInvalid(this.errors.PwdShort);
21816 this.errorMsg = this.errors.PwdShort;
21819 if (value.length > 16) {
21820 this.markInvalid(this.errors.PwdLong);
21821 this.errorMsg = this.errors.PwdLong;
21825 if (this.ClientSideStrongPassword(value)) {
21827 } else if (this.ClientSideMediumPassword(value)) {
21829 } else if (this.ClientSideWeakPassword(value)) {
21836 if (strength < 2) {
21837 //this.markInvalid(this.errors.TooWeak);
21838 this.errorMsg = this.errors.TooWeak;
21843 console.log('strength2: ' + strength);
21845 //var pm = this.trigger.child('div/div/div').dom;
21847 var pm = this.trigger.child('div/div');
21848 pm.removeClass(this.meterClass);
21849 pm.addClass(this.meterClass[strength]);
21851 var pt = this.trigger.child('/div').child('>*[class=roo-password-meter-text]').dom;
21853 pt.innerHTML = this.meterLabel + ' ' + this.pwdStrengths[strength];
21855 this.errorMsg = '';
21859 CharacterSetChecks: function (type)
21862 this.fResult = false;
21865 isctype: function (character, type)
21868 case this.kCapitalLetter:
21869 if (character >= 'A' && character <= 'Z') {
21874 case this.kSmallLetter:
21875 if (character >= 'a' && character <= 'z') {
21881 if (character >= '0' && character <= '9') {
21886 case this.kPunctuation:
21887 if ('!@#$%^&*()_+-=\'";:[{]}|.>,</?`~'.indexOf(character) >= 0) {
21898 IsLongEnough: function (pwd, size)
21900 return !(pwd == null || isNaN(size) || pwd.length < size);
21903 SpansEnoughCharacterSets: function (word, nb)
21905 if (!this.IsLongEnough(word, nb))
21910 var characterSetChecks = new Array(
21911 new this.CharacterSetChecks(this.kCapitalLetter), new this.CharacterSetChecks(this.kSmallLetter),
21912 new this.CharacterSetChecks(this.kDigit), new this.CharacterSetChecks(this.kPunctuation)
21915 for (var index = 0; index < word.length; ++index) {
21916 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21917 if (!characterSetChecks[nCharSet].fResult && this.isctype(word.charAt(index), characterSetChecks[nCharSet].type)) {
21918 characterSetChecks[nCharSet].fResult = true;
21925 for (var nCharSet = 0; nCharSet < characterSetChecks.length; ++nCharSet) {
21926 if (characterSetChecks[nCharSet].fResult) {
21931 if (nCharSets < nb) {
21937 ClientSideStrongPassword: function (pwd)
21939 return this.IsLongEnough(pwd, 8) && this.SpansEnoughCharacterSets(pwd, 3);
21942 ClientSideMediumPassword: function (pwd)
21944 return this.IsLongEnough(pwd, 7) && this.SpansEnoughCharacterSets(pwd, 2);
21947 ClientSideWeakPassword: function (pwd)
21949 return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
21952 })//<script type="text/javascript">
21955 * Based Ext JS Library 1.1.1
21956 * Copyright(c) 2006-2007, Ext JS, LLC.
21962 * @class Roo.HtmlEditorCore
21963 * @extends Roo.Component
21964 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
21966 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
21969 Roo.HtmlEditorCore = function(config){
21972 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
21977 * @event initialize
21978 * Fires when the editor is fully initialized (including the iframe)
21979 * @param {Roo.HtmlEditorCore} this
21984 * Fires when the editor is first receives the focus. Any insertion must wait
21985 * until after this event.
21986 * @param {Roo.HtmlEditorCore} this
21990 * @event beforesync
21991 * Fires before the textarea is updated with content from the editor iframe. Return false
21992 * to cancel the sync.
21993 * @param {Roo.HtmlEditorCore} this
21994 * @param {String} html
21998 * @event beforepush
21999 * Fires before the iframe editor is updated with content from the textarea. Return false
22000 * to cancel the push.
22001 * @param {Roo.HtmlEditorCore} this
22002 * @param {String} html
22007 * Fires when the textarea is updated with content from the editor iframe.
22008 * @param {Roo.HtmlEditorCore} this
22009 * @param {String} html
22014 * Fires when the iframe editor is updated with content from the textarea.
22015 * @param {Roo.HtmlEditorCore} this
22016 * @param {String} html
22021 * @event editorevent
22022 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
22023 * @param {Roo.HtmlEditorCore} this
22029 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
22031 // defaults : white / black...
22032 this.applyBlacklists();
22039 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
22043 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
22049 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
22054 * @cfg {Number} height (in pixels)
22058 * @cfg {Number} width (in pixels)
22063 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
22066 stylesheets: false,
22071 // private properties
22072 validationEvent : false,
22074 initialized : false,
22076 sourceEditMode : false,
22077 onFocus : Roo.emptyFn,
22079 hideMode:'offsets',
22083 // blacklist + whitelisted elements..
22090 * Protected method that will not generally be called directly. It
22091 * is called when the editor initializes the iframe with HTML contents. Override this method if you
22092 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
22094 getDocMarkup : function(){
22098 // inherit styels from page...??
22099 if (this.stylesheets === false) {
22101 Roo.get(document.head).select('style').each(function(node) {
22102 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22105 Roo.get(document.head).select('link').each(function(node) {
22106 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
22109 } else if (!this.stylesheets.length) {
22111 st = '<style type="text/css">' +
22112 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22115 st = '<style type="text/css">' +
22120 st += '<style type="text/css">' +
22121 'IMG { cursor: pointer } ' +
22124 var cls = 'roo-htmleditor-body';
22126 if(this.bodyCls.length){
22127 cls += ' ' + this.bodyCls;
22130 return '<html><head>' + st +
22131 //<style type="text/css">' +
22132 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
22134 ' </head><body class="' + cls + '"></body></html>';
22138 onRender : function(ct, position)
22141 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
22142 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
22145 this.el.dom.style.border = '0 none';
22146 this.el.dom.setAttribute('tabIndex', -1);
22147 this.el.addClass('x-hidden hide');
22151 if(Roo.isIE){ // fix IE 1px bogus margin
22152 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
22156 this.frameId = Roo.id();
22160 var iframe = this.owner.wrap.createChild({
22162 cls: 'form-control', // bootstrap..
22164 name: this.frameId,
22165 frameBorder : 'no',
22166 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
22171 this.iframe = iframe.dom;
22173 this.assignDocWin();
22175 this.doc.designMode = 'on';
22178 this.doc.write(this.getDocMarkup());
22182 var task = { // must defer to wait for browser to be ready
22184 //console.log("run task?" + this.doc.readyState);
22185 this.assignDocWin();
22186 if(this.doc.body || this.doc.readyState == 'complete'){
22188 this.doc.designMode="on";
22192 Roo.TaskMgr.stop(task);
22193 this.initEditor.defer(10, this);
22200 Roo.TaskMgr.start(task);
22205 onResize : function(w, h)
22207 Roo.log('resize: ' +w + ',' + h );
22208 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
22212 if(typeof w == 'number'){
22214 this.iframe.style.width = w + 'px';
22216 if(typeof h == 'number'){
22218 this.iframe.style.height = h + 'px';
22220 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
22227 * Toggles the editor between standard and source edit mode.
22228 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
22230 toggleSourceEdit : function(sourceEditMode){
22232 this.sourceEditMode = sourceEditMode === true;
22234 if(this.sourceEditMode){
22236 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
22239 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
22240 //this.iframe.className = '';
22243 //this.setSize(this.owner.wrap.getSize());
22244 //this.fireEvent('editmodechange', this, this.sourceEditMode);
22251 * Protected method that will not generally be called directly. If you need/want
22252 * custom HTML cleanup, this is the method you should override.
22253 * @param {String} html The HTML to be cleaned
22254 * return {String} The cleaned HTML
22256 cleanHtml : function(html){
22257 html = String(html);
22258 if(html.length > 5){
22259 if(Roo.isSafari){ // strip safari nonsense
22260 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
22263 if(html == ' '){
22270 * HTML Editor -> Textarea
22271 * Protected method that will not generally be called directly. Syncs the contents
22272 * of the editor iframe with the textarea.
22274 syncValue : function(){
22275 if(this.initialized){
22276 var bd = (this.doc.body || this.doc.documentElement);
22277 //this.cleanUpPaste(); -- this is done else where and causes havoc..
22278 var html = bd.innerHTML;
22280 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
22281 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
22283 html = '<div style="'+m[0]+'">' + html + '</div>';
22286 html = this.cleanHtml(html);
22287 // fix up the special chars.. normaly like back quotes in word...
22288 // however we do not want to do this with chinese..
22289 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
22290 var cc = b.charCodeAt();
22292 (cc >= 0x4E00 && cc < 0xA000 ) ||
22293 (cc >= 0x3400 && cc < 0x4E00 ) ||
22294 (cc >= 0xf900 && cc < 0xfb00 )
22300 if(this.owner.fireEvent('beforesync', this, html) !== false){
22301 this.el.dom.value = html;
22302 this.owner.fireEvent('sync', this, html);
22308 * Protected method that will not generally be called directly. Pushes the value of the textarea
22309 * into the iframe editor.
22311 pushValue : function(){
22312 if(this.initialized){
22313 var v = this.el.dom.value.trim();
22315 // if(v.length < 1){
22319 if(this.owner.fireEvent('beforepush', this, v) !== false){
22320 var d = (this.doc.body || this.doc.documentElement);
22322 this.cleanUpPaste();
22323 this.el.dom.value = d.innerHTML;
22324 this.owner.fireEvent('push', this, v);
22330 deferFocus : function(){
22331 this.focus.defer(10, this);
22335 focus : function(){
22336 if(this.win && !this.sourceEditMode){
22343 assignDocWin: function()
22345 var iframe = this.iframe;
22348 this.doc = iframe.contentWindow.document;
22349 this.win = iframe.contentWindow;
22351 // if (!Roo.get(this.frameId)) {
22354 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22355 // this.win = Roo.get(this.frameId).dom.contentWindow;
22357 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
22361 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
22362 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
22367 initEditor : function(){
22368 //console.log("INIT EDITOR");
22369 this.assignDocWin();
22373 this.doc.designMode="on";
22375 this.doc.write(this.getDocMarkup());
22378 var dbody = (this.doc.body || this.doc.documentElement);
22379 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
22380 // this copies styles from the containing element into thsi one..
22381 // not sure why we need all of this..
22382 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
22384 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
22385 //ss['background-attachment'] = 'fixed'; // w3c
22386 dbody.bgProperties = 'fixed'; // ie
22387 //Roo.DomHelper.applyStyles(dbody, ss);
22388 Roo.EventManager.on(this.doc, {
22389 //'mousedown': this.onEditorEvent,
22390 'mouseup': this.onEditorEvent,
22391 'dblclick': this.onEditorEvent,
22392 'click': this.onEditorEvent,
22393 'keyup': this.onEditorEvent,
22398 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
22400 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
22401 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
22403 this.initialized = true;
22405 this.owner.fireEvent('initialize', this);
22410 onDestroy : function(){
22416 //for (var i =0; i < this.toolbars.length;i++) {
22417 // // fixme - ask toolbars for heights?
22418 // this.toolbars[i].onDestroy();
22421 //this.wrap.dom.innerHTML = '';
22422 //this.wrap.remove();
22427 onFirstFocus : function(){
22429 this.assignDocWin();
22432 this.activated = true;
22435 if(Roo.isGecko){ // prevent silly gecko errors
22437 var s = this.win.getSelection();
22438 if(!s.focusNode || s.focusNode.nodeType != 3){
22439 var r = s.getRangeAt(0);
22440 r.selectNodeContents((this.doc.body || this.doc.documentElement));
22445 this.execCmd('useCSS', true);
22446 this.execCmd('styleWithCSS', false);
22449 this.owner.fireEvent('activate', this);
22453 adjustFont: function(btn){
22454 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
22455 //if(Roo.isSafari){ // safari
22458 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
22459 if(Roo.isSafari){ // safari
22460 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
22461 v = (v < 10) ? 10 : v;
22462 v = (v > 48) ? 48 : v;
22463 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
22468 v = Math.max(1, v+adjust);
22470 this.execCmd('FontSize', v );
22473 onEditorEvent : function(e)
22475 this.owner.fireEvent('editorevent', this, e);
22476 // this.updateToolbar();
22477 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
22480 insertTag : function(tg)
22482 // could be a bit smarter... -> wrap the current selected tRoo..
22483 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
22485 range = this.createRange(this.getSelection());
22486 var wrappingNode = this.doc.createElement(tg.toLowerCase());
22487 wrappingNode.appendChild(range.extractContents());
22488 range.insertNode(wrappingNode);
22495 this.execCmd("formatblock", tg);
22499 insertText : function(txt)
22503 var range = this.createRange();
22504 range.deleteContents();
22505 //alert(Sender.getAttribute('label'));
22507 range.insertNode(this.doc.createTextNode(txt));
22513 * Executes a Midas editor command on the editor document and performs necessary focus and
22514 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
22515 * @param {String} cmd The Midas command
22516 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22518 relayCmd : function(cmd, value){
22520 this.execCmd(cmd, value);
22521 this.owner.fireEvent('editorevent', this);
22522 //this.updateToolbar();
22523 this.owner.deferFocus();
22527 * Executes a Midas editor command directly on the editor document.
22528 * For visual commands, you should use {@link #relayCmd} instead.
22529 * <b>This should only be called after the editor is initialized.</b>
22530 * @param {String} cmd The Midas command
22531 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
22533 execCmd : function(cmd, value){
22534 this.doc.execCommand(cmd, false, value === undefined ? null : value);
22541 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
22543 * @param {String} text | dom node..
22545 insertAtCursor : function(text)
22548 if(!this.activated){
22554 var r = this.doc.selection.createRange();
22565 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
22569 // from jquery ui (MIT licenced)
22571 var win = this.win;
22573 if (win.getSelection && win.getSelection().getRangeAt) {
22574 range = win.getSelection().getRangeAt(0);
22575 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
22576 range.insertNode(node);
22577 } else if (win.document.selection && win.document.selection.createRange) {
22578 // no firefox support
22579 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22580 win.document.selection.createRange().pasteHTML(txt);
22582 // no firefox support
22583 var txt = typeof(text) == 'string' ? text : text.outerHTML;
22584 this.execCmd('InsertHTML', txt);
22593 mozKeyPress : function(e){
22595 var c = e.getCharCode(), cmd;
22598 c = String.fromCharCode(c).toLowerCase();
22612 this.cleanUpPaste.defer(100, this);
22620 e.preventDefault();
22628 fixKeys : function(){ // load time branching for fastest keydown performance
22630 return function(e){
22631 var k = e.getKey(), r;
22634 r = this.doc.selection.createRange();
22637 r.pasteHTML('    ');
22644 r = this.doc.selection.createRange();
22646 var target = r.parentElement();
22647 if(!target || target.tagName.toLowerCase() != 'li'){
22649 r.pasteHTML('<br />');
22655 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22656 this.cleanUpPaste.defer(100, this);
22662 }else if(Roo.isOpera){
22663 return function(e){
22664 var k = e.getKey();
22668 this.execCmd('InsertHTML','    ');
22671 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22672 this.cleanUpPaste.defer(100, this);
22677 }else if(Roo.isSafari){
22678 return function(e){
22679 var k = e.getKey();
22683 this.execCmd('InsertText','\t');
22687 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
22688 this.cleanUpPaste.defer(100, this);
22696 getAllAncestors: function()
22698 var p = this.getSelectedNode();
22701 a.push(p); // push blank onto stack..
22702 p = this.getParentElement();
22706 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
22710 a.push(this.doc.body);
22714 lastSelNode : false,
22717 getSelection : function()
22719 this.assignDocWin();
22720 return Roo.isIE ? this.doc.selection : this.win.getSelection();
22723 getSelectedNode: function()
22725 // this may only work on Gecko!!!
22727 // should we cache this!!!!
22732 var range = this.createRange(this.getSelection()).cloneRange();
22735 var parent = range.parentElement();
22737 var testRange = range.duplicate();
22738 testRange.moveToElementText(parent);
22739 if (testRange.inRange(range)) {
22742 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
22745 parent = parent.parentElement;
22750 // is ancestor a text element.
22751 var ac = range.commonAncestorContainer;
22752 if (ac.nodeType == 3) {
22753 ac = ac.parentNode;
22756 var ar = ac.childNodes;
22759 var other_nodes = [];
22760 var has_other_nodes = false;
22761 for (var i=0;i<ar.length;i++) {
22762 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
22765 // fullly contained node.
22767 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
22772 // probably selected..
22773 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
22774 other_nodes.push(ar[i]);
22778 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
22783 has_other_nodes = true;
22785 if (!nodes.length && other_nodes.length) {
22786 nodes= other_nodes;
22788 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
22794 createRange: function(sel)
22796 // this has strange effects when using with
22797 // top toolbar - not sure if it's a great idea.
22798 //this.editor.contentWindow.focus();
22799 if (typeof sel != "undefined") {
22801 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
22803 return this.doc.createRange();
22806 return this.doc.createRange();
22809 getParentElement: function()
22812 this.assignDocWin();
22813 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
22815 var range = this.createRange(sel);
22818 var p = range.commonAncestorContainer;
22819 while (p.nodeType == 3) { // text node
22830 * Range intersection.. the hard stuff...
22834 * [ -- selected range --- ]
22838 * if end is before start or hits it. fail.
22839 * if start is after end or hits it fail.
22841 * if either hits (but other is outside. - then it's not
22847 // @see http://www.thismuchiknow.co.uk/?p=64.
22848 rangeIntersectsNode : function(range, node)
22850 var nodeRange = node.ownerDocument.createRange();
22852 nodeRange.selectNode(node);
22854 nodeRange.selectNodeContents(node);
22857 var rangeStartRange = range.cloneRange();
22858 rangeStartRange.collapse(true);
22860 var rangeEndRange = range.cloneRange();
22861 rangeEndRange.collapse(false);
22863 var nodeStartRange = nodeRange.cloneRange();
22864 nodeStartRange.collapse(true);
22866 var nodeEndRange = nodeRange.cloneRange();
22867 nodeEndRange.collapse(false);
22869 return rangeStartRange.compareBoundaryPoints(
22870 Range.START_TO_START, nodeEndRange) == -1 &&
22871 rangeEndRange.compareBoundaryPoints(
22872 Range.START_TO_START, nodeStartRange) == 1;
22876 rangeCompareNode : function(range, node)
22878 var nodeRange = node.ownerDocument.createRange();
22880 nodeRange.selectNode(node);
22882 nodeRange.selectNodeContents(node);
22886 range.collapse(true);
22888 nodeRange.collapse(true);
22890 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
22891 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
22893 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
22895 var nodeIsBefore = ss == 1;
22896 var nodeIsAfter = ee == -1;
22898 if (nodeIsBefore && nodeIsAfter) {
22901 if (!nodeIsBefore && nodeIsAfter) {
22902 return 1; //right trailed.
22905 if (nodeIsBefore && !nodeIsAfter) {
22906 return 2; // left trailed.
22912 // private? - in a new class?
22913 cleanUpPaste : function()
22915 // cleans up the whole document..
22916 Roo.log('cleanuppaste');
22918 this.cleanUpChildren(this.doc.body);
22919 var clean = this.cleanWordChars(this.doc.body.innerHTML);
22920 if (clean != this.doc.body.innerHTML) {
22921 this.doc.body.innerHTML = clean;
22926 cleanWordChars : function(input) {// change the chars to hex code
22927 var he = Roo.HtmlEditorCore;
22929 var output = input;
22930 Roo.each(he.swapCodes, function(sw) {
22931 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
22933 output = output.replace(swapper, sw[1]);
22940 cleanUpChildren : function (n)
22942 if (!n.childNodes.length) {
22945 for (var i = n.childNodes.length-1; i > -1 ; i--) {
22946 this.cleanUpChild(n.childNodes[i]);
22953 cleanUpChild : function (node)
22956 //console.log(node);
22957 if (node.nodeName == "#text") {
22958 // clean up silly Windows -- stuff?
22961 if (node.nodeName == "#comment") {
22962 node.parentNode.removeChild(node);
22963 // clean up silly Windows -- stuff?
22966 var lcname = node.tagName.toLowerCase();
22967 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
22968 // whitelist of tags..
22970 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
22972 node.parentNode.removeChild(node);
22977 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
22979 // remove <a name=....> as rendering on yahoo mailer is borked with this.
22980 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
22982 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
22983 // remove_keep_children = true;
22986 if (remove_keep_children) {
22987 this.cleanUpChildren(node);
22988 // inserts everything just before this node...
22989 while (node.childNodes.length) {
22990 var cn = node.childNodes[0];
22991 node.removeChild(cn);
22992 node.parentNode.insertBefore(cn, node);
22994 node.parentNode.removeChild(node);
22998 if (!node.attributes || !node.attributes.length) {
22999 this.cleanUpChildren(node);
23003 function cleanAttr(n,v)
23006 if (v.match(/^\./) || v.match(/^\//)) {
23009 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
23012 if (v.match(/^#/)) {
23015 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
23016 node.removeAttribute(n);
23020 var cwhite = this.cwhite;
23021 var cblack = this.cblack;
23023 function cleanStyle(n,v)
23025 if (v.match(/expression/)) { //XSS?? should we even bother..
23026 node.removeAttribute(n);
23030 var parts = v.split(/;/);
23033 Roo.each(parts, function(p) {
23034 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
23038 var l = p.split(':').shift().replace(/\s+/g,'');
23039 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
23041 if ( cwhite.length && cblack.indexOf(l) > -1) {
23042 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23043 //node.removeAttribute(n);
23047 // only allow 'c whitelisted system attributes'
23048 if ( cwhite.length && cwhite.indexOf(l) < 0) {
23049 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
23050 //node.removeAttribute(n);
23060 if (clean.length) {
23061 node.setAttribute(n, clean.join(';'));
23063 node.removeAttribute(n);
23069 for (var i = node.attributes.length-1; i > -1 ; i--) {
23070 var a = node.attributes[i];
23073 if (a.name.toLowerCase().substr(0,2)=='on') {
23074 node.removeAttribute(a.name);
23077 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
23078 node.removeAttribute(a.name);
23081 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
23082 cleanAttr(a.name,a.value); // fixme..
23085 if (a.name == 'style') {
23086 cleanStyle(a.name,a.value);
23089 /// clean up MS crap..
23090 // tecnically this should be a list of valid class'es..
23093 if (a.name == 'class') {
23094 if (a.value.match(/^Mso/)) {
23095 node.className = '';
23098 if (a.value.match(/^body$/)) {
23099 node.className = '';
23110 this.cleanUpChildren(node);
23116 * Clean up MS wordisms...
23118 cleanWord : function(node)
23123 this.cleanWord(this.doc.body);
23126 if (node.nodeName == "#text") {
23127 // clean up silly Windows -- stuff?
23130 if (node.nodeName == "#comment") {
23131 node.parentNode.removeChild(node);
23132 // clean up silly Windows -- stuff?
23136 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
23137 node.parentNode.removeChild(node);
23141 // remove - but keep children..
23142 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
23143 while (node.childNodes.length) {
23144 var cn = node.childNodes[0];
23145 node.removeChild(cn);
23146 node.parentNode.insertBefore(cn, node);
23148 node.parentNode.removeChild(node);
23149 this.iterateChildren(node, this.cleanWord);
23153 if (node.className.length) {
23155 var cn = node.className.split(/\W+/);
23157 Roo.each(cn, function(cls) {
23158 if (cls.match(/Mso[a-zA-Z]+/)) {
23163 node.className = cna.length ? cna.join(' ') : '';
23165 node.removeAttribute("class");
23169 if (node.hasAttribute("lang")) {
23170 node.removeAttribute("lang");
23173 if (node.hasAttribute("style")) {
23175 var styles = node.getAttribute("style").split(";");
23177 Roo.each(styles, function(s) {
23178 if (!s.match(/:/)) {
23181 var kv = s.split(":");
23182 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
23185 // what ever is left... we allow.
23188 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23189 if (!nstyle.length) {
23190 node.removeAttribute('style');
23193 this.iterateChildren(node, this.cleanWord);
23199 * iterateChildren of a Node, calling fn each time, using this as the scole..
23200 * @param {DomNode} node node to iterate children of.
23201 * @param {Function} fn method of this class to call on each item.
23203 iterateChildren : function(node, fn)
23205 if (!node.childNodes.length) {
23208 for (var i = node.childNodes.length-1; i > -1 ; i--) {
23209 fn.call(this, node.childNodes[i])
23215 * cleanTableWidths.
23217 * Quite often pasting from word etc.. results in tables with column and widths.
23218 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
23221 cleanTableWidths : function(node)
23226 this.cleanTableWidths(this.doc.body);
23231 if (node.nodeName == "#text" || node.nodeName == "#comment") {
23234 Roo.log(node.tagName);
23235 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
23236 this.iterateChildren(node, this.cleanTableWidths);
23239 if (node.hasAttribute('width')) {
23240 node.removeAttribute('width');
23244 if (node.hasAttribute("style")) {
23247 var styles = node.getAttribute("style").split(";");
23249 Roo.each(styles, function(s) {
23250 if (!s.match(/:/)) {
23253 var kv = s.split(":");
23254 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
23257 // what ever is left... we allow.
23260 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
23261 if (!nstyle.length) {
23262 node.removeAttribute('style');
23266 this.iterateChildren(node, this.cleanTableWidths);
23274 domToHTML : function(currentElement, depth, nopadtext) {
23276 depth = depth || 0;
23277 nopadtext = nopadtext || false;
23279 if (!currentElement) {
23280 return this.domToHTML(this.doc.body);
23283 //Roo.log(currentElement);
23285 var allText = false;
23286 var nodeName = currentElement.nodeName;
23287 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
23289 if (nodeName == '#text') {
23291 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
23296 if (nodeName != 'BODY') {
23299 // Prints the node tagName, such as <A>, <IMG>, etc
23302 for(i = 0; i < currentElement.attributes.length;i++) {
23304 var aname = currentElement.attributes.item(i).name;
23305 if (!currentElement.attributes.item(i).value.length) {
23308 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
23311 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
23320 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
23323 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
23328 // Traverse the tree
23330 var currentElementChild = currentElement.childNodes.item(i);
23331 var allText = true;
23332 var innerHTML = '';
23334 while (currentElementChild) {
23335 // Formatting code (indent the tree so it looks nice on the screen)
23336 var nopad = nopadtext;
23337 if (lastnode == 'SPAN') {
23341 if (currentElementChild.nodeName == '#text') {
23342 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
23343 toadd = nopadtext ? toadd : toadd.trim();
23344 if (!nopad && toadd.length > 80) {
23345 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
23347 innerHTML += toadd;
23350 currentElementChild = currentElement.childNodes.item(i);
23356 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
23358 // Recursively traverse the tree structure of the child node
23359 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
23360 lastnode = currentElementChild.nodeName;
23362 currentElementChild=currentElement.childNodes.item(i);
23368 // The remaining code is mostly for formatting the tree
23369 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
23374 ret+= "</"+tagName+">";
23380 applyBlacklists : function()
23382 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
23383 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
23387 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
23388 if (b.indexOf(tag) > -1) {
23391 this.white.push(tag);
23395 Roo.each(w, function(tag) {
23396 if (b.indexOf(tag) > -1) {
23399 if (this.white.indexOf(tag) > -1) {
23402 this.white.push(tag);
23407 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
23408 if (w.indexOf(tag) > -1) {
23411 this.black.push(tag);
23415 Roo.each(b, function(tag) {
23416 if (w.indexOf(tag) > -1) {
23419 if (this.black.indexOf(tag) > -1) {
23422 this.black.push(tag);
23427 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
23428 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
23432 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
23433 if (b.indexOf(tag) > -1) {
23436 this.cwhite.push(tag);
23440 Roo.each(w, function(tag) {
23441 if (b.indexOf(tag) > -1) {
23444 if (this.cwhite.indexOf(tag) > -1) {
23447 this.cwhite.push(tag);
23452 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
23453 if (w.indexOf(tag) > -1) {
23456 this.cblack.push(tag);
23460 Roo.each(b, function(tag) {
23461 if (w.indexOf(tag) > -1) {
23464 if (this.cblack.indexOf(tag) > -1) {
23467 this.cblack.push(tag);
23472 setStylesheets : function(stylesheets)
23474 if(typeof(stylesheets) == 'string'){
23475 Roo.get(this.iframe.contentDocument.head).createChild({
23477 rel : 'stylesheet',
23486 Roo.each(stylesheets, function(s) {
23491 Roo.get(_this.iframe.contentDocument.head).createChild({
23493 rel : 'stylesheet',
23502 removeStylesheets : function()
23506 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
23511 setStyle : function(style)
23513 Roo.get(this.iframe.contentDocument.head).createChild({
23522 // hide stuff that is not compatible
23536 * @event specialkey
23540 * @cfg {String} fieldClass @hide
23543 * @cfg {String} focusClass @hide
23546 * @cfg {String} autoCreate @hide
23549 * @cfg {String} inputType @hide
23552 * @cfg {String} invalidClass @hide
23555 * @cfg {String} invalidText @hide
23558 * @cfg {String} msgFx @hide
23561 * @cfg {String} validateOnBlur @hide
23565 Roo.HtmlEditorCore.white = [
23566 'area', 'br', 'img', 'input', 'hr', 'wbr',
23568 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
23569 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
23570 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
23571 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
23572 'table', 'ul', 'xmp',
23574 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
23577 'dir', 'menu', 'ol', 'ul', 'dl',
23583 Roo.HtmlEditorCore.black = [
23584 // 'embed', 'object', // enable - backend responsiblity to clean thiese
23586 'base', 'basefont', 'bgsound', 'blink', 'body',
23587 'frame', 'frameset', 'head', 'html', 'ilayer',
23588 'iframe', 'layer', 'link', 'meta', 'object',
23589 'script', 'style' ,'title', 'xml' // clean later..
23591 Roo.HtmlEditorCore.clean = [
23592 'script', 'style', 'title', 'xml'
23594 Roo.HtmlEditorCore.remove = [
23599 Roo.HtmlEditorCore.ablack = [
23603 Roo.HtmlEditorCore.aclean = [
23604 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
23608 Roo.HtmlEditorCore.pwhite= [
23609 'http', 'https', 'mailto'
23612 // white listed style attributes.
23613 Roo.HtmlEditorCore.cwhite= [
23614 // 'text-align', /// default is to allow most things..
23620 // black listed style attributes.
23621 Roo.HtmlEditorCore.cblack= [
23622 // 'font-size' -- this can be set by the project
23626 Roo.HtmlEditorCore.swapCodes =[
23645 * @class Roo.bootstrap.HtmlEditor
23646 * @extends Roo.bootstrap.TextArea
23647 * Bootstrap HtmlEditor class
23650 * Create a new HtmlEditor
23651 * @param {Object} config The config object
23654 Roo.bootstrap.HtmlEditor = function(config){
23655 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
23656 if (!this.toolbars) {
23657 this.toolbars = [];
23660 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
23663 * @event initialize
23664 * Fires when the editor is fully initialized (including the iframe)
23665 * @param {HtmlEditor} this
23670 * Fires when the editor is first receives the focus. Any insertion must wait
23671 * until after this event.
23672 * @param {HtmlEditor} this
23676 * @event beforesync
23677 * Fires before the textarea is updated with content from the editor iframe. Return false
23678 * to cancel the sync.
23679 * @param {HtmlEditor} this
23680 * @param {String} html
23684 * @event beforepush
23685 * Fires before the iframe editor is updated with content from the textarea. Return false
23686 * to cancel the push.
23687 * @param {HtmlEditor} this
23688 * @param {String} html
23693 * Fires when the textarea is updated with content from the editor iframe.
23694 * @param {HtmlEditor} this
23695 * @param {String} html
23700 * Fires when the iframe editor is updated with content from the textarea.
23701 * @param {HtmlEditor} this
23702 * @param {String} html
23706 * @event editmodechange
23707 * Fires when the editor switches edit modes
23708 * @param {HtmlEditor} this
23709 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23711 editmodechange: true,
23713 * @event editorevent
23714 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23715 * @param {HtmlEditor} this
23719 * @event firstfocus
23720 * Fires when on first focus - needed by toolbars..
23721 * @param {HtmlEditor} this
23726 * Auto save the htmlEditor value as a file into Events
23727 * @param {HtmlEditor} this
23731 * @event savedpreview
23732 * preview the saved version of htmlEditor
23733 * @param {HtmlEditor} this
23740 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
23744 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23749 * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
23754 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
23759 * @cfg {Number} height (in pixels)
23763 * @cfg {Number} width (in pixels)
23768 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
23771 stylesheets: false,
23776 // private properties
23777 validationEvent : false,
23779 initialized : false,
23782 onFocus : Roo.emptyFn,
23784 hideMode:'offsets',
23786 tbContainer : false,
23790 toolbarContainer :function() {
23791 return this.wrap.select('.x-html-editor-tb',true).first();
23795 * Protected method that will not generally be called directly. It
23796 * is called when the editor creates its toolbar. Override this method if you need to
23797 * add custom toolbar buttons.
23798 * @param {HtmlEditor} editor
23800 createToolbar : function(){
23801 Roo.log('renewing');
23802 Roo.log("create toolbars");
23804 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
23805 this.toolbars[0].render(this.toolbarContainer());
23809 // if (!editor.toolbars || !editor.toolbars.length) {
23810 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
23813 // for (var i =0 ; i < editor.toolbars.length;i++) {
23814 // editor.toolbars[i] = Roo.factory(
23815 // typeof(editor.toolbars[i]) == 'string' ?
23816 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
23817 // Roo.bootstrap.HtmlEditor);
23818 // editor.toolbars[i].init(editor);
23824 onRender : function(ct, position)
23826 // Roo.log("Call onRender: " + this.xtype);
23828 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
23830 this.wrap = this.inputEl().wrap({
23831 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23834 this.editorcore.onRender(ct, position);
23836 if (this.resizable) {
23837 this.resizeEl = new Roo.Resizable(this.wrap, {
23841 minHeight : this.height,
23842 height: this.height,
23843 handles : this.resizable,
23846 resize : function(r, w, h) {
23847 _t.onResize(w,h); // -something
23853 this.createToolbar(this);
23856 if(!this.width && this.resizable){
23857 this.setSize(this.wrap.getSize());
23859 if (this.resizeEl) {
23860 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
23861 // should trigger onReize..
23867 onResize : function(w, h)
23869 Roo.log('resize: ' +w + ',' + h );
23870 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
23874 if(this.inputEl() ){
23875 if(typeof w == 'number'){
23876 var aw = w - this.wrap.getFrameWidth('lr');
23877 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
23880 if(typeof h == 'number'){
23881 var tbh = -11; // fixme it needs to tool bar size!
23882 for (var i =0; i < this.toolbars.length;i++) {
23883 // fixme - ask toolbars for heights?
23884 tbh += this.toolbars[i].el.getHeight();
23885 //if (this.toolbars[i].footer) {
23886 // tbh += this.toolbars[i].footer.el.getHeight();
23894 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
23895 ah -= 5; // knock a few pixes off for look..
23896 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
23900 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
23901 this.editorcore.onResize(ew,eh);
23906 * Toggles the editor between standard and source edit mode.
23907 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
23909 toggleSourceEdit : function(sourceEditMode)
23911 this.editorcore.toggleSourceEdit(sourceEditMode);
23913 if(this.editorcore.sourceEditMode){
23914 Roo.log('editor - showing textarea');
23917 // Roo.log(this.syncValue());
23919 this.inputEl().removeClass(['hide', 'x-hidden']);
23920 this.inputEl().dom.removeAttribute('tabIndex');
23921 this.inputEl().focus();
23923 Roo.log('editor - hiding textarea');
23925 // Roo.log(this.pushValue());
23928 this.inputEl().addClass(['hide', 'x-hidden']);
23929 this.inputEl().dom.setAttribute('tabIndex', -1);
23930 //this.deferFocus();
23933 if(this.resizable){
23934 this.setSize(this.wrap.getSize());
23937 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
23940 // private (for BoxComponent)
23941 adjustSize : Roo.BoxComponent.prototype.adjustSize,
23943 // private (for BoxComponent)
23944 getResizeEl : function(){
23948 // private (for BoxComponent)
23949 getPositionEl : function(){
23954 initEvents : function(){
23955 this.originalValue = this.getValue();
23959 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23962 // markInvalid : Roo.emptyFn,
23964 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
23967 // clearInvalid : Roo.emptyFn,
23969 setValue : function(v){
23970 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
23971 this.editorcore.pushValue();
23976 deferFocus : function(){
23977 this.focus.defer(10, this);
23981 focus : function(){
23982 this.editorcore.focus();
23988 onDestroy : function(){
23994 for (var i =0; i < this.toolbars.length;i++) {
23995 // fixme - ask toolbars for heights?
23996 this.toolbars[i].onDestroy();
23999 this.wrap.dom.innerHTML = '';
24000 this.wrap.remove();
24005 onFirstFocus : function(){
24006 //Roo.log("onFirstFocus");
24007 this.editorcore.onFirstFocus();
24008 for (var i =0; i < this.toolbars.length;i++) {
24009 this.toolbars[i].onFirstFocus();
24015 syncValue : function()
24017 this.editorcore.syncValue();
24020 pushValue : function()
24022 this.editorcore.pushValue();
24026 // hide stuff that is not compatible
24040 * @event specialkey
24044 * @cfg {String} fieldClass @hide
24047 * @cfg {String} focusClass @hide
24050 * @cfg {String} autoCreate @hide
24053 * @cfg {String} inputType @hide
24057 * @cfg {String} invalidText @hide
24060 * @cfg {String} msgFx @hide
24063 * @cfg {String} validateOnBlur @hide
24072 Roo.namespace('Roo.bootstrap.htmleditor');
24074 * @class Roo.bootstrap.HtmlEditorToolbar1
24079 new Roo.bootstrap.HtmlEditor({
24082 new Roo.bootstrap.HtmlEditorToolbar1({
24083 disable : { fonts: 1 , format: 1, ..., ... , ...],
24089 * @cfg {Object} disable List of elements to disable..
24090 * @cfg {Array} btns List of additional buttons.
24094 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24097 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
24100 Roo.apply(this, config);
24102 // default disabled, based on 'good practice'..
24103 this.disable = this.disable || {};
24104 Roo.applyIf(this.disable, {
24107 specialElements : true
24109 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
24111 this.editor = config.editor;
24112 this.editorcore = config.editor.editorcore;
24114 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
24116 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24117 // dont call parent... till later.
24119 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
24124 editorcore : false,
24129 "h1","h2","h3","h4","h5","h6",
24131 "abbr", "acronym", "address", "cite", "samp", "var",
24135 onRender : function(ct, position)
24137 // Roo.log("Call onRender: " + this.xtype);
24139 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
24141 this.el.dom.style.marginBottom = '0';
24143 var editorcore = this.editorcore;
24144 var editor= this.editor;
24147 var btn = function(id,cmd , toggle, handler, html){
24149 var event = toggle ? 'toggle' : 'click';
24154 xns: Roo.bootstrap,
24158 enableToggle:toggle !== false,
24160 pressed : toggle ? false : null,
24163 a.listeners[toggle ? 'toggle' : 'click'] = function() {
24164 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
24170 // var cb_box = function...
24175 xns: Roo.bootstrap,
24180 xns: Roo.bootstrap,
24184 Roo.each(this.formats, function(f) {
24185 style.menu.items.push({
24187 xns: Roo.bootstrap,
24188 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
24193 editorcore.insertTag(this.tagname);
24200 children.push(style);
24202 btn('bold',false,true);
24203 btn('italic',false,true);
24204 btn('align-left', 'justifyleft',true);
24205 btn('align-center', 'justifycenter',true);
24206 btn('align-right' , 'justifyright',true);
24207 btn('link', false, false, function(btn) {
24208 //Roo.log("create link?");
24209 var url = prompt(this.createLinkText, this.defaultLinkValue);
24210 if(url && url != 'http:/'+'/'){
24211 this.editorcore.relayCmd('createlink', url);
24214 btn('list','insertunorderedlist',true);
24215 btn('pencil', false,true, function(btn){
24217 this.toggleSourceEdit(btn.pressed);
24220 if (this.editor.btns.length > 0) {
24221 for (var i = 0; i<this.editor.btns.length; i++) {
24222 children.push(this.editor.btns[i]);
24230 xns: Roo.bootstrap,
24235 xns: Roo.bootstrap,
24240 cog.menu.items.push({
24242 xns: Roo.bootstrap,
24243 html : Clean styles,
24248 editorcore.insertTag(this.tagname);
24257 this.xtype = 'NavSimplebar';
24259 for(var i=0;i< children.length;i++) {
24261 this.buttons.add(this.addxtypeChild(children[i]));
24265 editor.on('editorevent', this.updateToolbar, this);
24267 onBtnClick : function(id)
24269 this.editorcore.relayCmd(id);
24270 this.editorcore.focus();
24274 * Protected method that will not generally be called directly. It triggers
24275 * a toolbar update by reading the markup state of the current selection in the editor.
24277 updateToolbar: function(){
24279 if(!this.editorcore.activated){
24280 this.editor.onFirstFocus(); // is this neeed?
24284 var btns = this.buttons;
24285 var doc = this.editorcore.doc;
24286 btns.get('bold').setActive(doc.queryCommandState('bold'));
24287 btns.get('italic').setActive(doc.queryCommandState('italic'));
24288 //btns.get('underline').setActive(doc.queryCommandState('underline'));
24290 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
24291 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
24292 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
24294 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
24295 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
24298 var ans = this.editorcore.getAllAncestors();
24299 if (this.formatCombo) {
24302 var store = this.formatCombo.store;
24303 this.formatCombo.setValue("");
24304 for (var i =0; i < ans.length;i++) {
24305 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
24307 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
24315 // hides menus... - so this cant be on a menu...
24316 Roo.bootstrap.MenuMgr.hideAll();
24318 Roo.bootstrap.MenuMgr.hideAll();
24319 //this.editorsyncValue();
24321 onFirstFocus: function() {
24322 this.buttons.each(function(item){
24326 toggleSourceEdit : function(sourceEditMode){
24329 if(sourceEditMode){
24330 Roo.log("disabling buttons");
24331 this.buttons.each( function(item){
24332 if(item.cmd != 'pencil'){
24338 Roo.log("enabling buttons");
24339 if(this.editorcore.initialized){
24340 this.buttons.each( function(item){
24346 Roo.log("calling toggole on editor");
24347 // tell the editor that it's been pressed..
24348 this.editor.toggleSourceEdit(sourceEditMode);
24358 * @class Roo.bootstrap.Table.AbstractSelectionModel
24359 * @extends Roo.util.Observable
24360 * Abstract base class for grid SelectionModels. It provides the interface that should be
24361 * implemented by descendant classes. This class should not be directly instantiated.
24364 Roo.bootstrap.Table.AbstractSelectionModel = function(){
24365 this.locked = false;
24366 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
24370 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
24371 /** @ignore Called by the grid automatically. Do not call directly. */
24372 init : function(grid){
24378 * Locks the selections.
24381 this.locked = true;
24385 * Unlocks the selections.
24387 unlock : function(){
24388 this.locked = false;
24392 * Returns true if the selections are locked.
24393 * @return {Boolean}
24395 isLocked : function(){
24396 return this.locked;
24400 * @extends Roo.bootstrap.Table.AbstractSelectionModel
24401 * @class Roo.bootstrap.Table.RowSelectionModel
24402 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
24403 * It supports multiple selections and keyboard selection/navigation.
24405 * @param {Object} config
24408 Roo.bootstrap.Table.RowSelectionModel = function(config){
24409 Roo.apply(this, config);
24410 this.selections = new Roo.util.MixedCollection(false, function(o){
24415 this.lastActive = false;
24419 * @event selectionchange
24420 * Fires when the selection changes
24421 * @param {SelectionModel} this
24423 "selectionchange" : true,
24425 * @event afterselectionchange
24426 * Fires after the selection changes (eg. by key press or clicking)
24427 * @param {SelectionModel} this
24429 "afterselectionchange" : true,
24431 * @event beforerowselect
24432 * Fires when a row is selected being selected, return false to cancel.
24433 * @param {SelectionModel} this
24434 * @param {Number} rowIndex The selected index
24435 * @param {Boolean} keepExisting False if other selections will be cleared
24437 "beforerowselect" : true,
24440 * Fires when a row is selected.
24441 * @param {SelectionModel} this
24442 * @param {Number} rowIndex The selected index
24443 * @param {Roo.data.Record} r The record
24445 "rowselect" : true,
24447 * @event rowdeselect
24448 * Fires when a row is deselected.
24449 * @param {SelectionModel} this
24450 * @param {Number} rowIndex The selected index
24452 "rowdeselect" : true
24454 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
24455 this.locked = false;
24458 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
24460 * @cfg {Boolean} singleSelect
24461 * True to allow selection of only one row at a time (defaults to false)
24463 singleSelect : false,
24466 initEvents : function()
24469 //if(!this.grid.enableDragDrop && !this.grid.enableDrag){
24470 // this.growclickrid.on("mousedown", this.handleMouseDown, this);
24471 //}else{ // allow click to work like normal
24472 // this.grid.on("rowclick", this.handleDragableRowClick, this);
24474 //this.grid.on("rowdblclick", this.handleMouseDBClick, this);
24475 this.grid.on("rowclick", this.handleMouseDown, this);
24477 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
24478 "up" : function(e){
24480 this.selectPrevious(e.shiftKey);
24481 }else if(this.last !== false && this.lastActive !== false){
24482 var last = this.last;
24483 this.selectRange(this.last, this.lastActive-1);
24484 this.grid.getView().focusRow(this.lastActive);
24485 if(last !== false){
24489 this.selectFirstRow();
24491 this.fireEvent("afterselectionchange", this);
24493 "down" : function(e){
24495 this.selectNext(e.shiftKey);
24496 }else if(this.last !== false && this.lastActive !== false){
24497 var last = this.last;
24498 this.selectRange(this.last, this.lastActive+1);
24499 this.grid.getView().focusRow(this.lastActive);
24500 if(last !== false){
24504 this.selectFirstRow();
24506 this.fireEvent("afterselectionchange", this);
24510 this.grid.store.on('load', function(){
24511 this.selections.clear();
24514 var view = this.grid.view;
24515 view.on("refresh", this.onRefresh, this);
24516 view.on("rowupdated", this.onRowUpdated, this);
24517 view.on("rowremoved", this.onRemove, this);
24522 onRefresh : function()
24524 var ds = this.grid.store, i, v = this.grid.view;
24525 var s = this.selections;
24526 s.each(function(r){
24527 if((i = ds.indexOfId(r.id)) != -1){
24536 onRemove : function(v, index, r){
24537 this.selections.remove(r);
24541 onRowUpdated : function(v, index, r){
24542 if(this.isSelected(r)){
24543 v.onRowSelect(index);
24549 * @param {Array} records The records to select
24550 * @param {Boolean} keepExisting (optional) True to keep existing selections
24552 selectRecords : function(records, keepExisting)
24555 this.clearSelections();
24557 var ds = this.grid.store;
24558 for(var i = 0, len = records.length; i < len; i++){
24559 this.selectRow(ds.indexOf(records[i]), true);
24564 * Gets the number of selected rows.
24567 getCount : function(){
24568 return this.selections.length;
24572 * Selects the first row in the grid.
24574 selectFirstRow : function(){
24579 * Select the last row.
24580 * @param {Boolean} keepExisting (optional) True to keep existing selections
24582 selectLastRow : function(keepExisting){
24583 //this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
24584 this.selectRow(this.grid.store.getCount() - 1, keepExisting);
24588 * Selects the row immediately following the last selected row.
24589 * @param {Boolean} keepExisting (optional) True to keep existing selections
24591 selectNext : function(keepExisting)
24593 if(this.last !== false && (this.last+1) < this.grid.store.getCount()){
24594 this.selectRow(this.last+1, keepExisting);
24595 this.grid.getView().focusRow(this.last);
24600 * Selects the row that precedes the last selected row.
24601 * @param {Boolean} keepExisting (optional) True to keep existing selections
24603 selectPrevious : function(keepExisting){
24605 this.selectRow(this.last-1, keepExisting);
24606 this.grid.getView().focusRow(this.last);
24611 * Returns the selected records
24612 * @return {Array} Array of selected records
24614 getSelections : function(){
24615 return [].concat(this.selections.items);
24619 * Returns the first selected record.
24622 getSelected : function(){
24623 return this.selections.itemAt(0);
24628 * Clears all selections.
24630 clearSelections : function(fast)
24636 var ds = this.grid.store;
24637 var s = this.selections;
24638 s.each(function(r){
24639 this.deselectRow(ds.indexOfId(r.id));
24643 this.selections.clear();
24650 * Selects all rows.
24652 selectAll : function(){
24656 this.selections.clear();
24657 for(var i = 0, len = this.grid.store.getCount(); i < len; i++){
24658 this.selectRow(i, true);
24663 * Returns True if there is a selection.
24664 * @return {Boolean}
24666 hasSelection : function(){
24667 return this.selections.length > 0;
24671 * Returns True if the specified row is selected.
24672 * @param {Number/Record} record The record or index of the record to check
24673 * @return {Boolean}
24675 isSelected : function(index){
24676 var r = typeof index == "number" ? this.grid.store.getAt(index) : index;
24677 return (r && this.selections.key(r.id) ? true : false);
24681 * Returns True if the specified record id is selected.
24682 * @param {String} id The id of record to check
24683 * @return {Boolean}
24685 isIdSelected : function(id){
24686 return (this.selections.key(id) ? true : false);
24691 handleMouseDBClick : function(e, t){
24695 handleMouseDown : function(e, t)
24697 var rowIndex = this.grid.headerShow ? t.dom.rowIndex - 1 : t.dom.rowIndex ; // first row is header???
24698 if(this.isLocked() || rowIndex < 0 ){
24701 if(e.shiftKey && this.last !== false){
24702 var last = this.last;
24703 this.selectRange(last, rowIndex, e.ctrlKey);
24704 this.last = last; // reset the last
24708 var isSelected = this.isSelected(rowIndex);
24709 //Roo.log("select row:" + rowIndex);
24711 this.deselectRow(rowIndex);
24713 this.selectRow(rowIndex, true);
24717 if(e.button !== 0 && isSelected){
24718 alert('rowIndex 2: ' + rowIndex);
24719 view.focusRow(rowIndex);
24720 }else if(e.ctrlKey && isSelected){
24721 this.deselectRow(rowIndex);
24722 }else if(!isSelected){
24723 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
24724 view.focusRow(rowIndex);
24728 this.fireEvent("afterselectionchange", this);
24731 handleDragableRowClick : function(grid, rowIndex, e)
24733 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
24734 this.selectRow(rowIndex, false);
24735 grid.view.focusRow(rowIndex);
24736 this.fireEvent("afterselectionchange", this);
24741 * Selects multiple rows.
24742 * @param {Array} rows Array of the indexes of the row to select
24743 * @param {Boolean} keepExisting (optional) True to keep existing selections
24745 selectRows : function(rows, keepExisting){
24747 this.clearSelections();
24749 for(var i = 0, len = rows.length; i < len; i++){
24750 this.selectRow(rows[i], true);
24755 * Selects a range of rows. All rows in between startRow and endRow are also selected.
24756 * @param {Number} startRow The index of the first row in the range
24757 * @param {Number} endRow The index of the last row in the range
24758 * @param {Boolean} keepExisting (optional) True to retain existing selections
24760 selectRange : function(startRow, endRow, keepExisting){
24765 this.clearSelections();
24767 if(startRow <= endRow){
24768 for(var i = startRow; i <= endRow; i++){
24769 this.selectRow(i, true);
24772 for(var i = startRow; i >= endRow; i--){
24773 this.selectRow(i, true);
24779 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
24780 * @param {Number} startRow The index of the first row in the range
24781 * @param {Number} endRow The index of the last row in the range
24783 deselectRange : function(startRow, endRow, preventViewNotify){
24787 for(var i = startRow; i <= endRow; i++){
24788 this.deselectRow(i, preventViewNotify);
24794 * @param {Number} row The index of the row to select
24795 * @param {Boolean} keepExisting (optional) True to keep existing selections
24797 selectRow : function(index, keepExisting, preventViewNotify)
24799 if(this.locked || (index < 0 || index > this.grid.store.getCount())) {
24802 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
24803 if(!keepExisting || this.singleSelect){
24804 this.clearSelections();
24807 var r = this.grid.store.getAt(index);
24808 //console.log('selectRow - record id :' + r.id);
24810 this.selections.add(r);
24811 this.last = this.lastActive = index;
24812 if(!preventViewNotify){
24813 var proxy = new Roo.Element(
24814 this.grid.getRowDom(index)
24816 proxy.addClass('bg-info info');
24818 this.fireEvent("rowselect", this, index, r);
24819 this.fireEvent("selectionchange", this);
24825 * @param {Number} row The index of the row to deselect
24827 deselectRow : function(index, preventViewNotify)
24832 if(this.last == index){
24835 if(this.lastActive == index){
24836 this.lastActive = false;
24839 var r = this.grid.store.getAt(index);
24844 this.selections.remove(r);
24845 //.console.log('deselectRow - record id :' + r.id);
24846 if(!preventViewNotify){
24848 var proxy = new Roo.Element(
24849 this.grid.getRowDom(index)
24851 proxy.removeClass('bg-info info');
24853 this.fireEvent("rowdeselect", this, index);
24854 this.fireEvent("selectionchange", this);
24858 restoreLast : function(){
24860 this.last = this._last;
24865 acceptsNav : function(row, col, cm){
24866 return !cm.isHidden(col) && cm.isCellEditable(col, row);
24870 onEditorKey : function(field, e){
24871 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
24876 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
24878 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
24880 }else if(k == e.ENTER && !e.ctrlKey){
24884 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
24886 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
24888 }else if(k == e.ESC){
24892 g.startEditing(newCell[0], newCell[1]);
24898 * Ext JS Library 1.1.1
24899 * Copyright(c) 2006-2007, Ext JS, LLC.
24901 * Originally Released Under LGPL - original licence link has changed is not relivant.
24904 * <script type="text/javascript">
24908 * @class Roo.bootstrap.PagingToolbar
24909 * @extends Roo.bootstrap.NavSimplebar
24910 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
24912 * Create a new PagingToolbar
24913 * @param {Object} config The config object
24914 * @param {Roo.data.Store} store
24916 Roo.bootstrap.PagingToolbar = function(config)
24918 // old args format still supported... - xtype is prefered..
24919 // created from xtype...
24921 this.ds = config.dataSource;
24923 if (config.store && !this.ds) {
24924 this.store= Roo.factory(config.store, Roo.data);
24925 this.ds = this.store;
24926 this.ds.xmodule = this.xmodule || false;
24929 this.toolbarItems = [];
24930 if (config.items) {
24931 this.toolbarItems = config.items;
24934 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
24939 this.bind(this.ds);
24942 if (Roo.bootstrap.version == 4) {
24943 this.navgroup = new Roo.bootstrap.ButtonGroup({ cls: 'pagination' });
24945 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
24950 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
24952 * @cfg {Roo.data.Store} dataSource
24953 * The underlying data store providing the paged data
24956 * @cfg {String/HTMLElement/Element} container
24957 * container The id or element that will contain the toolbar
24960 * @cfg {Boolean} displayInfo
24961 * True to display the displayMsg (defaults to false)
24964 * @cfg {Number} pageSize
24965 * The number of records to display per page (defaults to 20)
24969 * @cfg {String} displayMsg
24970 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
24972 displayMsg : 'Displaying {0} - {1} of {2}',
24974 * @cfg {String} emptyMsg
24975 * The message to display when no records are found (defaults to "No data to display")
24977 emptyMsg : 'No data to display',
24979 * Customizable piece of the default paging text (defaults to "Page")
24982 beforePageText : "Page",
24984 * Customizable piece of the default paging text (defaults to "of %0")
24987 afterPageText : "of {0}",
24989 * Customizable piece of the default paging text (defaults to "First Page")
24992 firstText : "First Page",
24994 * Customizable piece of the default paging text (defaults to "Previous Page")
24997 prevText : "Previous Page",
24999 * Customizable piece of the default paging text (defaults to "Next Page")
25002 nextText : "Next Page",
25004 * Customizable piece of the default paging text (defaults to "Last Page")
25007 lastText : "Last Page",
25009 * Customizable piece of the default paging text (defaults to "Refresh")
25012 refreshText : "Refresh",
25016 onRender : function(ct, position)
25018 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
25019 this.navgroup.parentId = this.id;
25020 this.navgroup.onRender(this.el, null);
25021 // add the buttons to the navgroup
25023 if(this.displayInfo){
25024 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
25025 this.displayEl = this.el.select('.x-paging-info', true).first();
25026 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
25027 // this.displayEl = navel.el.select('span',true).first();
25033 Roo.each(_this.buttons, function(e){ // this might need to use render????
25034 Roo.factory(e).render(_this.el);
25038 Roo.each(_this.toolbarItems, function(e) {
25039 _this.navgroup.addItem(e);
25043 this.first = this.navgroup.addItem({
25044 tooltip: this.firstText,
25045 cls: "prev btn-outline-secondary",
25046 html : ' <i class="fa fa-step-backward"></i>',
25048 preventDefault: true,
25049 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
25052 this.prev = this.navgroup.addItem({
25053 tooltip: this.prevText,
25054 cls: "prev btn-outline-secondary",
25055 html : ' <i class="fa fa-backward"></i>',
25057 preventDefault: true,
25058 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
25060 //this.addSeparator();
25063 var field = this.navgroup.addItem( {
25065 cls : 'x-paging-position btn-outline-secondary',
25067 html : this.beforePageText +
25068 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
25069 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
25072 this.field = field.el.select('input', true).first();
25073 this.field.on("keydown", this.onPagingKeydown, this);
25074 this.field.on("focus", function(){this.dom.select();});
25077 this.afterTextEl = field.el.select('.x-paging-after',true).first();
25078 //this.field.setHeight(18);
25079 //this.addSeparator();
25080 this.next = this.navgroup.addItem({
25081 tooltip: this.nextText,
25082 cls: "next btn-outline-secondary",
25083 html : ' <i class="fa fa-forward"></i>',
25085 preventDefault: true,
25086 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
25088 this.last = this.navgroup.addItem({
25089 tooltip: this.lastText,
25090 html : ' <i class="fa fa-step-forward"></i>',
25091 cls: "next btn-outline-secondary",
25093 preventDefault: true,
25094 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
25096 //this.addSeparator();
25097 this.loading = this.navgroup.addItem({
25098 tooltip: this.refreshText,
25099 cls: "btn-outline-secondary",
25100 html : ' <i class="fa fa-refresh"></i>',
25101 preventDefault: true,
25102 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
25108 updateInfo : function(){
25109 if(this.displayEl){
25110 var count = (typeof(this.getCount) == 'undefined') ? this.ds.getCount() : this.getCount();
25111 var msg = count == 0 ?
25115 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
25117 this.displayEl.update(msg);
25122 onLoad : function(ds, r, o)
25124 this.cursor = o.params.start ? o.params.start : 0;
25126 var d = this.getPageData(),
25131 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
25132 this.field.dom.value = ap;
25133 this.first.setDisabled(ap == 1);
25134 this.prev.setDisabled(ap == 1);
25135 this.next.setDisabled(ap == ps);
25136 this.last.setDisabled(ap == ps);
25137 this.loading.enable();
25142 getPageData : function(){
25143 var total = this.ds.getTotalCount();
25146 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
25147 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
25152 onLoadError : function(){
25153 this.loading.enable();
25157 onPagingKeydown : function(e){
25158 var k = e.getKey();
25159 var d = this.getPageData();
25161 var v = this.field.dom.value, pageNum;
25162 if(!v || isNaN(pageNum = parseInt(v, 10))){
25163 this.field.dom.value = d.activePage;
25166 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
25167 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25170 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))
25172 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
25173 this.field.dom.value = pageNum;
25174 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
25177 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
25179 var v = this.field.dom.value, pageNum;
25180 var increment = (e.shiftKey) ? 10 : 1;
25181 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
25184 if(!v || isNaN(pageNum = parseInt(v, 10))) {
25185 this.field.dom.value = d.activePage;
25188 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
25190 this.field.dom.value = parseInt(v, 10) + increment;
25191 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
25192 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
25199 beforeLoad : function(){
25201 this.loading.disable();
25206 onClick : function(which){
25215 ds.load({params:{start: 0, limit: this.pageSize}});
25218 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
25221 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
25224 var total = ds.getTotalCount();
25225 var extra = total % this.pageSize;
25226 var lastStart = extra ? (total - extra) : total-this.pageSize;
25227 ds.load({params:{start: lastStart, limit: this.pageSize}});
25230 ds.load({params:{start: this.cursor, limit: this.pageSize}});
25236 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
25237 * @param {Roo.data.Store} store The data store to unbind
25239 unbind : function(ds){
25240 ds.un("beforeload", this.beforeLoad, this);
25241 ds.un("load", this.onLoad, this);
25242 ds.un("loadexception", this.onLoadError, this);
25243 ds.un("remove", this.updateInfo, this);
25244 ds.un("add", this.updateInfo, this);
25245 this.ds = undefined;
25249 * Binds the paging toolbar to the specified {@link Roo.data.Store}
25250 * @param {Roo.data.Store} store The data store to bind
25252 bind : function(ds){
25253 ds.on("beforeload", this.beforeLoad, this);
25254 ds.on("load", this.onLoad, this);
25255 ds.on("loadexception", this.onLoadError, this);
25256 ds.on("remove", this.updateInfo, this);
25257 ds.on("add", this.updateInfo, this);
25268 * @class Roo.bootstrap.MessageBar
25269 * @extends Roo.bootstrap.Component
25270 * Bootstrap MessageBar class
25271 * @cfg {String} html contents of the MessageBar
25272 * @cfg {String} weight (info | success | warning | danger) default info
25273 * @cfg {String} beforeClass insert the bar before the given class
25274 * @cfg {Boolean} closable (true | false) default false
25275 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
25278 * Create a new Element
25279 * @param {Object} config The config object
25282 Roo.bootstrap.MessageBar = function(config){
25283 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
25286 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
25292 beforeClass: 'bootstrap-sticky-wrap',
25294 getAutoCreate : function(){
25298 cls: 'alert alert-dismissable alert-' + this.weight,
25303 html: this.html || ''
25309 cfg.cls += ' alert-messages-fixed';
25323 onRender : function(ct, position)
25325 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
25328 var cfg = Roo.apply({}, this.getAutoCreate());
25332 cfg.cls += ' ' + this.cls;
25335 cfg.style = this.style;
25337 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
25339 this.el.setVisibilityMode(Roo.Element.DISPLAY);
25342 this.el.select('>button.close').on('click', this.hide, this);
25348 if (!this.rendered) {
25354 this.fireEvent('show', this);
25360 if (!this.rendered) {
25366 this.fireEvent('hide', this);
25369 update : function()
25371 // var e = this.el.dom.firstChild;
25373 // if(this.closable){
25374 // e = e.nextSibling;
25377 // e.data = this.html || '';
25379 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
25395 * @class Roo.bootstrap.Graph
25396 * @extends Roo.bootstrap.Component
25397 * Bootstrap Graph class
25401 @cfg {String} graphtype bar | vbar | pie
25402 @cfg {number} g_x coodinator | centre x (pie)
25403 @cfg {number} g_y coodinator | centre y (pie)
25404 @cfg {number} g_r radius (pie)
25405 @cfg {number} g_height height of the chart (respected by all elements in the set)
25406 @cfg {number} g_width width of the chart (respected by all elements in the set)
25407 @cfg {Object} title The title of the chart
25410 -opts (object) options for the chart
25412 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
25413 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
25415 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.
25416 o stacked (boolean) whether or not to tread values as in a stacked bar chart
25418 o stretch (boolean)
25420 -opts (object) options for the pie
25423 o startAngle (number)
25424 o endAngle (number)
25428 * Create a new Input
25429 * @param {Object} config The config object
25432 Roo.bootstrap.Graph = function(config){
25433 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
25439 * The img click event for the img.
25440 * @param {Roo.EventObject} e
25446 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
25457 //g_colors: this.colors,
25464 getAutoCreate : function(){
25475 onRender : function(ct,position){
25478 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
25480 if (typeof(Raphael) == 'undefined') {
25481 Roo.bootstrap.MessageBox.alert("Error","Raphael is not availabe");
25485 this.raphael = Raphael(this.el.dom);
25487 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25488 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25489 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
25490 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
25492 r.text(160, 10, "Single Series Chart").attr(txtattr);
25493 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
25494 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
25495 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
25497 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
25498 r.barchart(330, 10, 300, 220, data1);
25499 r.barchart(10, 250, 300, 220, data2, {stacked: true});
25500 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
25503 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25504 // r.barchart(30, 30, 560, 250, xdata, {
25505 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
25506 // axis : "0 0 1 1",
25507 // axisxlabels : xdata
25508 // //yvalues : cols,
25511 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
25513 // this.load(null,xdata,{
25514 // axis : "0 0 1 1",
25515 // axisxlabels : xdata
25520 load : function(graphtype,xdata,opts)
25522 this.raphael.clear();
25524 graphtype = this.graphtype;
25529 var r = this.raphael,
25530 fin = function () {
25531 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
25533 fout = function () {
25534 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
25536 pfin = function() {
25537 this.sector.stop();
25538 this.sector.scale(1.1, 1.1, this.cx, this.cy);
25541 this.label[0].stop();
25542 this.label[0].attr({ r: 7.5 });
25543 this.label[1].attr({ "font-weight": 800 });
25546 pfout = function() {
25547 this.sector.animate({ transform: 's1 1 ' + this.cx + ' ' + this.cy }, 500, "bounce");
25550 this.label[0].animate({ r: 5 }, 500, "bounce");
25551 this.label[1].attr({ "font-weight": 400 });
25557 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25560 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
25563 // opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
25564 // href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
25566 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts).hover(pfin, pfout);
25573 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
25578 setTitle: function(o)
25583 initEvents: function() {
25586 this.el.on('click', this.onClick, this);
25590 onClick : function(e)
25592 Roo.log('img onclick');
25593 this.fireEvent('click', this, e);
25605 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25608 * @class Roo.bootstrap.dash.NumberBox
25609 * @extends Roo.bootstrap.Component
25610 * Bootstrap NumberBox class
25611 * @cfg {String} headline Box headline
25612 * @cfg {String} content Box content
25613 * @cfg {String} icon Box icon
25614 * @cfg {String} footer Footer text
25615 * @cfg {String} fhref Footer href
25618 * Create a new NumberBox
25619 * @param {Object} config The config object
25623 Roo.bootstrap.dash.NumberBox = function(config){
25624 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
25628 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
25637 getAutoCreate : function(){
25641 cls : 'small-box ',
25649 cls : 'roo-headline',
25650 html : this.headline
25654 cls : 'roo-content',
25655 html : this.content
25669 cls : 'ion ' + this.icon
25678 cls : 'small-box-footer',
25679 href : this.fhref || '#',
25683 cfg.cn.push(footer);
25690 onRender : function(ct,position){
25691 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
25698 setHeadline: function (value)
25700 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
25703 setFooter: function (value, href)
25705 this.el.select('a.small-box-footer',true).first().dom.innerHTML = value;
25708 this.el.select('a.small-box-footer',true).first().attr('href', href);
25713 setContent: function (value)
25715 this.el.select('.roo-content',true).first().dom.innerHTML = value;
25718 initEvents: function()
25732 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25735 * @class Roo.bootstrap.dash.TabBox
25736 * @extends Roo.bootstrap.Component
25737 * Bootstrap TabBox class
25738 * @cfg {String} title Title of the TabBox
25739 * @cfg {String} icon Icon of the TabBox
25740 * @cfg {Boolean} showtabs (true|false) show the tabs default true
25741 * @cfg {Boolean} tabScrollable (true|false) tab scrollable when mobile view default false
25744 * Create a new TabBox
25745 * @param {Object} config The config object
25749 Roo.bootstrap.dash.TabBox = function(config){
25750 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
25755 * When a pane is added
25756 * @param {Roo.bootstrap.dash.TabPane} pane
25760 * @event activatepane
25761 * When a pane is activated
25762 * @param {Roo.bootstrap.dash.TabPane} pane
25764 "activatepane" : true
25772 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
25777 tabScrollable : false,
25779 getChildContainer : function()
25781 return this.el.select('.tab-content', true).first();
25784 getAutoCreate : function(){
25788 cls: 'pull-left header',
25796 cls: 'fa ' + this.icon
25802 cls: 'nav nav-tabs pull-right',
25808 if(this.tabScrollable){
25815 cls: 'nav nav-tabs pull-right',
25826 cls: 'nav-tabs-custom',
25831 cls: 'tab-content no-padding',
25839 initEvents : function()
25841 //Roo.log('add add pane handler');
25842 this.on('addpane', this.onAddPane, this);
25845 * Updates the box title
25846 * @param {String} html to set the title to.
25848 setTitle : function(value)
25850 this.el.select('.nav-tabs .header', true).first().dom.innerHTML = value;
25852 onAddPane : function(pane)
25854 this.panes.push(pane);
25855 //Roo.log('addpane');
25857 // tabs are rendere left to right..
25858 if(!this.showtabs){
25862 var ctr = this.el.select('.nav-tabs', true).first();
25865 var existing = ctr.select('.nav-tab',true);
25866 var qty = existing.getCount();;
25869 var tab = ctr.createChild({
25871 cls : 'nav-tab' + (qty ? '' : ' active'),
25879 }, qty ? existing.first().dom : ctr.select('.header', true).first().dom );
25882 tab.on('click', this.onTabClick.createDelegate(this, [pane], true));
25884 pane.el.addClass('active');
25889 onTabClick : function(ev,un,ob,pane)
25891 //Roo.log('tab - prev default');
25892 ev.preventDefault();
25895 this.el.select('.nav-tabs li.nav-tab', true).removeClass('active');
25896 pane.tab.addClass('active');
25897 //Roo.log(pane.title);
25898 this.getChildContainer().select('.tab-pane',true).removeClass('active');
25899 // technically we should have a deactivate event.. but maybe add later.
25900 // and it should not de-activate the selected tab...
25901 this.fireEvent('activatepane', pane);
25902 pane.el.addClass('active');
25903 pane.fireEvent('activate');
25908 getActivePane : function()
25911 Roo.each(this.panes, function(p) {
25912 if(p.el.hasClass('active')){
25933 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
25935 * @class Roo.bootstrap.TabPane
25936 * @extends Roo.bootstrap.Component
25937 * Bootstrap TabPane class
25938 * @cfg {Boolean} active (false | true) Default false
25939 * @cfg {String} title title of panel
25943 * Create a new TabPane
25944 * @param {Object} config The config object
25947 Roo.bootstrap.dash.TabPane = function(config){
25948 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
25954 * When a pane is activated
25955 * @param {Roo.bootstrap.dash.TabPane} pane
25962 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
25967 // the tabBox that this is attached to.
25970 getAutoCreate : function()
25978 cfg.cls += ' active';
25983 initEvents : function()
25985 //Roo.log('trigger add pane handler');
25986 this.parent().fireEvent('addpane', this)
25990 * Updates the tab title
25991 * @param {String} html to set the title to.
25993 setTitle: function(str)
25999 this.tab.select('a', true).first().dom.innerHTML = str;
26016 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26019 * @class Roo.bootstrap.menu.Menu
26020 * @extends Roo.bootstrap.Component
26021 * Bootstrap Menu class - container for Menu
26022 * @cfg {String} html Text of the menu
26023 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
26024 * @cfg {String} icon Font awesome icon
26025 * @cfg {String} pos Menu align to (top | bottom) default bottom
26029 * Create a new Menu
26030 * @param {Object} config The config object
26034 Roo.bootstrap.menu.Menu = function(config){
26035 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
26039 * @event beforeshow
26040 * Fires before this menu is displayed
26041 * @param {Roo.bootstrap.menu.Menu} this
26045 * @event beforehide
26046 * Fires before this menu is hidden
26047 * @param {Roo.bootstrap.menu.Menu} this
26052 * Fires after this menu is displayed
26053 * @param {Roo.bootstrap.menu.Menu} this
26058 * Fires after this menu is hidden
26059 * @param {Roo.bootstrap.menu.Menu} this
26064 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
26065 * @param {Roo.bootstrap.menu.Menu} this
26066 * @param {Roo.EventObject} e
26073 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
26077 weight : 'default',
26082 getChildContainer : function() {
26083 if(this.isSubMenu){
26087 return this.el.select('ul.dropdown-menu', true).first();
26090 getAutoCreate : function()
26095 cls : 'roo-menu-text',
26103 cls : 'fa ' + this.icon
26114 cls : 'dropdown-button btn btn-' + this.weight,
26119 cls : 'dropdown-toggle btn btn-' + this.weight,
26129 cls : 'dropdown-menu'
26135 if(this.pos == 'top'){
26136 cfg.cls += ' dropup';
26139 if(this.isSubMenu){
26142 cls : 'dropdown-menu'
26149 onRender : function(ct, position)
26151 this.isSubMenu = ct.hasClass('dropdown-submenu');
26153 Roo.bootstrap.menu.Menu.superclass.onRender.call(this, ct, position);
26156 initEvents : function()
26158 if(this.isSubMenu){
26162 this.hidden = true;
26164 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
26165 this.triggerEl.on('click', this.onTriggerPress, this);
26167 this.buttonEl = this.el.select('button.dropdown-button', true).first();
26168 this.buttonEl.on('click', this.onClick, this);
26174 if(this.isSubMenu){
26178 return this.el.select('ul.dropdown-menu', true).first();
26181 onClick : function(e)
26183 this.fireEvent("click", this, e);
26186 onTriggerPress : function(e)
26188 if (this.isVisible()) {
26195 isVisible : function(){
26196 return !this.hidden;
26201 this.fireEvent("beforeshow", this);
26203 this.hidden = false;
26204 this.el.addClass('open');
26206 Roo.get(document).on("mouseup", this.onMouseUp, this);
26208 this.fireEvent("show", this);
26215 this.fireEvent("beforehide", this);
26217 this.hidden = true;
26218 this.el.removeClass('open');
26220 Roo.get(document).un("mouseup", this.onMouseUp);
26222 this.fireEvent("hide", this);
26225 onMouseUp : function()
26239 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26242 * @class Roo.bootstrap.menu.Item
26243 * @extends Roo.bootstrap.Component
26244 * Bootstrap MenuItem class
26245 * @cfg {Boolean} submenu (true | false) default false
26246 * @cfg {String} html text of the item
26247 * @cfg {String} href the link
26248 * @cfg {Boolean} disable (true | false) default false
26249 * @cfg {Boolean} preventDefault (true | false) default true
26250 * @cfg {String} icon Font awesome icon
26251 * @cfg {String} pos Submenu align to (left | right) default right
26255 * Create a new Item
26256 * @param {Object} config The config object
26260 Roo.bootstrap.menu.Item = function(config){
26261 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
26265 * Fires when the mouse is hovering over this menu
26266 * @param {Roo.bootstrap.menu.Item} this
26267 * @param {Roo.EventObject} e
26272 * Fires when the mouse exits this menu
26273 * @param {Roo.bootstrap.menu.Item} this
26274 * @param {Roo.EventObject} e
26280 * The raw click event for the entire grid.
26281 * @param {Roo.EventObject} e
26287 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
26292 preventDefault: true,
26297 getAutoCreate : function()
26302 cls : 'roo-menu-item-text',
26310 cls : 'fa ' + this.icon
26319 href : this.href || '#',
26326 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
26330 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
26332 if(this.pos == 'left'){
26333 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
26340 initEvents : function()
26342 this.el.on('mouseover', this.onMouseOver, this);
26343 this.el.on('mouseout', this.onMouseOut, this);
26345 this.el.select('a', true).first().on('click', this.onClick, this);
26349 onClick : function(e)
26351 if(this.preventDefault){
26352 e.preventDefault();
26355 this.fireEvent("click", this, e);
26358 onMouseOver : function(e)
26360 if(this.submenu && this.pos == 'left'){
26361 this.el.select('ul.dropdown-menu', true).first().setLeft(this.el.select('ul.dropdown-menu', true).first().getWidth() * -1);
26364 this.fireEvent("mouseover", this, e);
26367 onMouseOut : function(e)
26369 this.fireEvent("mouseout", this, e);
26381 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
26384 * @class Roo.bootstrap.menu.Separator
26385 * @extends Roo.bootstrap.Component
26386 * Bootstrap Separator class
26389 * Create a new Separator
26390 * @param {Object} config The config object
26394 Roo.bootstrap.menu.Separator = function(config){
26395 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
26398 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
26400 getAutoCreate : function(){
26421 * @class Roo.bootstrap.Tooltip
26422 * Bootstrap Tooltip class
26423 * This is basic at present - all componets support it by default, however they should add tooltipEl() method
26424 * to determine which dom element triggers the tooltip.
26426 * It needs to add support for additional attributes like tooltip-position
26429 * Create a new Toolti
26430 * @param {Object} config The config object
26433 Roo.bootstrap.Tooltip = function(config){
26434 Roo.bootstrap.Tooltip.superclass.constructor.call(this, config);
26436 this.alignment = Roo.bootstrap.Tooltip.alignment;
26438 if(typeof(config) != 'undefined' && typeof(config.alignment) != 'undefined'){
26439 this.alignment = config.alignment;
26444 Roo.apply(Roo.bootstrap.Tooltip, {
26446 * @function init initialize tooltip monitoring.
26450 currentTip : false,
26451 currentRegion : false,
26457 Roo.get(document).on('mouseover', this.enter ,this);
26458 Roo.get(document).on('mouseout', this.leave, this);
26461 this.currentTip = new Roo.bootstrap.Tooltip();
26464 enter : function(ev)
26466 var dom = ev.getTarget();
26468 //Roo.log(['enter',dom]);
26469 var el = Roo.fly(dom);
26470 if (this.currentEl) {
26472 //Roo.log(this.currentEl);
26473 //Roo.log(this.currentEl.contains(dom));
26474 if (this.currentEl == el) {
26477 if (dom != this.currentEl.dom && this.currentEl.contains(dom)) {
26483 if (this.currentTip.el) {
26484 this.currentTip.el.setVisibilityMode(Roo.Element.DISPLAY).hide(); // force hiding...
26488 if(!el || el.dom == document){
26494 // you can not look for children, as if el is the body.. then everythign is the child..
26495 if (!el.attr('tooltip')) { //
26496 if (!el.select("[tooltip]").elements.length) {
26499 // is the mouse over this child...?
26500 bindEl = el.select("[tooltip]").first();
26501 var xy = ev.getXY();
26502 if (!bindEl.getRegion().contains( { top : xy[1] ,right : xy[0] , bottom : xy[1], left : xy[0]})) {
26503 //Roo.log("not in region.");
26506 //Roo.log("child element over..");
26509 this.currentEl = bindEl;
26510 this.currentTip.bind(bindEl);
26511 this.currentRegion = Roo.lib.Region.getRegion(dom);
26512 this.currentTip.enter();
26515 leave : function(ev)
26517 var dom = ev.getTarget();
26518 //Roo.log(['leave',dom]);
26519 if (!this.currentEl) {
26524 if (dom != this.currentEl.dom) {
26527 var xy = ev.getXY();
26528 if (this.currentRegion.contains( new Roo.lib.Region( xy[1], xy[0] ,xy[1], xy[0] ))) {
26531 // only activate leave if mouse cursor is outside... bounding box..
26536 if (this.currentTip) {
26537 this.currentTip.leave();
26539 //Roo.log('clear currentEl');
26540 this.currentEl = false;
26545 'left' : ['r-l', [-2,0], 'right'],
26546 'right' : ['l-r', [2,0], 'left'],
26547 'bottom' : ['t-b', [0,2], 'top'],
26548 'top' : [ 'b-t', [0,-2], 'bottom']
26554 Roo.extend(Roo.bootstrap.Tooltip, Roo.bootstrap.Component, {
26559 delay : null, // can be { show : 300 , hide: 500}
26563 hoverState : null, //???
26565 placement : 'bottom',
26569 getAutoCreate : function(){
26576 cls : 'tooltip-arrow'
26579 cls : 'tooltip-inner'
26586 bind : function(el)
26592 enter : function () {
26594 if (this.timeout != null) {
26595 clearTimeout(this.timeout);
26598 this.hoverState = 'in';
26599 //Roo.log("enter - show");
26600 if (!this.delay || !this.delay.show) {
26605 this.timeout = setTimeout(function () {
26606 if (_t.hoverState == 'in') {
26609 }, this.delay.show);
26613 clearTimeout(this.timeout);
26615 this.hoverState = 'out';
26616 if (!this.delay || !this.delay.hide) {
26622 this.timeout = setTimeout(function () {
26623 //Roo.log("leave - timeout");
26625 if (_t.hoverState == 'out') {
26627 Roo.bootstrap.Tooltip.currentEl = false;
26632 show : function (msg)
26635 this.render(document.body);
26638 //Roo.log([this.bindEl, this.bindEl.attr('tooltip')]);
26640 var tip = msg || this.bindEl.attr('tooltip') || this.bindEl.select("[tooltip]").first().attr('tooltip');
26642 this.el.select('.tooltip-inner',true).first().dom.innerHTML = tip;
26644 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
26646 var placement = typeof this.placement == 'function' ?
26647 this.placement.call(this, this.el, on_el) :
26650 var autoToken = /\s?auto?\s?/i;
26651 var autoPlace = autoToken.test(placement);
26653 placement = placement.replace(autoToken, '') || 'top';
26657 //this.el.setXY([0,0]);
26659 //this.el.dom.style.display='block';
26661 //this.el.appendTo(on_el);
26663 var p = this.getPosition();
26664 var box = this.el.getBox();
26670 var align = this.alignment[placement];
26672 var xy = this.el.getAlignToXY(this.bindEl, align[0], align[1]);
26674 if(placement == 'top' || placement == 'bottom'){
26676 placement = 'right';
26679 if(xy[0] + this.el.getWidth() > Roo.lib.Dom.getViewWidth()){
26680 placement = 'left';
26683 var scroll = Roo.select('body', true).first().getScroll();
26685 if(xy[1] > Roo.lib.Dom.getViewHeight() + scroll.top - this.el.getHeight()){
26689 align = this.alignment[placement];
26692 this.el.alignTo(this.bindEl, align[0],align[1]);
26693 //var arrow = this.el.select('.arrow',true).first();
26694 //arrow.set(align[2],
26696 this.el.addClass(placement);
26698 this.el.addClass('in fade');
26700 this.hoverState = null;
26702 if (this.el.hasClass('fade')) {
26713 //this.el.setXY([0,0]);
26714 this.el.removeClass('in');
26730 * @class Roo.bootstrap.LocationPicker
26731 * @extends Roo.bootstrap.Component
26732 * Bootstrap LocationPicker class
26733 * @cfg {Number} latitude Position when init default 0
26734 * @cfg {Number} longitude Position when init default 0
26735 * @cfg {Number} zoom default 15
26736 * @cfg {String} mapTypeId default google.maps.MapTypeId.ROADMAP
26737 * @cfg {Boolean} mapTypeControl default false
26738 * @cfg {Boolean} disableDoubleClickZoom default false
26739 * @cfg {Boolean} scrollwheel default true
26740 * @cfg {Boolean} streetViewControl default false
26741 * @cfg {Number} radius default 0
26742 * @cfg {String} locationName
26743 * @cfg {Boolean} draggable default true
26744 * @cfg {Boolean} enableAutocomplete default false
26745 * @cfg {Boolean} enableReverseGeocode default true
26746 * @cfg {String} markerTitle
26749 * Create a new LocationPicker
26750 * @param {Object} config The config object
26754 Roo.bootstrap.LocationPicker = function(config){
26756 Roo.bootstrap.LocationPicker.superclass.constructor.call(this, config);
26761 * Fires when the picker initialized.
26762 * @param {Roo.bootstrap.LocationPicker} this
26763 * @param {Google Location} location
26767 * @event positionchanged
26768 * Fires when the picker position changed.
26769 * @param {Roo.bootstrap.LocationPicker} this
26770 * @param {Google Location} location
26772 positionchanged : true,
26775 * Fires when the map resize.
26776 * @param {Roo.bootstrap.LocationPicker} this
26781 * Fires when the map show.
26782 * @param {Roo.bootstrap.LocationPicker} this
26787 * Fires when the map hide.
26788 * @param {Roo.bootstrap.LocationPicker} this
26793 * Fires when click the map.
26794 * @param {Roo.bootstrap.LocationPicker} this
26795 * @param {Map event} e
26799 * @event mapRightClick
26800 * Fires when right click the map.
26801 * @param {Roo.bootstrap.LocationPicker} this
26802 * @param {Map event} e
26804 mapRightClick : true,
26806 * @event markerClick
26807 * Fires when click the marker.
26808 * @param {Roo.bootstrap.LocationPicker} this
26809 * @param {Map event} e
26811 markerClick : true,
26813 * @event markerRightClick
26814 * Fires when right click the marker.
26815 * @param {Roo.bootstrap.LocationPicker} this
26816 * @param {Map event} e
26818 markerRightClick : true,
26820 * @event OverlayViewDraw
26821 * Fires when OverlayView Draw
26822 * @param {Roo.bootstrap.LocationPicker} this
26824 OverlayViewDraw : true,
26826 * @event OverlayViewOnAdd
26827 * Fires when OverlayView Draw
26828 * @param {Roo.bootstrap.LocationPicker} this
26830 OverlayViewOnAdd : true,
26832 * @event OverlayViewOnRemove
26833 * Fires when OverlayView Draw
26834 * @param {Roo.bootstrap.LocationPicker} this
26836 OverlayViewOnRemove : true,
26838 * @event OverlayViewShow
26839 * Fires when OverlayView Draw
26840 * @param {Roo.bootstrap.LocationPicker} this
26841 * @param {Pixel} cpx
26843 OverlayViewShow : true,
26845 * @event OverlayViewHide
26846 * Fires when OverlayView Draw
26847 * @param {Roo.bootstrap.LocationPicker} this
26849 OverlayViewHide : true,
26851 * @event loadexception
26852 * Fires when load google lib failed.
26853 * @param {Roo.bootstrap.LocationPicker} this
26855 loadexception : true
26860 Roo.extend(Roo.bootstrap.LocationPicker, Roo.bootstrap.Component, {
26862 gMapContext: false,
26868 mapTypeControl: false,
26869 disableDoubleClickZoom: false,
26871 streetViewControl: false,
26875 enableAutocomplete: false,
26876 enableReverseGeocode: true,
26879 getAutoCreate: function()
26884 cls: 'roo-location-picker'
26890 initEvents: function(ct, position)
26892 if(!this.el.getWidth() || this.isApplied()){
26896 this.el.setVisibilityMode(Roo.Element.DISPLAY);
26901 initial: function()
26903 if(typeof(google) == 'undefined' || typeof(google.maps) == 'undefined'){
26904 this.fireEvent('loadexception', this);
26908 if(!this.mapTypeId){
26909 this.mapTypeId = google.maps.MapTypeId.ROADMAP;
26912 this.gMapContext = this.GMapContext();
26914 this.initOverlayView();
26916 this.OverlayView = new Roo.bootstrap.LocationPicker.OverlayView(this.gMapContext.map);
26920 google.maps.event.addListener(this.gMapContext.marker, "dragend", function(event) {
26921 _this.setPosition(_this.gMapContext.marker.position);
26924 google.maps.event.addListener(this.gMapContext.map, 'click', function(event){
26925 _this.fireEvent('mapClick', this, event);
26929 google.maps.event.addListener(this.gMapContext.map, 'rightclick', function(event){
26930 _this.fireEvent('mapRightClick', this, event);
26934 google.maps.event.addListener(this.gMapContext.marker, 'click', function(event){
26935 _this.fireEvent('markerClick', this, event);
26939 google.maps.event.addListener(this.gMapContext.marker, 'rightclick', function(event){
26940 _this.fireEvent('markerRightClick', this, event);
26944 this.setPosition(this.gMapContext.location);
26946 this.fireEvent('initial', this, this.gMapContext.location);
26949 initOverlayView: function()
26953 Roo.bootstrap.LocationPicker.OverlayView.prototype = Roo.apply(new google.maps.OverlayView(), {
26957 _this.fireEvent('OverlayViewDraw', _this);
26962 _this.fireEvent('OverlayViewOnAdd', _this);
26965 onRemove: function()
26967 _this.fireEvent('OverlayViewOnRemove', _this);
26970 show: function(cpx)
26972 _this.fireEvent('OverlayViewShow', _this, cpx);
26977 _this.fireEvent('OverlayViewHide', _this);
26983 fromLatLngToContainerPixel: function(event)
26985 return this.OverlayView.getProjection().fromLatLngToContainerPixel(event.latLng);
26988 isApplied: function()
26990 return this.getGmapContext() == false ? false : true;
26993 getGmapContext: function()
26995 return (typeof(this.gMapContext) == 'undefined') ? false : this.gMapContext;
26998 GMapContext: function()
27000 var position = new google.maps.LatLng(this.latitude, this.longitude);
27002 var _map = new google.maps.Map(this.el.dom, {
27005 mapTypeId: this.mapTypeId,
27006 mapTypeControl: this.mapTypeControl,
27007 disableDoubleClickZoom: this.disableDoubleClickZoom,
27008 scrollwheel: this.scrollwheel,
27009 streetViewControl: this.streetViewControl,
27010 locationName: this.locationName,
27011 draggable: this.draggable,
27012 enableAutocomplete: this.enableAutocomplete,
27013 enableReverseGeocode: this.enableReverseGeocode
27016 var _marker = new google.maps.Marker({
27017 position: position,
27019 title: this.markerTitle,
27020 draggable: this.draggable
27027 location: position,
27028 radius: this.radius,
27029 locationName: this.locationName,
27030 addressComponents: {
27031 formatted_address: null,
27032 addressLine1: null,
27033 addressLine2: null,
27035 streetNumber: null,
27039 stateOrProvince: null
27042 domContainer: this.el.dom,
27043 geodecoder: new google.maps.Geocoder()
27047 drawCircle: function(center, radius, options)
27049 if (this.gMapContext.circle != null) {
27050 this.gMapContext.circle.setMap(null);
27054 options = Roo.apply({}, options, {
27055 strokeColor: "#0000FF",
27056 strokeOpacity: .35,
27058 fillColor: "#0000FF",
27062 options.map = this.gMapContext.map;
27063 options.radius = radius;
27064 options.center = center;
27065 this.gMapContext.circle = new google.maps.Circle(options);
27066 return this.gMapContext.circle;
27072 setPosition: function(location)
27074 this.gMapContext.location = location;
27075 this.gMapContext.marker.setPosition(location);
27076 this.gMapContext.map.panTo(location);
27077 this.drawCircle(location, this.gMapContext.radius, {});
27081 if (this.gMapContext.settings.enableReverseGeocode) {
27082 this.gMapContext.geodecoder.geocode({
27083 latLng: this.gMapContext.location
27084 }, function(results, status) {
27086 if (status == google.maps.GeocoderStatus.OK && results.length > 0) {
27087 _this.gMapContext.locationName = results[0].formatted_address;
27088 _this.gMapContext.addressComponents = _this.address_component_from_google_geocode(results[0].address_components);
27090 _this.fireEvent('positionchanged', this, location);
27097 this.fireEvent('positionchanged', this, location);
27102 google.maps.event.trigger(this.gMapContext.map, "resize");
27104 this.gMapContext.map.setCenter(this.gMapContext.marker.position);
27106 this.fireEvent('resize', this);
27109 setPositionByLatLng: function(latitude, longitude)
27111 this.setPosition(new google.maps.LatLng(latitude, longitude));
27114 getCurrentPosition: function()
27117 latitude: this.gMapContext.location.lat(),
27118 longitude: this.gMapContext.location.lng()
27122 getAddressName: function()
27124 return this.gMapContext.locationName;
27127 getAddressComponents: function()
27129 return this.gMapContext.addressComponents;
27132 address_component_from_google_geocode: function(address_components)
27136 for (var i = 0; i < address_components.length; i++) {
27137 var component = address_components[i];
27138 if (component.types.indexOf("postal_code") >= 0) {
27139 result.postalCode = component.short_name;
27140 } else if (component.types.indexOf("street_number") >= 0) {
27141 result.streetNumber = component.short_name;
27142 } else if (component.types.indexOf("route") >= 0) {
27143 result.streetName = component.short_name;
27144 } else if (component.types.indexOf("neighborhood") >= 0) {
27145 result.city = component.short_name;
27146 } else if (component.types.indexOf("locality") >= 0) {
27147 result.city = component.short_name;
27148 } else if (component.types.indexOf("sublocality") >= 0) {
27149 result.district = component.short_name;
27150 } else if (component.types.indexOf("administrative_area_level_1") >= 0) {
27151 result.stateOrProvince = component.short_name;
27152 } else if (component.types.indexOf("country") >= 0) {
27153 result.country = component.short_name;
27157 result.addressLine1 = [ result.streetNumber, result.streetName ].join(" ").trim();
27158 result.addressLine2 = "";
27162 setZoomLevel: function(zoom)
27164 this.gMapContext.map.setZoom(zoom);
27177 this.fireEvent('show', this);
27188 this.fireEvent('hide', this);
27193 Roo.apply(Roo.bootstrap.LocationPicker, {
27195 OverlayView : function(map, options)
27197 options = options || {};
27211 * @class Roo.bootstrap.Alert
27212 * @extends Roo.bootstrap.Component
27213 * Bootstrap Alert class
27214 * @cfg {String} title The title of alert
27215 * @cfg {String} html The content of alert
27216 * @cfg {String} weight ( success | info | warning | danger )
27217 * @cfg {String} faicon font-awesomeicon
27220 * Create a new alert
27221 * @param {Object} config The config object
27225 Roo.bootstrap.Alert = function(config){
27226 Roo.bootstrap.Alert.superclass.constructor.call(this, config);
27230 Roo.extend(Roo.bootstrap.Alert, Roo.bootstrap.Component, {
27237 getAutoCreate : function()
27246 cls : 'roo-alert-icon'
27251 cls : 'roo-alert-title',
27256 cls : 'roo-alert-text',
27263 cfg.cn[0].cls += ' fa ' + this.faicon;
27267 cfg.cls += ' alert-' + this.weight;
27273 initEvents: function()
27275 this.el.setVisibilityMode(Roo.Element.DISPLAY);
27278 setTitle : function(str)
27280 this.el.select('.roo-alert-title',true).first().dom.innerHTML = str;
27283 setText : function(str)
27285 this.el.select('.roo-alert-text',true).first().dom.innerHTML = str;
27288 setWeight : function(weight)
27291 this.el.select('.alert',true).first().removeClass('alert-' + this.weight);
27294 this.weight = weight;
27296 this.el.select('.alert',true).first().addClass('alert-' + this.weight);
27299 setIcon : function(icon)
27302 this.el.select('.roo-alert-icon',true).first().removeClass(['fa', 'fa-' + this.faicon]);
27305 this.faicon = icon;
27307 this.el.select('.roo-alert-icon',true).first().addClass(['fa', 'fa-' + this.faicon]);
27328 * @class Roo.bootstrap.UploadCropbox
27329 * @extends Roo.bootstrap.Component
27330 * Bootstrap UploadCropbox class
27331 * @cfg {String} emptyText show when image has been loaded
27332 * @cfg {String} rotateNotify show when image too small to rotate
27333 * @cfg {Number} errorTimeout default 3000
27334 * @cfg {Number} minWidth default 300
27335 * @cfg {Number} minHeight default 300
27336 * @cfg {Array} buttons default ['rotateLeft', 'pictureBtn', 'rotateRight']
27337 * @cfg {Boolean} isDocument (true|false) default false
27338 * @cfg {String} url action url
27339 * @cfg {String} paramName default 'imageUpload'
27340 * @cfg {String} method default POST
27341 * @cfg {Boolean} loadMask (true|false) default true
27342 * @cfg {Boolean} loadingText default 'Loading...'
27345 * Create a new UploadCropbox
27346 * @param {Object} config The config object
27349 Roo.bootstrap.UploadCropbox = function(config){
27350 Roo.bootstrap.UploadCropbox.superclass.constructor.call(this, config);
27354 * @event beforeselectfile
27355 * Fire before select file
27356 * @param {Roo.bootstrap.UploadCropbox} this
27358 "beforeselectfile" : true,
27361 * Fire after initEvent
27362 * @param {Roo.bootstrap.UploadCropbox} this
27367 * Fire after initEvent
27368 * @param {Roo.bootstrap.UploadCropbox} this
27369 * @param {String} data
27374 * Fire when preparing the file data
27375 * @param {Roo.bootstrap.UploadCropbox} this
27376 * @param {Object} file
27381 * Fire when get exception
27382 * @param {Roo.bootstrap.UploadCropbox} this
27383 * @param {XMLHttpRequest} xhr
27385 "exception" : true,
27387 * @event beforeloadcanvas
27388 * Fire before load the canvas
27389 * @param {Roo.bootstrap.UploadCropbox} this
27390 * @param {String} src
27392 "beforeloadcanvas" : true,
27395 * Fire when trash image
27396 * @param {Roo.bootstrap.UploadCropbox} this
27401 * Fire when download the image
27402 * @param {Roo.bootstrap.UploadCropbox} this
27406 * @event footerbuttonclick
27407 * Fire when footerbuttonclick
27408 * @param {Roo.bootstrap.UploadCropbox} this
27409 * @param {String} type
27411 "footerbuttonclick" : true,
27415 * @param {Roo.bootstrap.UploadCropbox} this
27420 * Fire when rotate the image
27421 * @param {Roo.bootstrap.UploadCropbox} this
27422 * @param {String} pos
27427 * Fire when inspect the file
27428 * @param {Roo.bootstrap.UploadCropbox} this
27429 * @param {Object} file
27434 * Fire when xhr upload the file
27435 * @param {Roo.bootstrap.UploadCropbox} this
27436 * @param {Object} data
27441 * Fire when arrange the file data
27442 * @param {Roo.bootstrap.UploadCropbox} this
27443 * @param {Object} formData
27448 this.buttons = this.buttons || Roo.bootstrap.UploadCropbox.footer.STANDARD;
27451 Roo.extend(Roo.bootstrap.UploadCropbox, Roo.bootstrap.Component, {
27453 emptyText : 'Click to upload image',
27454 rotateNotify : 'Image is too small to rotate',
27455 errorTimeout : 3000,
27469 cropType : 'image/jpeg',
27471 canvasLoaded : false,
27472 isDocument : false,
27474 paramName : 'imageUpload',
27476 loadingText : 'Loading...',
27479 getAutoCreate : function()
27483 cls : 'roo-upload-cropbox',
27487 cls : 'roo-upload-cropbox-selector',
27492 cls : 'roo-upload-cropbox-body',
27493 style : 'cursor:pointer',
27497 cls : 'roo-upload-cropbox-preview'
27501 cls : 'roo-upload-cropbox-thumb'
27505 cls : 'roo-upload-cropbox-empty-notify',
27506 html : this.emptyText
27510 cls : 'roo-upload-cropbox-error-notify alert alert-danger',
27511 html : this.rotateNotify
27517 cls : 'roo-upload-cropbox-footer',
27520 cls : 'btn-group btn-group-justified roo-upload-cropbox-btn-group',
27530 onRender : function(ct, position)
27532 Roo.bootstrap.UploadCropbox.superclass.onRender.call(this, ct, position);
27534 if (this.buttons.length) {
27536 Roo.each(this.buttons, function(bb) {
27538 var btn = this.el.select('.roo-upload-cropbox-footer div.roo-upload-cropbox-btn-group').first().createChild(bb);
27540 btn.on('click', this.onFooterButtonClick.createDelegate(this, [bb.action], true));
27546 this.maskEl = this.el;
27550 initEvents : function()
27552 this.urlAPI = (window.createObjectURL && window) ||
27553 (window.URL && URL.revokeObjectURL && URL) ||
27554 (window.webkitURL && webkitURL);
27556 this.bodyEl = this.el.select('.roo-upload-cropbox-body', true).first();
27557 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27559 this.selectorEl = this.el.select('.roo-upload-cropbox-selector', true).first();
27560 this.selectorEl.hide();
27562 this.previewEl = this.el.select('.roo-upload-cropbox-preview', true).first();
27563 this.previewEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27565 this.thumbEl = this.el.select('.roo-upload-cropbox-thumb', true).first();
27566 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27567 this.thumbEl.hide();
27569 this.notifyEl = this.el.select('.roo-upload-cropbox-empty-notify', true).first();
27570 this.notifyEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27572 this.errorEl = this.el.select('.roo-upload-cropbox-error-notify', true).first();
27573 this.errorEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27574 this.errorEl.hide();
27576 this.footerEl = this.el.select('.roo-upload-cropbox-footer', true).first();
27577 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
27578 this.footerEl.hide();
27580 this.setThumbBoxSize();
27586 this.fireEvent('initial', this);
27593 window.addEventListener("resize", function() { _this.resize(); } );
27595 this.bodyEl.on('click', this.beforeSelectFile, this);
27598 this.bodyEl.on('touchstart', this.onTouchStart, this);
27599 this.bodyEl.on('touchmove', this.onTouchMove, this);
27600 this.bodyEl.on('touchend', this.onTouchEnd, this);
27604 this.bodyEl.on('mousedown', this.onMouseDown, this);
27605 this.bodyEl.on('mousemove', this.onMouseMove, this);
27606 var mousewheel = (/Firefox/i.test(navigator.userAgent))? 'DOMMouseScroll' : 'mousewheel';
27607 this.bodyEl.on(mousewheel, this.onMouseWheel, this);
27608 Roo.get(document).on('mouseup', this.onMouseUp, this);
27611 this.selectorEl.on('change', this.onFileSelected, this);
27617 this.baseScale = 1;
27619 this.baseRotate = 1;
27620 this.dragable = false;
27621 this.pinching = false;
27624 this.cropData = false;
27625 this.notifyEl.dom.innerHTML = this.emptyText;
27627 this.selectorEl.dom.value = '';
27631 resize : function()
27633 if(this.fireEvent('resize', this) != false){
27634 this.setThumbBoxPosition();
27635 this.setCanvasPosition();
27639 onFooterButtonClick : function(e, el, o, type)
27642 case 'rotate-left' :
27643 this.onRotateLeft(e);
27645 case 'rotate-right' :
27646 this.onRotateRight(e);
27649 this.beforeSelectFile(e);
27664 this.fireEvent('footerbuttonclick', this, type);
27667 beforeSelectFile : function(e)
27669 e.preventDefault();
27671 if(this.fireEvent('beforeselectfile', this) != false){
27672 this.selectorEl.dom.click();
27676 onFileSelected : function(e)
27678 e.preventDefault();
27680 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
27684 var file = this.selectorEl.dom.files[0];
27686 if(this.fireEvent('inspect', this, file) != false){
27687 this.prepare(file);
27692 trash : function(e)
27694 this.fireEvent('trash', this);
27697 download : function(e)
27699 this.fireEvent('download', this);
27702 loadCanvas : function(src)
27704 if(this.fireEvent('beforeloadcanvas', this, src) != false){
27708 this.imageEl = document.createElement('img');
27712 this.imageEl.addEventListener("load", function(){ _this.onLoadCanvas(); });
27714 this.imageEl.src = src;
27718 onLoadCanvas : function()
27720 this.imageEl.OriginWidth = this.imageEl.naturalWidth || this.imageEl.width;
27721 this.imageEl.OriginHeight = this.imageEl.naturalHeight || this.imageEl.height;
27723 this.bodyEl.un('click', this.beforeSelectFile, this);
27725 this.notifyEl.hide();
27726 this.thumbEl.show();
27727 this.footerEl.show();
27729 this.baseRotateLevel();
27731 if(this.isDocument){
27732 this.setThumbBoxSize();
27735 this.setThumbBoxPosition();
27737 this.baseScaleLevel();
27743 this.canvasLoaded = true;
27746 this.maskEl.unmask();
27751 setCanvasPosition : function()
27753 if(!this.canvasEl){
27757 var pw = Math.ceil((this.bodyEl.getWidth() - this.canvasEl.width) / 2);
27758 var ph = Math.ceil((this.bodyEl.getHeight() - this.canvasEl.height) / 2);
27760 this.previewEl.setLeft(pw);
27761 this.previewEl.setTop(ph);
27765 onMouseDown : function(e)
27769 this.dragable = true;
27770 this.pinching = false;
27772 if(this.isDocument && (this.canvasEl.width < this.thumbEl.getWidth() || this.canvasEl.height < this.thumbEl.getHeight())){
27773 this.dragable = false;
27777 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27778 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27782 onMouseMove : function(e)
27786 if(!this.canvasLoaded){
27790 if (!this.dragable){
27794 var minX = Math.ceil(this.thumbEl.getLeft(true));
27795 var minY = Math.ceil(this.thumbEl.getTop(true));
27797 var maxX = Math.ceil(minX + this.thumbEl.getWidth() - this.canvasEl.width);
27798 var maxY = Math.ceil(minY + this.thumbEl.getHeight() - this.canvasEl.height);
27800 var x = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27801 var y = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27803 x = x - this.mouseX;
27804 y = y - this.mouseY;
27806 var bgX = Math.ceil(x + this.previewEl.getLeft(true));
27807 var bgY = Math.ceil(y + this.previewEl.getTop(true));
27809 bgX = (minX < bgX) ? minX : ((maxX > bgX) ? maxX : bgX);
27810 bgY = (minY < bgY) ? minY : ((maxY > bgY) ? maxY : bgY);
27812 this.previewEl.setLeft(bgX);
27813 this.previewEl.setTop(bgY);
27815 this.mouseX = Roo.isTouch ? e.browserEvent.touches[0].pageX : e.getPageX();
27816 this.mouseY = Roo.isTouch ? e.browserEvent.touches[0].pageY : e.getPageY();
27819 onMouseUp : function(e)
27823 this.dragable = false;
27826 onMouseWheel : function(e)
27830 this.startScale = this.scale;
27832 this.scale = (e.getWheelDelta() == 1) ? (this.scale + 1) : (this.scale - 1);
27834 if(!this.zoomable()){
27835 this.scale = this.startScale;
27844 zoomable : function()
27846 var minScale = this.thumbEl.getWidth() / this.minWidth;
27848 if(this.minWidth < this.minHeight){
27849 minScale = this.thumbEl.getHeight() / this.minHeight;
27852 var width = Math.ceil(this.imageEl.OriginWidth * this.getScaleLevel() / minScale);
27853 var height = Math.ceil(this.imageEl.OriginHeight * this.getScaleLevel() / minScale);
27857 (this.rotate == 0 || this.rotate == 180) &&
27859 width > this.imageEl.OriginWidth ||
27860 height > this.imageEl.OriginHeight ||
27861 (width < this.minWidth && height < this.minHeight)
27869 (this.rotate == 90 || this.rotate == 270) &&
27871 width > this.imageEl.OriginWidth ||
27872 height > this.imageEl.OriginHeight ||
27873 (width < this.minHeight && height < this.minWidth)
27880 !this.isDocument &&
27881 (this.rotate == 0 || this.rotate == 180) &&
27883 width < this.minWidth ||
27884 width > this.imageEl.OriginWidth ||
27885 height < this.minHeight ||
27886 height > this.imageEl.OriginHeight
27893 !this.isDocument &&
27894 (this.rotate == 90 || this.rotate == 270) &&
27896 width < this.minHeight ||
27897 width > this.imageEl.OriginWidth ||
27898 height < this.minWidth ||
27899 height > this.imageEl.OriginHeight
27909 onRotateLeft : function(e)
27911 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27913 var minScale = this.thumbEl.getWidth() / this.minWidth;
27915 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27916 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27918 this.startScale = this.scale;
27920 while (this.getScaleLevel() < minScale){
27922 this.scale = this.scale + 1;
27924 if(!this.zoomable()){
27929 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27930 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27935 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27942 this.scale = this.startScale;
27944 this.onRotateFail();
27949 this.rotate = (this.rotate < 90) ? 270 : this.rotate - 90;
27951 if(this.isDocument){
27952 this.setThumbBoxSize();
27953 this.setThumbBoxPosition();
27954 this.setCanvasPosition();
27959 this.fireEvent('rotate', this, 'left');
27963 onRotateRight : function(e)
27965 if(!this.isDocument && (this.canvasEl.height < this.thumbEl.getWidth() || this.canvasEl.width < this.thumbEl.getHeight())){
27967 var minScale = this.thumbEl.getWidth() / this.minWidth;
27969 var bw = Math.ceil(this.canvasEl.width / this.getScaleLevel());
27970 var bh = Math.ceil(this.canvasEl.height / this.getScaleLevel());
27972 this.startScale = this.scale;
27974 while (this.getScaleLevel() < minScale){
27976 this.scale = this.scale + 1;
27978 if(!this.zoomable()){
27983 Math.ceil(bw * this.getScaleLevel()) < this.thumbEl.getHeight() ||
27984 Math.ceil(bh * this.getScaleLevel()) < this.thumbEl.getWidth()
27989 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
27996 this.scale = this.startScale;
27998 this.onRotateFail();
28003 this.rotate = (this.rotate > 180) ? 0 : this.rotate + 90;
28005 if(this.isDocument){
28006 this.setThumbBoxSize();
28007 this.setThumbBoxPosition();
28008 this.setCanvasPosition();
28013 this.fireEvent('rotate', this, 'right');
28016 onRotateFail : function()
28018 this.errorEl.show(true);
28022 (function() { _this.errorEl.hide(true); }).defer(this.errorTimeout);
28027 this.previewEl.dom.innerHTML = '';
28029 var canvasEl = document.createElement("canvas");
28031 var contextEl = canvasEl.getContext("2d");
28033 canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28034 canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28035 var center = this.imageEl.OriginWidth / 2;
28037 if(this.imageEl.OriginWidth < this.imageEl.OriginHeight){
28038 canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28039 canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28040 center = this.imageEl.OriginHeight / 2;
28043 contextEl.scale(this.getScaleLevel(), this.getScaleLevel());
28045 contextEl.translate(center, center);
28046 contextEl.rotate(this.rotate * Math.PI / 180);
28048 contextEl.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28050 this.canvasEl = document.createElement("canvas");
28052 this.contextEl = this.canvasEl.getContext("2d");
28054 switch (this.rotate) {
28057 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28058 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28060 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28065 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28066 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28068 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28069 this.contextEl.drawImage(canvasEl, Math.abs(this.canvasEl.width - this.canvasEl.height), 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28073 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28078 this.canvasEl.width = this.imageEl.OriginWidth * this.getScaleLevel();
28079 this.canvasEl.height = this.imageEl.OriginHeight * this.getScaleLevel();
28081 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28082 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);
28086 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);
28091 this.canvasEl.width = this.imageEl.OriginHeight * this.getScaleLevel();
28092 this.canvasEl.height = this.imageEl.OriginWidth * this.getScaleLevel();
28094 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28095 this.contextEl.drawImage(canvasEl, 0, 0, this.canvasEl.width, this.canvasEl.height, 0, 0, this.canvasEl.width, this.canvasEl.height);
28099 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);
28106 this.previewEl.appendChild(this.canvasEl);
28108 this.setCanvasPosition();
28113 if(!this.canvasLoaded){
28117 var imageCanvas = document.createElement("canvas");
28119 var imageContext = imageCanvas.getContext("2d");
28121 imageCanvas.width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28122 imageCanvas.height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? this.imageEl.OriginWidth : this.imageEl.OriginHeight;
28124 var center = imageCanvas.width / 2;
28126 imageContext.translate(center, center);
28128 imageContext.rotate(this.rotate * Math.PI / 180);
28130 imageContext.drawImage(this.imageEl, 0, 0, this.imageEl.OriginWidth, this.imageEl.OriginHeight, center * -1, center * -1, this.imageEl.OriginWidth, this.imageEl.OriginHeight);
28132 var canvas = document.createElement("canvas");
28134 var context = canvas.getContext("2d");
28136 canvas.width = this.minWidth;
28137 canvas.height = this.minHeight;
28139 switch (this.rotate) {
28142 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28143 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28145 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28146 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28148 var targetWidth = this.minWidth - 2 * x;
28149 var targetHeight = this.minHeight - 2 * y;
28153 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28154 scale = targetWidth / width;
28157 if(x > 0 && y == 0){
28158 scale = targetHeight / height;
28161 if(x > 0 && y > 0){
28162 scale = targetWidth / width;
28164 if(width < height){
28165 scale = targetHeight / height;
28169 context.scale(scale, scale);
28171 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28172 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28174 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28175 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28177 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28182 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28183 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28185 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28186 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28188 var targetWidth = this.minWidth - 2 * x;
28189 var targetHeight = this.minHeight - 2 * y;
28193 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28194 scale = targetWidth / width;
28197 if(x > 0 && y == 0){
28198 scale = targetHeight / height;
28201 if(x > 0 && y > 0){
28202 scale = targetWidth / width;
28204 if(width < height){
28205 scale = targetHeight / height;
28209 context.scale(scale, scale);
28211 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28212 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28214 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28215 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28217 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28219 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28224 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getWidth() / this.getScaleLevel());
28225 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getHeight() / this.getScaleLevel());
28227 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28228 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28230 var targetWidth = this.minWidth - 2 * x;
28231 var targetHeight = this.minHeight - 2 * y;
28235 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28236 scale = targetWidth / width;
28239 if(x > 0 && y == 0){
28240 scale = targetHeight / height;
28243 if(x > 0 && y > 0){
28244 scale = targetWidth / width;
28246 if(width < height){
28247 scale = targetHeight / height;
28251 context.scale(scale, scale);
28253 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28254 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28256 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28257 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28259 sx += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28260 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight) : 0;
28262 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28267 var width = (this.thumbEl.getWidth() / this.getScaleLevel() > this.imageEl.OriginHeight) ? this.imageEl.OriginHeight : (this.thumbEl.getWidth() / this.getScaleLevel());
28268 var height = (this.thumbEl.getHeight() / this.getScaleLevel() > this.imageEl.OriginWidth) ? this.imageEl.OriginWidth : (this.thumbEl.getHeight() / this.getScaleLevel());
28270 var x = (this.thumbEl.getLeft(true) > this.previewEl.getLeft(true)) ? 0 : ((this.previewEl.getLeft(true) - this.thumbEl.getLeft(true)) / this.getScaleLevel());
28271 var y = (this.thumbEl.getTop(true) > this.previewEl.getTop(true)) ? 0 : ((this.previewEl.getTop(true) - this.thumbEl.getTop(true)) / this.getScaleLevel());
28273 var targetWidth = this.minWidth - 2 * x;
28274 var targetHeight = this.minHeight - 2 * y;
28278 if((x == 0 && y == 0) || (x == 0 && y > 0)){
28279 scale = targetWidth / width;
28282 if(x > 0 && y == 0){
28283 scale = targetHeight / height;
28286 if(x > 0 && y > 0){
28287 scale = targetWidth / width;
28289 if(width < height){
28290 scale = targetHeight / height;
28294 context.scale(scale, scale);
28296 var sx = Math.min(this.canvasEl.width - this.thumbEl.getWidth(), this.thumbEl.getLeft(true) - this.previewEl.getLeft(true));
28297 var sy = Math.min(this.canvasEl.height - this.thumbEl.getHeight(), this.thumbEl.getTop(true) - this.previewEl.getTop(true));
28299 sx = sx < 0 ? 0 : (sx / this.getScaleLevel());
28300 sy = sy < 0 ? 0 : (sy / this.getScaleLevel());
28302 sy += (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? 0 : Math.abs(this.imageEl.OriginWidth - this.imageEl.OriginHeight);
28304 context.drawImage(imageCanvas, sx, sy, width, height, x, y, width, height);
28311 this.cropData = canvas.toDataURL(this.cropType);
28313 if(this.fireEvent('crop', this, this.cropData) !== false){
28314 this.process(this.file, this.cropData);
28321 setThumbBoxSize : function()
28325 if(this.isDocument && typeof(this.imageEl) != 'undefined'){
28326 width = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.max(this.minWidth, this.minHeight) : Math.min(this.minWidth, this.minHeight);
28327 height = (this.imageEl.OriginWidth > this.imageEl.OriginHeight) ? Math.min(this.minWidth, this.minHeight) : Math.max(this.minWidth, this.minHeight);
28329 this.minWidth = width;
28330 this.minHeight = height;
28332 if(this.rotate == 90 || this.rotate == 270){
28333 this.minWidth = height;
28334 this.minHeight = width;
28339 width = Math.ceil(this.minWidth * height / this.minHeight);
28341 if(this.minWidth > this.minHeight){
28343 height = Math.ceil(this.minHeight * width / this.minWidth);
28346 this.thumbEl.setStyle({
28347 width : width + 'px',
28348 height : height + 'px'
28355 setThumbBoxPosition : function()
28357 var x = Math.ceil((this.bodyEl.getWidth() - this.thumbEl.getWidth()) / 2 );
28358 var y = Math.ceil((this.bodyEl.getHeight() - this.thumbEl.getHeight()) / 2);
28360 this.thumbEl.setLeft(x);
28361 this.thumbEl.setTop(y);
28365 baseRotateLevel : function()
28367 this.baseRotate = 1;
28370 typeof(this.exif) != 'undefined' &&
28371 typeof(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != 'undefined' &&
28372 [1, 3, 6, 8].indexOf(this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']]) != -1
28374 this.baseRotate = this.exif[Roo.bootstrap.UploadCropbox['tags']['Orientation']];
28377 this.rotate = Roo.bootstrap.UploadCropbox['Orientation'][this.baseRotate];
28381 baseScaleLevel : function()
28385 if(this.isDocument){
28387 if(this.baseRotate == 6 || this.baseRotate == 8){
28389 height = this.thumbEl.getHeight();
28390 this.baseScale = height / this.imageEl.OriginWidth;
28392 if(this.imageEl.OriginHeight * this.baseScale > this.thumbEl.getWidth()){
28393 width = this.thumbEl.getWidth();
28394 this.baseScale = width / this.imageEl.OriginHeight;
28400 height = this.thumbEl.getHeight();
28401 this.baseScale = height / this.imageEl.OriginHeight;
28403 if(this.imageEl.OriginWidth * this.baseScale > this.thumbEl.getWidth()){
28404 width = this.thumbEl.getWidth();
28405 this.baseScale = width / this.imageEl.OriginWidth;
28411 if(this.baseRotate == 6 || this.baseRotate == 8){
28413 width = this.thumbEl.getHeight();
28414 this.baseScale = width / this.imageEl.OriginHeight;
28416 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getWidth()){
28417 height = this.thumbEl.getWidth();
28418 this.baseScale = height / this.imageEl.OriginHeight;
28421 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28422 height = this.thumbEl.getWidth();
28423 this.baseScale = height / this.imageEl.OriginHeight;
28425 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getHeight()){
28426 width = this.thumbEl.getHeight();
28427 this.baseScale = width / this.imageEl.OriginWidth;
28434 width = this.thumbEl.getWidth();
28435 this.baseScale = width / this.imageEl.OriginWidth;
28437 if(this.imageEl.OriginHeight * this.baseScale < this.thumbEl.getHeight()){
28438 height = this.thumbEl.getHeight();
28439 this.baseScale = height / this.imageEl.OriginHeight;
28442 if(this.imageEl.OriginWidth > this.imageEl.OriginHeight){
28444 height = this.thumbEl.getHeight();
28445 this.baseScale = height / this.imageEl.OriginHeight;
28447 if(this.imageEl.OriginWidth * this.baseScale < this.thumbEl.getWidth()){
28448 width = this.thumbEl.getWidth();
28449 this.baseScale = width / this.imageEl.OriginWidth;
28457 getScaleLevel : function()
28459 return this.baseScale * Math.pow(1.1, this.scale);
28462 onTouchStart : function(e)
28464 if(!this.canvasLoaded){
28465 this.beforeSelectFile(e);
28469 var touches = e.browserEvent.touches;
28475 if(touches.length == 1){
28476 this.onMouseDown(e);
28480 if(touches.length != 2){
28486 for(var i = 0, finger; finger = touches[i]; i++){
28487 coords.push(finger.pageX, finger.pageY);
28490 var x = Math.pow(coords[0] - coords[2], 2);
28491 var y = Math.pow(coords[1] - coords[3], 2);
28493 this.startDistance = Math.sqrt(x + y);
28495 this.startScale = this.scale;
28497 this.pinching = true;
28498 this.dragable = false;
28502 onTouchMove : function(e)
28504 if(!this.pinching && !this.dragable){
28508 var touches = e.browserEvent.touches;
28515 this.onMouseMove(e);
28521 for(var i = 0, finger; finger = touches[i]; i++){
28522 coords.push(finger.pageX, finger.pageY);
28525 var x = Math.pow(coords[0] - coords[2], 2);
28526 var y = Math.pow(coords[1] - coords[3], 2);
28528 this.endDistance = Math.sqrt(x + y);
28530 this.scale = this.startScale + Math.floor(Math.log(this.endDistance / this.startDistance) / Math.log(1.1));
28532 if(!this.zoomable()){
28533 this.scale = this.startScale;
28541 onTouchEnd : function(e)
28543 this.pinching = false;
28544 this.dragable = false;
28548 process : function(file, crop)
28551 this.maskEl.mask(this.loadingText);
28554 this.xhr = new XMLHttpRequest();
28556 file.xhr = this.xhr;
28558 this.xhr.open(this.method, this.url, true);
28561 "Accept": "application/json",
28562 "Cache-Control": "no-cache",
28563 "X-Requested-With": "XMLHttpRequest"
28566 for (var headerName in headers) {
28567 var headerValue = headers[headerName];
28569 this.xhr.setRequestHeader(headerName, headerValue);
28575 this.xhr.onload = function()
28577 _this.xhrOnLoad(_this.xhr);
28580 this.xhr.onerror = function()
28582 _this.xhrOnError(_this.xhr);
28585 var formData = new FormData();
28587 formData.append('returnHTML', 'NO');
28590 formData.append('crop', crop);
28593 if(typeof(file) != 'undefined' && (typeof(file.id) == 'undefined' || file.id * 1 < 1)){
28594 formData.append(this.paramName, file, file.name);
28597 if(typeof(file.filename) != 'undefined'){
28598 formData.append('filename', file.filename);
28601 if(typeof(file.mimetype) != 'undefined'){
28602 formData.append('mimetype', file.mimetype);
28605 if(this.fireEvent('arrange', this, formData) != false){
28606 this.xhr.send(formData);
28610 xhrOnLoad : function(xhr)
28613 this.maskEl.unmask();
28616 if (xhr.readyState !== 4) {
28617 this.fireEvent('exception', this, xhr);
28621 var response = Roo.decode(xhr.responseText);
28623 if(!response.success){
28624 this.fireEvent('exception', this, xhr);
28628 var response = Roo.decode(xhr.responseText);
28630 this.fireEvent('upload', this, response);
28634 xhrOnError : function()
28637 this.maskEl.unmask();
28640 Roo.log('xhr on error');
28642 var response = Roo.decode(xhr.responseText);
28648 prepare : function(file)
28651 this.maskEl.mask(this.loadingText);
28657 if(typeof(file) === 'string'){
28658 this.loadCanvas(file);
28662 if(!file || !this.urlAPI){
28667 this.cropType = file.type;
28671 if(this.fireEvent('prepare', this, this.file) != false){
28673 var reader = new FileReader();
28675 reader.onload = function (e) {
28676 if (e.target.error) {
28677 Roo.log(e.target.error);
28681 var buffer = e.target.result,
28682 dataView = new DataView(buffer),
28684 maxOffset = dataView.byteLength - 4,
28688 if (dataView.getUint16(0) === 0xffd8) {
28689 while (offset < maxOffset) {
28690 markerBytes = dataView.getUint16(offset);
28692 if ((markerBytes >= 0xffe0 && markerBytes <= 0xffef) || markerBytes === 0xfffe) {
28693 markerLength = dataView.getUint16(offset + 2) + 2;
28694 if (offset + markerLength > dataView.byteLength) {
28695 Roo.log('Invalid meta data: Invalid segment size.');
28699 if(markerBytes == 0xffe1){
28700 _this.parseExifData(
28707 offset += markerLength;
28717 var url = _this.urlAPI.createObjectURL(_this.file);
28719 _this.loadCanvas(url);
28724 reader.readAsArrayBuffer(this.file);
28730 parseExifData : function(dataView, offset, length)
28732 var tiffOffset = offset + 10,
28736 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28737 // No Exif data, might be XMP data instead
28741 // Check for the ASCII code for "Exif" (0x45786966):
28742 if (dataView.getUint32(offset + 4) !== 0x45786966) {
28743 // No Exif data, might be XMP data instead
28746 if (tiffOffset + 8 > dataView.byteLength) {
28747 Roo.log('Invalid Exif data: Invalid segment size.');
28750 // Check for the two null bytes:
28751 if (dataView.getUint16(offset + 8) !== 0x0000) {
28752 Roo.log('Invalid Exif data: Missing byte alignment offset.');
28755 // Check the byte alignment:
28756 switch (dataView.getUint16(tiffOffset)) {
28758 littleEndian = true;
28761 littleEndian = false;
28764 Roo.log('Invalid Exif data: Invalid byte alignment marker.');
28767 // Check for the TIFF tag marker (0x002A):
28768 if (dataView.getUint16(tiffOffset + 2, littleEndian) !== 0x002A) {
28769 Roo.log('Invalid Exif data: Missing TIFF marker.');
28772 // Retrieve the directory offset bytes, usually 0x00000008 or 8 decimal:
28773 dirOffset = dataView.getUint32(tiffOffset + 4, littleEndian);
28775 this.parseExifTags(
28778 tiffOffset + dirOffset,
28783 parseExifTags : function(dataView, tiffOffset, dirOffset, littleEndian)
28788 if (dirOffset + 6 > dataView.byteLength) {
28789 Roo.log('Invalid Exif data: Invalid directory offset.');
28792 tagsNumber = dataView.getUint16(dirOffset, littleEndian);
28793 dirEndOffset = dirOffset + 2 + 12 * tagsNumber;
28794 if (dirEndOffset + 4 > dataView.byteLength) {
28795 Roo.log('Invalid Exif data: Invalid directory size.');
28798 for (i = 0; i < tagsNumber; i += 1) {
28802 dirOffset + 2 + 12 * i, // tag offset
28806 // Return the offset to the next directory:
28807 return dataView.getUint32(dirEndOffset, littleEndian);
28810 parseExifTag : function (dataView, tiffOffset, offset, littleEndian)
28812 var tag = dataView.getUint16(offset, littleEndian);
28814 this.exif[tag] = this.getExifValue(
28818 dataView.getUint16(offset + 2, littleEndian), // tag type
28819 dataView.getUint32(offset + 4, littleEndian), // tag length
28824 getExifValue : function (dataView, tiffOffset, offset, type, length, littleEndian)
28826 var tagType = Roo.bootstrap.UploadCropbox.exifTagTypes[type],
28835 Roo.log('Invalid Exif data: Invalid tag type.');
28839 tagSize = tagType.size * length;
28840 // Determine if the value is contained in the dataOffset bytes,
28841 // or if the value at the dataOffset is a pointer to the actual data:
28842 dataOffset = tagSize > 4 ?
28843 tiffOffset + dataView.getUint32(offset + 8, littleEndian) : (offset + 8);
28844 if (dataOffset + tagSize > dataView.byteLength) {
28845 Roo.log('Invalid Exif data: Invalid data offset.');
28848 if (length === 1) {
28849 return tagType.getValue(dataView, dataOffset, littleEndian);
28852 for (i = 0; i < length; i += 1) {
28853 values[i] = tagType.getValue(dataView, dataOffset + i * tagType.size, littleEndian);
28856 if (tagType.ascii) {
28858 // Concatenate the chars:
28859 for (i = 0; i < values.length; i += 1) {
28861 // Ignore the terminating NULL byte(s):
28862 if (c === '\u0000') {
28874 Roo.apply(Roo.bootstrap.UploadCropbox, {
28876 'Orientation': 0x0112
28880 1: 0, //'top-left',
28882 3: 180, //'bottom-right',
28883 // 4: 'bottom-left',
28885 6: 90, //'right-top',
28886 // 7: 'right-bottom',
28887 8: 270 //'left-bottom'
28891 // byte, 8-bit unsigned int:
28893 getValue: function (dataView, dataOffset) {
28894 return dataView.getUint8(dataOffset);
28898 // ascii, 8-bit byte:
28900 getValue: function (dataView, dataOffset) {
28901 return String.fromCharCode(dataView.getUint8(dataOffset));
28906 // short, 16 bit int:
28908 getValue: function (dataView, dataOffset, littleEndian) {
28909 return dataView.getUint16(dataOffset, littleEndian);
28913 // long, 32 bit int:
28915 getValue: function (dataView, dataOffset, littleEndian) {
28916 return dataView.getUint32(dataOffset, littleEndian);
28920 // rational = two long values, first is numerator, second is denominator:
28922 getValue: function (dataView, dataOffset, littleEndian) {
28923 return dataView.getUint32(dataOffset, littleEndian) /
28924 dataView.getUint32(dataOffset + 4, littleEndian);
28928 // slong, 32 bit signed int:
28930 getValue: function (dataView, dataOffset, littleEndian) {
28931 return dataView.getInt32(dataOffset, littleEndian);
28935 // srational, two slongs, first is numerator, second is denominator:
28937 getValue: function (dataView, dataOffset, littleEndian) {
28938 return dataView.getInt32(dataOffset, littleEndian) /
28939 dataView.getInt32(dataOffset + 4, littleEndian);
28949 cls : 'btn-group roo-upload-cropbox-rotate-left',
28950 action : 'rotate-left',
28954 cls : 'btn btn-default',
28955 html : '<i class="fa fa-undo"></i>'
28961 cls : 'btn-group roo-upload-cropbox-picture',
28962 action : 'picture',
28966 cls : 'btn btn-default',
28967 html : '<i class="fa fa-picture-o"></i>'
28973 cls : 'btn-group roo-upload-cropbox-rotate-right',
28974 action : 'rotate-right',
28978 cls : 'btn btn-default',
28979 html : '<i class="fa fa-repeat"></i>'
28987 cls : 'btn-group roo-upload-cropbox-rotate-left',
28988 action : 'rotate-left',
28992 cls : 'btn btn-default',
28993 html : '<i class="fa fa-undo"></i>'
28999 cls : 'btn-group roo-upload-cropbox-download',
29000 action : 'download',
29004 cls : 'btn btn-default',
29005 html : '<i class="fa fa-download"></i>'
29011 cls : 'btn-group roo-upload-cropbox-crop',
29016 cls : 'btn btn-default',
29017 html : '<i class="fa fa-crop"></i>'
29023 cls : 'btn-group roo-upload-cropbox-trash',
29028 cls : 'btn btn-default',
29029 html : '<i class="fa fa-trash"></i>'
29035 cls : 'btn-group roo-upload-cropbox-rotate-right',
29036 action : 'rotate-right',
29040 cls : 'btn btn-default',
29041 html : '<i class="fa fa-repeat"></i>'
29049 cls : 'btn-group roo-upload-cropbox-rotate-left',
29050 action : 'rotate-left',
29054 cls : 'btn btn-default',
29055 html : '<i class="fa fa-undo"></i>'
29061 cls : 'btn-group roo-upload-cropbox-rotate-right',
29062 action : 'rotate-right',
29066 cls : 'btn btn-default',
29067 html : '<i class="fa fa-repeat"></i>'
29080 * @class Roo.bootstrap.DocumentManager
29081 * @extends Roo.bootstrap.Component
29082 * Bootstrap DocumentManager class
29083 * @cfg {String} paramName default 'imageUpload'
29084 * @cfg {String} toolTipName default 'filename'
29085 * @cfg {String} method default POST
29086 * @cfg {String} url action url
29087 * @cfg {Number} boxes number of boxes, 0 is no limit.. default 0
29088 * @cfg {Boolean} multiple multiple upload default true
29089 * @cfg {Number} thumbSize default 300
29090 * @cfg {String} fieldLabel
29091 * @cfg {Number} labelWidth default 4
29092 * @cfg {String} labelAlign (left|top) default left
29093 * @cfg {Boolean} editable (true|false) allow edit when upload a image default true
29094 * @cfg {Number} labellg set the width of label (1-12)
29095 * @cfg {Number} labelmd set the width of label (1-12)
29096 * @cfg {Number} labelsm set the width of label (1-12)
29097 * @cfg {Number} labelxs set the width of label (1-12)
29100 * Create a new DocumentManager
29101 * @param {Object} config The config object
29104 Roo.bootstrap.DocumentManager = function(config){
29105 Roo.bootstrap.DocumentManager.superclass.constructor.call(this, config);
29108 this.delegates = [];
29113 * Fire when initial the DocumentManager
29114 * @param {Roo.bootstrap.DocumentManager} this
29119 * inspect selected file
29120 * @param {Roo.bootstrap.DocumentManager} this
29121 * @param {File} file
29126 * Fire when xhr load exception
29127 * @param {Roo.bootstrap.DocumentManager} this
29128 * @param {XMLHttpRequest} xhr
29130 "exception" : true,
29132 * @event afterupload
29133 * Fire when xhr load exception
29134 * @param {Roo.bootstrap.DocumentManager} this
29135 * @param {XMLHttpRequest} xhr
29137 "afterupload" : true,
29140 * prepare the form data
29141 * @param {Roo.bootstrap.DocumentManager} this
29142 * @param {Object} formData
29147 * Fire when remove the file
29148 * @param {Roo.bootstrap.DocumentManager} this
29149 * @param {Object} file
29154 * Fire after refresh the file
29155 * @param {Roo.bootstrap.DocumentManager} this
29160 * Fire after click the image
29161 * @param {Roo.bootstrap.DocumentManager} this
29162 * @param {Object} file
29167 * Fire when upload a image and editable set to true
29168 * @param {Roo.bootstrap.DocumentManager} this
29169 * @param {Object} file
29173 * @event beforeselectfile
29174 * Fire before select file
29175 * @param {Roo.bootstrap.DocumentManager} this
29177 "beforeselectfile" : true,
29180 * Fire before process file
29181 * @param {Roo.bootstrap.DocumentManager} this
29182 * @param {Object} file
29186 * @event previewrendered
29187 * Fire when preview rendered
29188 * @param {Roo.bootstrap.DocumentManager} this
29189 * @param {Object} file
29191 "previewrendered" : true,
29194 "previewResize" : true
29199 Roo.extend(Roo.bootstrap.DocumentManager, Roo.bootstrap.Component, {
29208 paramName : 'imageUpload',
29209 toolTipName : 'filename',
29212 labelAlign : 'left',
29222 getAutoCreate : function()
29224 var managerWidget = {
29226 cls : 'roo-document-manager',
29230 cls : 'roo-document-manager-selector',
29235 cls : 'roo-document-manager-uploader',
29239 cls : 'roo-document-manager-upload-btn',
29240 html : '<i class="fa fa-plus"></i>'
29251 cls : 'column col-md-12',
29256 if(this.fieldLabel.length){
29261 cls : 'column col-md-12',
29262 html : this.fieldLabel
29266 cls : 'column col-md-12',
29271 if(this.labelAlign == 'left'){
29276 html : this.fieldLabel
29285 if(this.labelWidth > 12){
29286 content[0].style = "width: " + this.labelWidth + 'px';
29289 if(this.labelWidth < 13 && this.labelmd == 0){
29290 this.labelmd = this.labelWidth;
29293 if(this.labellg > 0){
29294 content[0].cls += ' col-lg-' + this.labellg;
29295 content[1].cls += ' col-lg-' + (12 - this.labellg);
29298 if(this.labelmd > 0){
29299 content[0].cls += ' col-md-' + this.labelmd;
29300 content[1].cls += ' col-md-' + (12 - this.labelmd);
29303 if(this.labelsm > 0){
29304 content[0].cls += ' col-sm-' + this.labelsm;
29305 content[1].cls += ' col-sm-' + (12 - this.labelsm);
29308 if(this.labelxs > 0){
29309 content[0].cls += ' col-xs-' + this.labelxs;
29310 content[1].cls += ' col-xs-' + (12 - this.labelxs);
29318 cls : 'row clearfix',
29326 initEvents : function()
29328 this.managerEl = this.el.select('.roo-document-manager', true).first();
29329 this.managerEl.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29331 this.selectorEl = this.el.select('.roo-document-manager-selector', true).first();
29332 this.selectorEl.hide();
29335 this.selectorEl.attr('multiple', 'multiple');
29338 this.selectorEl.on('change', this.onFileSelected, this);
29340 this.uploader = this.el.select('.roo-document-manager-uploader', true).first();
29341 this.uploader.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29343 this.uploader.on('click', this.onUploaderClick, this);
29345 this.renderProgressDialog();
29349 window.addEventListener("resize", function() { _this.refresh(); } );
29351 this.fireEvent('initial', this);
29354 renderProgressDialog : function()
29358 this.progressDialog = new Roo.bootstrap.Modal({
29359 cls : 'roo-document-manager-progress-dialog',
29360 allow_close : false,
29371 btnclick : function() {
29372 _this.uploadCancel();
29378 this.progressDialog.render(Roo.get(document.body));
29380 this.progress = new Roo.bootstrap.Progress({
29381 cls : 'roo-document-manager-progress',
29386 this.progress.render(this.progressDialog.getChildContainer());
29388 this.progressBar = new Roo.bootstrap.ProgressBar({
29389 cls : 'roo-document-manager-progress-bar',
29392 aria_valuemax : 12,
29396 this.progressBar.render(this.progress.getChildContainer());
29399 onUploaderClick : function(e)
29401 e.preventDefault();
29403 if(this.fireEvent('beforeselectfile', this) != false){
29404 this.selectorEl.dom.click();
29409 onFileSelected : function(e)
29411 e.preventDefault();
29413 if(typeof(this.selectorEl.dom.files) == 'undefined' || !this.selectorEl.dom.files.length){
29417 Roo.each(this.selectorEl.dom.files, function(file){
29418 if(this.fireEvent('inspect', this, file) != false){
29419 this.files.push(file);
29429 this.selectorEl.dom.value = '';
29431 if(!this.files || !this.files.length){
29435 if(this.boxes > 0 && this.files.length > this.boxes){
29436 this.files = this.files.slice(0, this.boxes);
29439 this.uploader.show();
29441 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29442 this.uploader.hide();
29451 Roo.each(this.files, function(file){
29453 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29454 var f = this.renderPreview(file);
29459 if(file.type.indexOf('image') != -1){
29460 this.delegates.push(
29462 _this.process(file);
29463 }).createDelegate(this)
29471 _this.process(file);
29472 }).createDelegate(this)
29477 this.files = files;
29479 this.delegates = this.delegates.concat(docs);
29481 if(!this.delegates.length){
29486 this.progressBar.aria_valuemax = this.delegates.length;
29493 arrange : function()
29495 if(!this.delegates.length){
29496 this.progressDialog.hide();
29501 var delegate = this.delegates.shift();
29503 this.progressDialog.show();
29505 this.progressDialog.setTitle((this.progressBar.aria_valuemax - this.delegates.length) + ' / ' + this.progressBar.aria_valuemax);
29507 this.progressBar.update(this.progressBar.aria_valuemax - this.delegates.length);
29512 refresh : function()
29514 this.uploader.show();
29516 if(this.boxes > 0 && this.files.length > this.boxes - 1){
29517 this.uploader.hide();
29520 Roo.isTouch ? this.closable(false) : this.closable(true);
29522 this.fireEvent('refresh', this);
29525 onRemove : function(e, el, o)
29527 e.preventDefault();
29529 this.fireEvent('remove', this, o);
29533 remove : function(o)
29537 Roo.each(this.files, function(file){
29538 if(typeof(file.id) == 'undefined' || file.id * 1 < 1 || file.id != o.id){
29547 this.files = files;
29554 Roo.each(this.files, function(file){
29559 file.target.remove();
29568 onClick : function(e, el, o)
29570 e.preventDefault();
29572 this.fireEvent('click', this, o);
29576 closable : function(closable)
29578 Roo.each(this.managerEl.select('.roo-document-manager-preview > button.close', true).elements, function(el){
29580 el.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
29592 xhrOnLoad : function(xhr)
29594 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29598 if (xhr.readyState !== 4) {
29600 this.fireEvent('exception', this, xhr);
29604 var response = Roo.decode(xhr.responseText);
29606 if(!response.success){
29608 this.fireEvent('exception', this, xhr);
29612 var file = this.renderPreview(response.data);
29614 this.files.push(file);
29618 this.fireEvent('afterupload', this, xhr);
29622 xhrOnError : function(xhr)
29624 Roo.log('xhr on error');
29626 var response = Roo.decode(xhr.responseText);
29633 process : function(file)
29635 if(this.fireEvent('process', this, file) !== false){
29636 if(this.editable && file.type.indexOf('image') != -1){
29637 this.fireEvent('edit', this, file);
29641 this.uploadStart(file, false);
29648 uploadStart : function(file, crop)
29650 this.xhr = new XMLHttpRequest();
29652 if(typeof(file.id) != 'undefined' && file.id * 1 > 0){
29657 file.xhr = this.xhr;
29659 this.managerEl.createChild({
29661 cls : 'roo-document-manager-loading',
29665 tooltip : file.name,
29666 cls : 'roo-document-manager-thumb',
29667 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29673 this.xhr.open(this.method, this.url, true);
29676 "Accept": "application/json",
29677 "Cache-Control": "no-cache",
29678 "X-Requested-With": "XMLHttpRequest"
29681 for (var headerName in headers) {
29682 var headerValue = headers[headerName];
29684 this.xhr.setRequestHeader(headerName, headerValue);
29690 this.xhr.onload = function()
29692 _this.xhrOnLoad(_this.xhr);
29695 this.xhr.onerror = function()
29697 _this.xhrOnError(_this.xhr);
29700 var formData = new FormData();
29702 formData.append('returnHTML', 'NO');
29705 formData.append('crop', crop);
29708 formData.append(this.paramName, file, file.name);
29715 if(this.fireEvent('prepare', this, formData, options) != false){
29717 if(options.manually){
29721 this.xhr.send(formData);
29725 this.uploadCancel();
29728 uploadCancel : function()
29734 this.delegates = [];
29736 Roo.each(this.managerEl.select('.roo-document-manager-loading', true).elements, function(el){
29743 renderPreview : function(file)
29745 if(typeof(file.target) != 'undefined' && file.target){
29749 var img_src = encodeURI(baseURL +'/Images/Thumb/' + this.thumbSize + '/' + file.id + '/' + file.filename);
29751 var previewEl = this.managerEl.createChild({
29753 cls : 'roo-document-manager-preview',
29757 tooltip : file[this.toolTipName],
29758 cls : 'roo-document-manager-thumb',
29759 html : '<img tooltip="' + file[this.toolTipName] + '" src="' + img_src + '">'
29764 html : '<i class="fa fa-times-circle"></i>'
29769 var close = previewEl.select('button.close', true).first();
29771 close.on('click', this.onRemove, this, file);
29773 file.target = previewEl;
29775 var image = previewEl.select('img', true).first();
29779 image.dom.addEventListener("load", function(){ _this.onPreviewLoad(file, image); });
29781 image.on('click', this.onClick, this, file);
29783 this.fireEvent('previewrendered', this, file);
29789 onPreviewLoad : function(file, image)
29791 if(typeof(file.target) == 'undefined' || !file.target){
29795 var width = image.dom.naturalWidth || image.dom.width;
29796 var height = image.dom.naturalHeight || image.dom.height;
29798 if(!this.previewResize) {
29802 if(width > height){
29803 file.target.addClass('wide');
29807 file.target.addClass('tall');
29812 uploadFromSource : function(file, crop)
29814 this.xhr = new XMLHttpRequest();
29816 this.managerEl.createChild({
29818 cls : 'roo-document-manager-loading',
29822 tooltip : file.name,
29823 cls : 'roo-document-manager-thumb',
29824 html : '<i class="fa fa-circle-o-notch fa-spin"></i>'
29830 this.xhr.open(this.method, this.url, true);
29833 "Accept": "application/json",
29834 "Cache-Control": "no-cache",
29835 "X-Requested-With": "XMLHttpRequest"
29838 for (var headerName in headers) {
29839 var headerValue = headers[headerName];
29841 this.xhr.setRequestHeader(headerName, headerValue);
29847 this.xhr.onload = function()
29849 _this.xhrOnLoad(_this.xhr);
29852 this.xhr.onerror = function()
29854 _this.xhrOnError(_this.xhr);
29857 var formData = new FormData();
29859 formData.append('returnHTML', 'NO');
29861 formData.append('crop', crop);
29863 if(typeof(file.filename) != 'undefined'){
29864 formData.append('filename', file.filename);
29867 if(typeof(file.mimetype) != 'undefined'){
29868 formData.append('mimetype', file.mimetype);
29873 if(this.fireEvent('prepare', this, formData) != false){
29874 this.xhr.send(formData);
29884 * @class Roo.bootstrap.DocumentViewer
29885 * @extends Roo.bootstrap.Component
29886 * Bootstrap DocumentViewer class
29887 * @cfg {Boolean} showDownload (true|false) show download button (default true)
29888 * @cfg {Boolean} showTrash (true|false) show trash button (default true)
29891 * Create a new DocumentViewer
29892 * @param {Object} config The config object
29895 Roo.bootstrap.DocumentViewer = function(config){
29896 Roo.bootstrap.DocumentViewer.superclass.constructor.call(this, config);
29901 * Fire after initEvent
29902 * @param {Roo.bootstrap.DocumentViewer} this
29908 * @param {Roo.bootstrap.DocumentViewer} this
29913 * Fire after download button
29914 * @param {Roo.bootstrap.DocumentViewer} this
29919 * Fire after trash button
29920 * @param {Roo.bootstrap.DocumentViewer} this
29927 Roo.extend(Roo.bootstrap.DocumentViewer, Roo.bootstrap.Component, {
29929 showDownload : true,
29933 getAutoCreate : function()
29937 cls : 'roo-document-viewer',
29941 cls : 'roo-document-viewer-body',
29945 cls : 'roo-document-viewer-thumb',
29949 cls : 'roo-document-viewer-image'
29957 cls : 'roo-document-viewer-footer',
29960 cls : 'btn-group btn-group-justified roo-document-viewer-btn-group',
29964 cls : 'btn-group roo-document-viewer-download',
29968 cls : 'btn btn-default',
29969 html : '<i class="fa fa-download"></i>'
29975 cls : 'btn-group roo-document-viewer-trash',
29979 cls : 'btn btn-default',
29980 html : '<i class="fa fa-trash"></i>'
29993 initEvents : function()
29995 this.bodyEl = this.el.select('.roo-document-viewer-body', true).first();
29996 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
29998 this.thumbEl = this.el.select('.roo-document-viewer-thumb', true).first();
29999 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
30001 this.imageEl = this.el.select('.roo-document-viewer-image', true).first();
30002 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
30004 this.footerEl = this.el.select('.roo-document-viewer-footer', true).first();
30005 this.footerEl.setVisibilityMode(Roo.Element.DISPLAY);
30007 this.downloadBtn = this.el.select('.roo-document-viewer-download', true).first();
30008 this.downloadBtn.setVisibilityMode(Roo.Element.DISPLAY);
30010 this.trashBtn = this.el.select('.roo-document-viewer-trash', true).first();
30011 this.trashBtn.setVisibilityMode(Roo.Element.DISPLAY);
30013 this.bodyEl.on('click', this.onClick, this);
30014 this.downloadBtn.on('click', this.onDownload, this);
30015 this.trashBtn.on('click', this.onTrash, this);
30017 this.downloadBtn.hide();
30018 this.trashBtn.hide();
30020 if(this.showDownload){
30021 this.downloadBtn.show();
30024 if(this.showTrash){
30025 this.trashBtn.show();
30028 if(!this.showDownload && !this.showTrash) {
30029 this.footerEl.hide();
30034 initial : function()
30036 this.fireEvent('initial', this);
30040 onClick : function(e)
30042 e.preventDefault();
30044 this.fireEvent('click', this);
30047 onDownload : function(e)
30049 e.preventDefault();
30051 this.fireEvent('download', this);
30054 onTrash : function(e)
30056 e.preventDefault();
30058 this.fireEvent('trash', this);
30070 * @class Roo.bootstrap.NavProgressBar
30071 * @extends Roo.bootstrap.Component
30072 * Bootstrap NavProgressBar class
30075 * Create a new nav progress bar
30076 * @param {Object} config The config object
30079 Roo.bootstrap.NavProgressBar = function(config){
30080 Roo.bootstrap.NavProgressBar.superclass.constructor.call(this, config);
30082 this.bullets = this.bullets || [];
30084 // Roo.bootstrap.NavProgressBar.register(this);
30088 * Fires when the active item changes
30089 * @param {Roo.bootstrap.NavProgressBar} this
30090 * @param {Roo.bootstrap.NavProgressItem} selected The item selected
30091 * @param {Roo.bootstrap.NavProgressItem} prev The previously selected item
30098 Roo.extend(Roo.bootstrap.NavProgressBar, Roo.bootstrap.Component, {
30103 getAutoCreate : function()
30105 var cfg = Roo.apply({}, Roo.bootstrap.NavProgressBar.superclass.getAutoCreate.call(this));
30109 cls : 'roo-navigation-bar-group',
30113 cls : 'roo-navigation-top-bar'
30117 cls : 'roo-navigation-bullets-bar',
30121 cls : 'roo-navigation-bar'
30128 cls : 'roo-navigation-bottom-bar'
30138 initEvents: function()
30143 onRender : function(ct, position)
30145 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30147 if(this.bullets.length){
30148 Roo.each(this.bullets, function(b){
30157 addItem : function(cfg)
30159 var item = new Roo.bootstrap.NavProgressItem(cfg);
30161 item.parentId = this.id;
30162 item.render(this.el.select('.roo-navigation-bar', true).first(), null);
30165 var top = new Roo.bootstrap.Element({
30167 cls : 'roo-navigation-bar-text'
30170 var bottom = new Roo.bootstrap.Element({
30172 cls : 'roo-navigation-bar-text'
30175 top.onRender(this.el.select('.roo-navigation-top-bar', true).first(), null);
30176 bottom.onRender(this.el.select('.roo-navigation-bottom-bar', true).first(), null);
30178 var topText = new Roo.bootstrap.Element({
30180 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? cfg.html : ''
30183 var bottomText = new Roo.bootstrap.Element({
30185 html : (typeof(cfg.position) != 'undefined' && cfg.position == 'top') ? '' : cfg.html
30188 topText.onRender(top.el, null);
30189 bottomText.onRender(bottom.el, null);
30192 item.bottomEl = bottom;
30195 this.barItems.push(item);
30200 getActive : function()
30202 var active = false;
30204 Roo.each(this.barItems, function(v){
30206 if (!v.isActive()) {
30218 setActiveItem : function(item)
30222 Roo.each(this.barItems, function(v){
30223 if (v.rid == item.rid) {
30227 if (v.isActive()) {
30228 v.setActive(false);
30233 item.setActive(true);
30235 this.fireEvent('changed', this, item, prev);
30238 getBarItem: function(rid)
30242 Roo.each(this.barItems, function(e) {
30243 if (e.rid != rid) {
30254 indexOfItem : function(item)
30258 Roo.each(this.barItems, function(v, i){
30260 if (v.rid != item.rid) {
30271 setActiveNext : function()
30273 var i = this.indexOfItem(this.getActive());
30275 if (i > this.barItems.length) {
30279 this.setActiveItem(this.barItems[i+1]);
30282 setActivePrev : function()
30284 var i = this.indexOfItem(this.getActive());
30290 this.setActiveItem(this.barItems[i-1]);
30293 format : function()
30295 if(!this.barItems.length){
30299 var width = 100 / this.barItems.length;
30301 Roo.each(this.barItems, function(i){
30302 i.el.setStyle('width', width + '%');
30303 i.topEl.el.setStyle('width', width + '%');
30304 i.bottomEl.el.setStyle('width', width + '%');
30313 * Nav Progress Item
30318 * @class Roo.bootstrap.NavProgressItem
30319 * @extends Roo.bootstrap.Component
30320 * Bootstrap NavProgressItem class
30321 * @cfg {String} rid the reference id
30322 * @cfg {Boolean} active (true|false) Is item active default false
30323 * @cfg {Boolean} disabled (true|false) Is item active default false
30324 * @cfg {String} html
30325 * @cfg {String} position (top|bottom) text position default bottom
30326 * @cfg {String} icon show icon instead of number
30329 * Create a new NavProgressItem
30330 * @param {Object} config The config object
30332 Roo.bootstrap.NavProgressItem = function(config){
30333 Roo.bootstrap.NavProgressItem.superclass.constructor.call(this, config);
30338 * The raw click event for the entire grid.
30339 * @param {Roo.bootstrap.NavProgressItem} this
30340 * @param {Roo.EventObject} e
30347 Roo.extend(Roo.bootstrap.NavProgressItem, Roo.bootstrap.Component, {
30353 position : 'bottom',
30356 getAutoCreate : function()
30358 var iconCls = 'roo-navigation-bar-item-icon';
30360 iconCls += ((this.icon) ? (' ' + this.icon) : (' step-number')) ;
30364 cls: 'roo-navigation-bar-item',
30374 cfg.cls += ' active';
30377 cfg.cls += ' disabled';
30383 disable : function()
30385 this.setDisabled(true);
30388 enable : function()
30390 this.setDisabled(false);
30393 initEvents: function()
30395 this.iconEl = this.el.select('.roo-navigation-bar-item-icon', true).first();
30397 this.iconEl.on('click', this.onClick, this);
30400 onClick : function(e)
30402 e.preventDefault();
30408 if(this.fireEvent('click', this, e) === false){
30412 this.parent().setActiveItem(this);
30415 isActive: function ()
30417 return this.active;
30420 setActive : function(state)
30422 if(this.active == state){
30426 this.active = state;
30429 this.el.addClass('active');
30433 this.el.removeClass('active');
30438 setDisabled : function(state)
30440 if(this.disabled == state){
30444 this.disabled = state;
30447 this.el.addClass('disabled');
30451 this.el.removeClass('disabled');
30454 tooltipEl : function()
30456 return this.el.select('.roo-navigation-bar-item-icon', true).first();;
30469 * @class Roo.bootstrap.FieldLabel
30470 * @extends Roo.bootstrap.Component
30471 * Bootstrap FieldLabel class
30472 * @cfg {String} html contents of the element
30473 * @cfg {String} tag tag of the element default label
30474 * @cfg {String} cls class of the element
30475 * @cfg {String} target label target
30476 * @cfg {Boolean} allowBlank (true|false) target allowBlank default true
30477 * @cfg {String} invalidClass DEPRICATED - BS4 uses is-invalid
30478 * @cfg {String} validClass DEPRICATED - BS4 uses is-valid
30479 * @cfg {String} iconTooltip default "This field is required"
30480 * @cfg {String} indicatorpos (left|right) default left
30483 * Create a new FieldLabel
30484 * @param {Object} config The config object
30487 Roo.bootstrap.FieldLabel = function(config){
30488 Roo.bootstrap.Element.superclass.constructor.call(this, config);
30493 * Fires after the field has been marked as invalid.
30494 * @param {Roo.form.FieldLabel} this
30495 * @param {String} msg The validation message
30500 * Fires after the field has been validated with no errors.
30501 * @param {Roo.form.FieldLabel} this
30507 Roo.extend(Roo.bootstrap.FieldLabel, Roo.bootstrap.Component, {
30514 invalidClass : 'has-warning',
30515 validClass : 'has-success',
30516 iconTooltip : 'This field is required',
30517 indicatorpos : 'left',
30519 getAutoCreate : function(){
30522 if (!this.allowBlank) {
30528 cls : 'roo-bootstrap-field-label ' + this.cls,
30533 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star ' + cls,
30534 tooltip : this.iconTooltip
30543 if(this.indicatorpos == 'right'){
30546 cls : 'roo-bootstrap-field-label ' + this.cls,
30555 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star '+ cls,
30556 tooltip : this.iconTooltip
30565 initEvents: function()
30567 Roo.bootstrap.Element.superclass.initEvents.call(this);
30569 this.indicator = this.indicatorEl();
30571 if(this.indicator){
30572 this.indicator.removeClass('visible');
30573 this.indicator.addClass('invisible');
30576 Roo.bootstrap.FieldLabel.register(this);
30579 indicatorEl : function()
30581 var indicator = this.el.select('i.roo-required-indicator',true).first();
30592 * Mark this field as valid
30594 markValid : function()
30596 if(this.indicator){
30597 this.indicator.removeClass('visible');
30598 this.indicator.addClass('invisible');
30600 if (Roo.bootstrap.version == 3) {
30601 this.el.removeClass(this.invalidClass);
30602 this.el.addClass(this.validClass);
30604 this.el.removeClass('is-invalid');
30605 this.el.addClass('is-valid');
30609 this.fireEvent('valid', this);
30613 * Mark this field as invalid
30614 * @param {String} msg The validation message
30616 markInvalid : function(msg)
30618 if(this.indicator){
30619 this.indicator.removeClass('invisible');
30620 this.indicator.addClass('visible');
30622 if (Roo.bootstrap.version == 3) {
30623 this.el.removeClass(this.validClass);
30624 this.el.addClass(this.invalidClass);
30626 this.el.removeClass('is-valid');
30627 this.el.addClass('is-invalid');
30631 this.fireEvent('invalid', this, msg);
30637 Roo.apply(Roo.bootstrap.FieldLabel, {
30642 * register a FieldLabel Group
30643 * @param {Roo.bootstrap.FieldLabel} the FieldLabel to add
30645 register : function(label)
30647 if(this.groups.hasOwnProperty(label.target)){
30651 this.groups[label.target] = label;
30655 * fetch a FieldLabel Group based on the target
30656 * @param {string} target
30657 * @returns {Roo.bootstrap.FieldLabel} the CheckBox group
30659 get: function(target) {
30660 if (typeof(this.groups[target]) == 'undefined') {
30664 return this.groups[target] ;
30673 * page DateSplitField.
30679 * @class Roo.bootstrap.DateSplitField
30680 * @extends Roo.bootstrap.Component
30681 * Bootstrap DateSplitField class
30682 * @cfg {string} fieldLabel - the label associated
30683 * @cfg {Number} labelWidth set the width of label (0-12)
30684 * @cfg {String} labelAlign (top|left)
30685 * @cfg {Boolean} dayAllowBlank (true|false) default false
30686 * @cfg {Boolean} monthAllowBlank (true|false) default false
30687 * @cfg {Boolean} yearAllowBlank (true|false) default false
30688 * @cfg {string} dayPlaceholder
30689 * @cfg {string} monthPlaceholder
30690 * @cfg {string} yearPlaceholder
30691 * @cfg {string} dayFormat default 'd'
30692 * @cfg {string} monthFormat default 'm'
30693 * @cfg {string} yearFormat default 'Y'
30694 * @cfg {Number} labellg set the width of label (1-12)
30695 * @cfg {Number} labelmd set the width of label (1-12)
30696 * @cfg {Number} labelsm set the width of label (1-12)
30697 * @cfg {Number} labelxs set the width of label (1-12)
30701 * Create a new DateSplitField
30702 * @param {Object} config The config object
30705 Roo.bootstrap.DateSplitField = function(config){
30706 Roo.bootstrap.DateSplitField.superclass.constructor.call(this, config);
30712 * getting the data of years
30713 * @param {Roo.bootstrap.DateSplitField} this
30714 * @param {Object} years
30719 * getting the data of days
30720 * @param {Roo.bootstrap.DateSplitField} this
30721 * @param {Object} days
30726 * Fires after the field has been marked as invalid.
30727 * @param {Roo.form.Field} this
30728 * @param {String} msg The validation message
30733 * Fires after the field has been validated with no errors.
30734 * @param {Roo.form.Field} this
30740 Roo.extend(Roo.bootstrap.DateSplitField, Roo.bootstrap.Component, {
30743 labelAlign : 'top',
30745 dayAllowBlank : false,
30746 monthAllowBlank : false,
30747 yearAllowBlank : false,
30748 dayPlaceholder : '',
30749 monthPlaceholder : '',
30750 yearPlaceholder : '',
30754 isFormField : true,
30760 getAutoCreate : function()
30764 cls : 'row roo-date-split-field-group',
30769 cls : 'form-hidden-field roo-date-split-field-group-value',
30775 var labelCls = 'col-md-12';
30776 var contentCls = 'col-md-4';
30778 if(this.fieldLabel){
30782 cls : 'column roo-date-split-field-label col-md-' + ((this.labelAlign == 'top') ? '12' : this.labelWidth),
30786 html : this.fieldLabel
30791 if(this.labelAlign == 'left'){
30793 if(this.labelWidth > 12){
30794 label.style = "width: " + this.labelWidth + 'px';
30797 if(this.labelWidth < 13 && this.labelmd == 0){
30798 this.labelmd = this.labelWidth;
30801 if(this.labellg > 0){
30802 labelCls = ' col-lg-' + this.labellg;
30803 contentCls = ' col-lg-' + ((12 - this.labellg) / 3);
30806 if(this.labelmd > 0){
30807 labelCls = ' col-md-' + this.labelmd;
30808 contentCls = ' col-md-' + ((12 - this.labelmd) / 3);
30811 if(this.labelsm > 0){
30812 labelCls = ' col-sm-' + this.labelsm;
30813 contentCls = ' col-sm-' + ((12 - this.labelsm) / 3);
30816 if(this.labelxs > 0){
30817 labelCls = ' col-xs-' + this.labelxs;
30818 contentCls = ' col-xs-' + ((12 - this.labelxs) / 3);
30822 label.cls += ' ' + labelCls;
30824 cfg.cn.push(label);
30827 Roo.each(['day', 'month', 'year'], function(t){
30830 cls : 'column roo-date-split-field-' + t + ' ' + contentCls
30837 inputEl: function ()
30839 return this.el.select('.roo-date-split-field-group-value', true).first();
30842 onRender : function(ct, position)
30846 Roo.bootstrap.NavProgressBar.superclass.onRender.call(this, ct, position);
30848 this.inputEl = this.el.select('.roo-date-split-field-group-value', true).first();
30850 this.dayField = new Roo.bootstrap.ComboBox({
30851 allowBlank : this.dayAllowBlank,
30852 alwaysQuery : true,
30853 displayField : 'value',
30856 forceSelection : true,
30858 placeholder : this.dayPlaceholder,
30859 selectOnFocus : true,
30860 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30861 triggerAction : 'all',
30863 valueField : 'value',
30864 store : new Roo.data.SimpleStore({
30865 data : (function() {
30867 _this.fireEvent('days', _this, days);
30870 fields : [ 'value' ]
30873 select : function (_self, record, index)
30875 _this.setValue(_this.getValue());
30880 this.dayField.render(this.el.select('.roo-date-split-field-day', true).first(), null);
30882 this.monthField = new Roo.bootstrap.MonthField({
30883 after : '<i class=\"fa fa-calendar\"></i>',
30884 allowBlank : this.monthAllowBlank,
30885 placeholder : this.monthPlaceholder,
30888 render : function (_self)
30890 this.el.select('span.input-group-addon', true).first().on('click', function(e){
30891 e.preventDefault();
30895 select : function (_self, oldvalue, newvalue)
30897 _this.setValue(_this.getValue());
30902 this.monthField.render(this.el.select('.roo-date-split-field-month', true).first(), null);
30904 this.yearField = new Roo.bootstrap.ComboBox({
30905 allowBlank : this.yearAllowBlank,
30906 alwaysQuery : true,
30907 displayField : 'value',
30910 forceSelection : true,
30912 placeholder : this.yearPlaceholder,
30913 selectOnFocus : true,
30914 tpl : '<div class="roo-select2-result"><b>{value}</b></div>',
30915 triggerAction : 'all',
30917 valueField : 'value',
30918 store : new Roo.data.SimpleStore({
30919 data : (function() {
30921 _this.fireEvent('years', _this, years);
30924 fields : [ 'value' ]
30927 select : function (_self, record, index)
30929 _this.setValue(_this.getValue());
30934 this.yearField.render(this.el.select('.roo-date-split-field-year', true).first(), null);
30937 setValue : function(v, format)
30939 this.inputEl.dom.value = v;
30941 var f = format || (this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat);
30943 var d = Date.parseDate(v, f);
30950 this.setDay(d.format(this.dayFormat));
30951 this.setMonth(d.format(this.monthFormat));
30952 this.setYear(d.format(this.yearFormat));
30959 setDay : function(v)
30961 this.dayField.setValue(v);
30962 this.inputEl.dom.value = this.getValue();
30967 setMonth : function(v)
30969 this.monthField.setValue(v, true);
30970 this.inputEl.dom.value = this.getValue();
30975 setYear : function(v)
30977 this.yearField.setValue(v);
30978 this.inputEl.dom.value = this.getValue();
30983 getDay : function()
30985 return this.dayField.getValue();
30988 getMonth : function()
30990 return this.monthField.getValue();
30993 getYear : function()
30995 return this.yearField.getValue();
30998 getValue : function()
31000 var f = this.yearFormat + '-' + this.monthFormat + '-' + this.dayFormat;
31002 var date = this.yearField.getValue() + '-' + this.monthField.getValue() + '-' + this.dayField.getValue();
31012 this.inputEl.dom.value = '';
31017 validate : function()
31019 var d = this.dayField.validate();
31020 var m = this.monthField.validate();
31021 var y = this.yearField.validate();
31026 (!this.dayAllowBlank && !d) ||
31027 (!this.monthAllowBlank && !m) ||
31028 (!this.yearAllowBlank && !y)
31033 if(this.dayAllowBlank && this.monthAllowBlank && this.yearAllowBlank){
31042 this.markInvalid();
31047 markValid : function()
31050 var label = this.el.select('label', true).first();
31051 var icon = this.el.select('i.fa-star', true).first();
31057 this.fireEvent('valid', this);
31061 * Mark this field as invalid
31062 * @param {String} msg The validation message
31064 markInvalid : function(msg)
31067 var label = this.el.select('label', true).first();
31068 var icon = this.el.select('i.fa-star', true).first();
31070 if(label && !icon){
31071 this.el.select('.roo-date-split-field-label', true).createChild({
31073 cls : 'text-danger fa fa-lg fa-star',
31074 tooltip : 'This field is required',
31075 style : 'margin-right:5px;'
31079 this.fireEvent('invalid', this, msg);
31082 clearInvalid : function()
31084 var label = this.el.select('label', true).first();
31085 var icon = this.el.select('i.fa-star', true).first();
31091 this.fireEvent('valid', this);
31094 getName: function()
31104 * http://masonry.desandro.com
31106 * The idea is to render all the bricks based on vertical width...
31108 * The original code extends 'outlayer' - we might need to use that....
31114 * @class Roo.bootstrap.LayoutMasonry
31115 * @extends Roo.bootstrap.Component
31116 * Bootstrap Layout Masonry class
31119 * Create a new Element
31120 * @param {Object} config The config object
31123 Roo.bootstrap.LayoutMasonry = function(config){
31125 Roo.bootstrap.LayoutMasonry.superclass.constructor.call(this, config);
31129 Roo.bootstrap.LayoutMasonry.register(this);
31135 * Fire after layout the items
31136 * @param {Roo.bootstrap.LayoutMasonry} this
31137 * @param {Roo.EventObject} e
31144 Roo.extend(Roo.bootstrap.LayoutMasonry, Roo.bootstrap.Component, {
31147 * @cfg {Boolean} isLayoutInstant = no animation?
31149 isLayoutInstant : false, // needed?
31152 * @cfg {Number} boxWidth width of the columns
31157 * @cfg {Number} boxHeight - 0 for square, or fix it at a certian height
31162 * @cfg {Number} padWidth padding below box..
31167 * @cfg {Number} gutter gutter width..
31172 * @cfg {Number} maxCols maximum number of columns
31178 * @cfg {Boolean} isAutoInitial defalut true
31180 isAutoInitial : true,
31185 * @cfg {Boolean} isHorizontal defalut false
31187 isHorizontal : false,
31189 currentSize : null,
31195 bricks: null, //CompositeElement
31199 _isLayoutInited : false,
31201 // isAlternative : false, // only use for vertical layout...
31204 * @cfg {Number} alternativePadWidth padding below box..
31206 alternativePadWidth : 50,
31208 selectedBrick : [],
31210 getAutoCreate : function(){
31212 var cfg = Roo.apply({}, Roo.bootstrap.LayoutMasonry.superclass.getAutoCreate.call(this));
31216 cls: 'blog-masonary-wrapper ' + this.cls,
31218 cls : 'mas-boxes masonary'
31225 getChildContainer: function( )
31227 if (this.boxesEl) {
31228 return this.boxesEl;
31231 this.boxesEl = this.el.select('.mas-boxes').first();
31233 return this.boxesEl;
31237 initEvents : function()
31241 if(this.isAutoInitial){
31242 Roo.log('hook children rendered');
31243 this.on('childrenrendered', function() {
31244 Roo.log('children rendered');
31250 initial : function()
31252 this.selectedBrick = [];
31254 this.currentSize = this.el.getBox(true);
31256 Roo.EventManager.onWindowResize(this.resize, this);
31258 if(!this.isAutoInitial){
31266 //this.layout.defer(500,this);
31270 resize : function()
31272 var cs = this.el.getBox(true);
31275 this.currentSize.width == cs.width &&
31276 this.currentSize.x == cs.x &&
31277 this.currentSize.height == cs.height &&
31278 this.currentSize.y == cs.y
31280 Roo.log("no change in with or X or Y");
31284 this.currentSize = cs;
31290 layout : function()
31292 this._resetLayout();
31294 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
31296 this.layoutItems( isInstant );
31298 this._isLayoutInited = true;
31300 this.fireEvent('layout', this);
31304 _resetLayout : function()
31306 if(this.isHorizontal){
31307 this.horizontalMeasureColumns();
31311 this.verticalMeasureColumns();
31315 verticalMeasureColumns : function()
31317 this.getContainerWidth();
31319 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31320 // this.colWidth = Math.floor(this.containerWidth * 0.8);
31324 var boxWidth = this.boxWidth + this.padWidth;
31326 if(this.containerWidth < this.boxWidth){
31327 boxWidth = this.containerWidth
31330 var containerWidth = this.containerWidth;
31332 var cols = Math.floor(containerWidth / boxWidth);
31334 this.cols = Math.max( cols, 1 );
31336 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
31338 var totalBoxWidth = this.cols * boxWidth - this.padWidth;
31340 var avail = Math.floor((containerWidth - totalBoxWidth) / this.cols);
31342 this.colWidth = boxWidth + avail - this.padWidth;
31344 this.unitWidth = Math.round((this.colWidth - (this.gutter * 2)) / 3);
31345 this.unitHeight = this.boxHeight > 0 ? this.boxHeight : this.unitWidth;
31348 horizontalMeasureColumns : function()
31350 this.getContainerWidth();
31352 var boxWidth = this.boxWidth;
31354 if(this.containerWidth < boxWidth){
31355 boxWidth = this.containerWidth;
31358 this.unitWidth = Math.floor((boxWidth - (this.gutter * 2)) / 3);
31360 this.el.setHeight(boxWidth);
31364 getContainerWidth : function()
31366 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
31369 layoutItems : function( isInstant )
31371 Roo.log(this.bricks);
31373 var items = Roo.apply([], this.bricks);
31375 if(this.isHorizontal){
31376 this._horizontalLayoutItems( items , isInstant );
31380 // if(Roo.lib.Dom.getViewWidth() < 768 && this.isAlternative){
31381 // this._verticalAlternativeLayoutItems( items , isInstant );
31385 this._verticalLayoutItems( items , isInstant );
31389 _verticalLayoutItems : function ( items , isInstant)
31391 if ( !items || !items.length ) {
31396 ['xs', 'xs', 'xs', 'tall'],
31397 ['xs', 'xs', 'tall'],
31398 ['xs', 'xs', 'sm'],
31399 ['xs', 'xs', 'xs'],
31405 ['sm', 'xs', 'xs'],
31409 ['tall', 'xs', 'xs', 'xs'],
31410 ['tall', 'xs', 'xs'],
31422 Roo.each(items, function(item, k){
31424 switch (item.size) {
31425 // these layouts take up a full box,
31436 boxes.push([item]);
31459 var filterPattern = function(box, length)
31467 var pattern = box.slice(0, length);
31471 Roo.each(pattern, function(i){
31472 format.push(i.size);
31475 Roo.each(standard, function(s){
31477 if(String(s) != String(format)){
31486 if(!match && length == 1){
31491 filterPattern(box, length - 1);
31495 queue.push(pattern);
31497 box = box.slice(length, box.length);
31499 filterPattern(box, 4);
31505 Roo.each(boxes, function(box, k){
31511 if(box.length == 1){
31516 filterPattern(box, 4);
31520 this._processVerticalLayoutQueue( queue, isInstant );
31524 // _verticalAlternativeLayoutItems : function( items , isInstant )
31526 // if ( !items || !items.length ) {
31530 // this._processVerticalAlternativeLayoutQueue( items, isInstant );
31534 _horizontalLayoutItems : function ( items , isInstant)
31536 if ( !items || !items.length || items.length < 3) {
31542 var eItems = items.slice(0, 3);
31544 items = items.slice(3, items.length);
31547 ['xs', 'xs', 'xs', 'wide'],
31548 ['xs', 'xs', 'wide'],
31549 ['xs', 'xs', 'sm'],
31550 ['xs', 'xs', 'xs'],
31556 ['sm', 'xs', 'xs'],
31560 ['wide', 'xs', 'xs', 'xs'],
31561 ['wide', 'xs', 'xs'],
31574 Roo.each(items, function(item, k){
31576 switch (item.size) {
31587 boxes.push([item]);
31611 var filterPattern = function(box, length)
31619 var pattern = box.slice(0, length);
31623 Roo.each(pattern, function(i){
31624 format.push(i.size);
31627 Roo.each(standard, function(s){
31629 if(String(s) != String(format)){
31638 if(!match && length == 1){
31643 filterPattern(box, length - 1);
31647 queue.push(pattern);
31649 box = box.slice(length, box.length);
31651 filterPattern(box, 4);
31657 Roo.each(boxes, function(box, k){
31663 if(box.length == 1){
31668 filterPattern(box, 4);
31675 var pos = this.el.getBox(true);
31679 var maxX = pos.right - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31681 var hit_end = false;
31683 Roo.each(queue, function(box){
31687 Roo.each(box, function(b){
31689 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31699 Roo.each(box, function(b){
31701 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31704 mx = Math.max(mx, b.x);
31708 maxX = maxX - this.unitWidth * mx - this.gutter * (mx - 1) - this.padWidth;
31712 Roo.each(box, function(b){
31714 b.el.setVisibilityMode(Roo.Element.DISPLAY);
31728 this._processHorizontalLayoutQueue( prune, eItems, isInstant );
31731 /** Sets position of item in DOM
31732 * @param {Element} item
31733 * @param {Number} x - horizontal position
31734 * @param {Number} y - vertical position
31735 * @param {Boolean} isInstant - disables transitions
31737 _processVerticalLayoutQueue : function( queue, isInstant )
31739 var pos = this.el.getBox(true);
31744 for (var i = 0; i < this.cols; i++){
31748 Roo.each(queue, function(box, k){
31750 var col = k % this.cols;
31752 Roo.each(box, function(b,kk){
31754 b.el.position('absolute');
31756 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31757 var height = Math.floor(this.unitHeight * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31759 if(b.size == 'md-left' || b.size == 'md-right'){
31760 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31761 height = Math.floor(this.unitHeight * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31764 b.el.setWidth(width);
31765 b.el.setHeight(height);
31767 b.el.select('iframe',true).setSize(width,height);
31771 for (var i = 0; i < this.cols; i++){
31773 if(maxY[i] < maxY[col]){
31778 col = Math.min(col, i);
31782 x = pos.x + col * (this.colWidth + this.padWidth);
31786 var positions = [];
31788 switch (box.length){
31790 positions = this.getVerticalOneBoxColPositions(x, y, box);
31793 positions = this.getVerticalTwoBoxColPositions(x, y, box);
31796 positions = this.getVerticalThreeBoxColPositions(x, y, box);
31799 positions = this.getVerticalFourBoxColPositions(x, y, box);
31805 Roo.each(box, function(b,kk){
31807 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31809 var sz = b.el.getSize();
31811 maxY[col] = Math.max(maxY[col], positions[kk].y + sz.height + this.padWidth);
31819 for (var i = 0; i < this.cols; i++){
31820 mY = Math.max(mY, maxY[i]);
31823 this.el.setHeight(mY - pos.y);
31827 // _processVerticalAlternativeLayoutQueue : function( items, isInstant )
31829 // var pos = this.el.getBox(true);
31832 // var maxX = pos.right;
31834 // var maxHeight = 0;
31836 // Roo.each(items, function(item, k){
31840 // item.el.position('absolute');
31842 // var width = Math.floor(this.colWidth + item.el.getPadding('lr'));
31844 // item.el.setWidth(width);
31846 // var height = Math.floor(this.colWidth * item.y / item.x + item.el.getPadding('tb'));
31848 // item.el.setHeight(height);
31851 // item.el.setXY([x, y], isInstant ? false : true);
31853 // item.el.setXY([maxX - width, y], isInstant ? false : true);
31856 // y = y + height + this.alternativePadWidth;
31858 // maxHeight = maxHeight + height + this.alternativePadWidth;
31862 // this.el.setHeight(maxHeight);
31866 _processHorizontalLayoutQueue : function( queue, eItems, isInstant )
31868 var pos = this.el.getBox(true);
31873 var maxX = pos.right;
31875 this._processHorizontalEndItem(eItems, maxX, minX, minY, isInstant);
31877 var maxX = maxX - this.unitWidth * 3 - this.gutter * 2 - this.padWidth;
31879 Roo.each(queue, function(box, k){
31881 Roo.each(box, function(b, kk){
31883 b.el.position('absolute');
31885 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31886 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31888 if(b.size == 'md-left' || b.size == 'md-right'){
31889 width = Math.floor(this.unitWidth * (b.x - 1) + (this.gutter * (b.x - 2)) + b.el.getPadding('lr'));
31890 height = Math.floor(this.unitWidth * (b.y - 1) + (this.gutter * (b.y - 2)) + b.el.getPadding('tb'));
31893 b.el.setWidth(width);
31894 b.el.setHeight(height);
31902 var positions = [];
31904 switch (box.length){
31906 positions = this.getHorizontalOneBoxColPositions(maxX, minY, box);
31909 positions = this.getHorizontalTwoBoxColPositions(maxX, minY, box);
31912 positions = this.getHorizontalThreeBoxColPositions(maxX, minY, box);
31915 positions = this.getHorizontalFourBoxColPositions(maxX, minY, box);
31921 Roo.each(box, function(b,kk){
31923 b.el.setXY([positions[kk].x, positions[kk].y], isInstant ? false : true);
31925 maxX = Math.min(maxX, positions[kk].x - this.padWidth);
31933 _processHorizontalEndItem : function(eItems, maxX, minX, minY, isInstant)
31935 Roo.each(eItems, function(b,k){
31937 b.size = (k == 0) ? 'sm' : 'xs';
31938 b.x = (k == 0) ? 2 : 1;
31939 b.y = (k == 0) ? 2 : 1;
31941 b.el.position('absolute');
31943 var width = Math.floor(this.unitWidth * b.x + (this.gutter * (b.x - 1)) + b.el.getPadding('lr'));
31945 b.el.setWidth(width);
31947 var height = Math.floor(this.unitWidth * b.y + (this.gutter * (b.y - 1)) + b.el.getPadding('tb'));
31949 b.el.setHeight(height);
31953 var positions = [];
31956 x : maxX - this.unitWidth * 2 - this.gutter,
31961 x : maxX - this.unitWidth,
31962 y : minY + (this.unitWidth + this.gutter) * 2
31966 x : maxX - this.unitWidth * 3 - this.gutter * 2,
31970 Roo.each(eItems, function(b,k){
31972 b.el.setXY([positions[k].x, positions[k].y], isInstant ? false : true);
31978 getVerticalOneBoxColPositions : function(x, y, box)
31982 var rand = Math.floor(Math.random() * ((4 - box[0].x)));
31984 if(box[0].size == 'md-left'){
31988 if(box[0].size == 'md-right'){
31993 x : x + (this.unitWidth + this.gutter) * rand,
32000 getVerticalTwoBoxColPositions : function(x, y, box)
32004 if(box[0].size == 'xs'){
32008 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[1].y))
32012 x : x + (this.unitWidth + this.gutter) * (3 - box[1].x),
32026 x : x + (this.unitWidth + this.gutter) * 2,
32027 y : y + ((this.unitHeight + this.gutter) * Math.floor(Math.random() * box[0].y))
32034 getVerticalThreeBoxColPositions : function(x, y, box)
32038 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32046 x : x + (this.unitWidth + this.gutter) * 1,
32051 x : x + (this.unitWidth + this.gutter) * 2,
32059 if(box[0].size == 'xs' && box[1].size == 'xs'){
32068 y : y + ((this.unitHeight + this.gutter) * (box[2].y - 1))
32072 x : x + (this.unitWidth + this.gutter) * 1,
32086 x : x + (this.unitWidth + this.gutter) * 2,
32091 x : x + (this.unitWidth + this.gutter) * 2,
32092 y : y + (this.unitHeight + this.gutter) * (box[0].y - 1)
32099 getVerticalFourBoxColPositions : function(x, y, box)
32103 if(box[0].size == 'xs'){
32112 y : y + (this.unitHeight + this.gutter) * 1
32117 y : y + (this.unitHeight + this.gutter) * 2
32121 x : x + (this.unitWidth + this.gutter) * 1,
32135 x : x + (this.unitWidth + this.gutter) * 2,
32140 x : x + (this.unitHeightunitWidth + this.gutter) * 2,
32141 y : y + (this.unitHeight + this.gutter) * 1
32145 x : x + (this.unitWidth + this.gutter) * 2,
32146 y : y + (this.unitWidth + this.gutter) * 2
32153 getHorizontalOneBoxColPositions : function(maxX, minY, box)
32157 if(box[0].size == 'md-left'){
32159 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32166 if(box[0].size == 'md-right'){
32168 x : maxX - this.unitWidth * (box[0].x - 1) - this.gutter * (box[0].x - 2),
32169 y : minY + (this.unitWidth + this.gutter) * 1
32175 var rand = Math.floor(Math.random() * (4 - box[0].y));
32178 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32179 y : minY + (this.unitWidth + this.gutter) * rand
32186 getHorizontalTwoBoxColPositions : function(maxX, minY, box)
32190 if(box[0].size == 'xs'){
32193 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32198 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32199 y : minY + (this.unitWidth + this.gutter) * (3 - box[1].y)
32207 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32212 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32213 y : minY + (this.unitWidth + this.gutter) * 2
32220 getHorizontalThreeBoxColPositions : function(maxX, minY, box)
32224 if(box[0].size == 'xs' && box[1].size == 'xs' && box[2].size == 'xs'){
32227 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32232 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32233 y : minY + (this.unitWidth + this.gutter) * 1
32237 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32238 y : minY + (this.unitWidth + this.gutter) * 2
32245 if(box[0].size == 'xs' && box[1].size == 'xs'){
32248 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32253 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32258 x : maxX - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32259 y : minY + (this.unitWidth + this.gutter) * 1
32267 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32272 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32273 y : minY + (this.unitWidth + this.gutter) * 2
32277 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32278 y : minY + (this.unitWidth + this.gutter) * 2
32285 getHorizontalFourBoxColPositions : function(maxX, minY, box)
32289 if(box[0].size == 'xs'){
32292 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32297 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1) - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32302 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),
32307 x : maxX - this.unitWidth * box[3].x - this.gutter * (box[3].x - 1),
32308 y : minY + (this.unitWidth + this.gutter) * 1
32316 x : maxX - this.unitWidth * box[0].x - this.gutter * (box[0].x - 1),
32321 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1),
32322 y : minY + (this.unitWidth + this.gutter) * 2
32326 x : maxX - this.unitWidth * box[1].x - this.gutter * (box[1].x - 1) - this.unitWidth * box[2].x - this.gutter * (box[2].x - 1),
32327 y : minY + (this.unitWidth + this.gutter) * 2
32331 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),
32332 y : minY + (this.unitWidth + this.gutter) * 2
32340 * remove a Masonry Brick
32341 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to remove
32343 removeBrick : function(brick_id)
32349 for (var i = 0; i<this.bricks.length; i++) {
32350 if (this.bricks[i].id == brick_id) {
32351 this.bricks.splice(i,1);
32352 this.el.dom.removeChild(Roo.get(brick_id).dom);
32359 * adds a Masonry Brick
32360 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32362 addBrick : function(cfg)
32364 var cn = new Roo.bootstrap.MasonryBrick(cfg);
32365 //this.register(cn);
32366 cn.parentId = this.id;
32367 cn.render(this.el);
32372 * register a Masonry Brick
32373 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
32376 register : function(brick)
32378 this.bricks.push(brick);
32379 brick.masonryId = this.id;
32383 * clear all the Masonry Brick
32385 clearAll : function()
32388 //this.getChildContainer().dom.innerHTML = "";
32389 this.el.dom.innerHTML = '';
32392 getSelected : function()
32394 if (!this.selectedBrick) {
32398 return this.selectedBrick;
32402 Roo.apply(Roo.bootstrap.LayoutMasonry, {
32406 * register a Masonry Layout
32407 * @param {Roo.bootstrap.LayoutMasonry} the masonry layout to add
32410 register : function(layout)
32412 this.groups[layout.id] = layout;
32415 * fetch a Masonry Layout based on the masonry layout ID
32416 * @param {string} the masonry layout to add
32417 * @returns {Roo.bootstrap.LayoutMasonry} the masonry layout
32420 get: function(layout_id) {
32421 if (typeof(this.groups[layout_id]) == 'undefined') {
32424 return this.groups[layout_id] ;
32436 * http://masonry.desandro.com
32438 * The idea is to render all the bricks based on vertical width...
32440 * The original code extends 'outlayer' - we might need to use that....
32446 * @class Roo.bootstrap.LayoutMasonryAuto
32447 * @extends Roo.bootstrap.Component
32448 * Bootstrap Layout Masonry class
32451 * Create a new Element
32452 * @param {Object} config The config object
32455 Roo.bootstrap.LayoutMasonryAuto = function(config){
32456 Roo.bootstrap.LayoutMasonryAuto.superclass.constructor.call(this, config);
32459 Roo.extend(Roo.bootstrap.LayoutMasonryAuto, Roo.bootstrap.Component, {
32462 * @cfg {Boolean} isFitWidth - resize the width..
32464 isFitWidth : false, // options..
32466 * @cfg {Boolean} isOriginLeft = left align?
32468 isOriginLeft : true,
32470 * @cfg {Boolean} isOriginTop = top align?
32472 isOriginTop : false,
32474 * @cfg {Boolean} isLayoutInstant = no animation?
32476 isLayoutInstant : false, // needed?
32478 * @cfg {Boolean} isResizingContainer = not sure if this is used..
32480 isResizingContainer : true,
32482 * @cfg {Number} columnWidth width of the columns
32488 * @cfg {Number} maxCols maximum number of columns
32493 * @cfg {Number} padHeight padding below box..
32499 * @cfg {Boolean} isAutoInitial defalut true
32502 isAutoInitial : true,
32508 initialColumnWidth : 0,
32509 currentSize : null,
32511 colYs : null, // array.
32518 bricks: null, //CompositeElement
32519 cols : 0, // array?
32520 // element : null, // wrapped now this.el
32521 _isLayoutInited : null,
32524 getAutoCreate : function(){
32528 cls: 'blog-masonary-wrapper ' + this.cls,
32530 cls : 'mas-boxes masonary'
32537 getChildContainer: function( )
32539 if (this.boxesEl) {
32540 return this.boxesEl;
32543 this.boxesEl = this.el.select('.mas-boxes').first();
32545 return this.boxesEl;
32549 initEvents : function()
32553 if(this.isAutoInitial){
32554 Roo.log('hook children rendered');
32555 this.on('childrenrendered', function() {
32556 Roo.log('children rendered');
32563 initial : function()
32565 this.reloadItems();
32567 this.currentSize = this.el.getBox(true);
32569 /// was window resize... - let's see if this works..
32570 Roo.EventManager.onWindowResize(this.resize, this);
32572 if(!this.isAutoInitial){
32577 this.layout.defer(500,this);
32580 reloadItems: function()
32582 this.bricks = this.el.select('.masonry-brick', true);
32584 this.bricks.each(function(b) {
32585 //Roo.log(b.getSize());
32586 if (!b.attr('originalwidth')) {
32587 b.attr('originalwidth', b.getSize().width);
32592 Roo.log(this.bricks.elements.length);
32595 resize : function()
32598 var cs = this.el.getBox(true);
32600 if (this.currentSize.width == cs.width && this.currentSize.x == cs.x ) {
32601 Roo.log("no change in with or X");
32604 this.currentSize = cs;
32608 layout : function()
32611 this._resetLayout();
32612 //this._manageStamps();
32614 // don't animate first layout
32615 var isInstant = this.isLayoutInstant !== undefined ? this.isLayoutInstant : !this._isLayoutInited;
32616 this.layoutItems( isInstant );
32618 // flag for initalized
32619 this._isLayoutInited = true;
32622 layoutItems : function( isInstant )
32624 //var items = this._getItemsForLayout( this.items );
32625 // original code supports filtering layout items.. we just ignore it..
32627 this._layoutItems( this.bricks , isInstant );
32629 this._postLayout();
32631 _layoutItems : function ( items , isInstant)
32633 //this.fireEvent( 'layout', this, items );
32636 if ( !items || !items.elements.length ) {
32637 // no items, emit event with empty array
32642 items.each(function(item) {
32643 Roo.log("layout item");
32645 // get x/y object from method
32646 var position = this._getItemLayoutPosition( item );
32648 position.item = item;
32649 position.isInstant = isInstant; // || item.isLayoutInstant; << not set yet...
32650 queue.push( position );
32653 this._processLayoutQueue( queue );
32655 /** Sets position of item in DOM
32656 * @param {Element} item
32657 * @param {Number} x - horizontal position
32658 * @param {Number} y - vertical position
32659 * @param {Boolean} isInstant - disables transitions
32661 _processLayoutQueue : function( queue )
32663 for ( var i=0, len = queue.length; i < len; i++ ) {
32664 var obj = queue[i];
32665 obj.item.position('absolute');
32666 obj.item.setXY([obj.x,obj.y], obj.isInstant ? false : true);
32672 * Any logic you want to do after each layout,
32673 * i.e. size the container
32675 _postLayout : function()
32677 this.resizeContainer();
32680 resizeContainer : function()
32682 if ( !this.isResizingContainer ) {
32685 var size = this._getContainerSize();
32687 this.el.setSize(size.width,size.height);
32688 this.boxesEl.setSize(size.width,size.height);
32694 _resetLayout : function()
32696 //this.getSize(); // -- does not really do anything.. it probably applies left/right etc. to obuject but not used
32697 this.colWidth = this.el.getWidth();
32698 //this.gutter = this.el.getWidth();
32700 this.measureColumns();
32706 this.colYs.push( 0 );
32712 measureColumns : function()
32714 this.getContainerWidth();
32715 // if columnWidth is 0, default to outerWidth of first item
32716 if ( !this.columnWidth ) {
32717 var firstItem = this.bricks.first();
32718 Roo.log(firstItem);
32719 this.columnWidth = this.containerWidth;
32720 if (firstItem && firstItem.attr('originalwidth') ) {
32721 this.columnWidth = 1* (firstItem.attr('originalwidth') || firstItem.getWidth());
32723 // columnWidth fall back to item of first element
32724 Roo.log("set column width?");
32725 this.initialColumnWidth = this.columnWidth ;
32727 // if first elem has no width, default to size of container
32732 if (this.initialColumnWidth) {
32733 this.columnWidth = this.initialColumnWidth;
32738 // column width is fixed at the top - however if container width get's smaller we should
32741 // this bit calcs how man columns..
32743 var columnWidth = this.columnWidth += this.gutter;
32745 // calculate columns
32746 var containerWidth = this.containerWidth + this.gutter;
32748 var cols = (containerWidth - this.padWidth) / (columnWidth - this.padWidth);
32749 // fix rounding errors, typically with gutters
32750 var excess = columnWidth - containerWidth % columnWidth;
32753 // if overshoot is less than a pixel, round up, otherwise floor it
32754 var mathMethod = excess && excess < 1 ? 'round' : 'floor';
32755 cols = Math[ mathMethod ]( cols );
32756 this.cols = Math.max( cols, 1 );
32757 this.cols = this.maxCols > 0 ? Math.min( this.cols, this.maxCols ) : this.cols;
32759 // padding positioning..
32760 var totalColWidth = this.cols * this.columnWidth;
32761 var padavail = this.containerWidth - totalColWidth;
32762 // so for 2 columns - we need 3 'pads'
32764 var padNeeded = (1+this.cols) * this.padWidth;
32766 var padExtra = Math.floor((padavail - padNeeded) / this.cols);
32768 this.columnWidth += padExtra
32769 //this.padWidth = Math.floor(padavail / ( this.cols));
32771 // adjust colum width so that padding is fixed??
32773 // we have 3 columns ... total = width * 3
32774 // we have X left over... that should be used by
32776 //if (this.expandC) {
32784 getContainerWidth : function()
32786 /* // container is parent if fit width
32787 var container = this.isFitWidth ? this.element.parentNode : this.element;
32788 // check that this.size and size are there
32789 // IE8 triggers resize on body size change, so they might not be
32791 var size = getSize( container ); //FIXME
32792 this.containerWidth = size && size.innerWidth; //FIXME
32795 this.containerWidth = this.el.getBox(true).width; //maybe use getComputedWidth
32799 _getItemLayoutPosition : function( item ) // what is item?
32801 // we resize the item to our columnWidth..
32803 item.setWidth(this.columnWidth);
32804 item.autoBoxAdjust = false;
32806 var sz = item.getSize();
32808 // how many columns does this brick span
32809 var remainder = this.containerWidth % this.columnWidth;
32811 var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';
32812 // round if off by 1 pixel, otherwise use ceil
32813 var colSpan = Math[ mathMethod ]( sz.width / this.columnWidth );
32814 colSpan = Math.min( colSpan, this.cols );
32816 // normally this should be '1' as we dont' currently allow multi width columns..
32818 var colGroup = this._getColGroup( colSpan );
32819 // get the minimum Y value from the columns
32820 var minimumY = Math.min.apply( Math, colGroup );
32821 Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32823 var shortColIndex = colGroup.indexOf( minimumY ); // broken on ie8..?? probably...
32825 // position the brick
32827 x: this.currentSize.x + (this.padWidth /2) + ((this.columnWidth + this.padWidth )* shortColIndex),
32828 y: this.currentSize.y + minimumY + this.padHeight
32832 // apply setHeight to necessary columns
32833 var setHeight = minimumY + sz.height + this.padHeight;
32834 //Roo.log([ 'setHeight', minimumY, sz.height, setHeight ]);
32836 var setSpan = this.cols + 1 - colGroup.length;
32837 for ( var i = 0; i < setSpan; i++ ) {
32838 this.colYs[ shortColIndex + i ] = setHeight ;
32845 * @param {Number} colSpan - number of columns the element spans
32846 * @returns {Array} colGroup
32848 _getColGroup : function( colSpan )
32850 if ( colSpan < 2 ) {
32851 // if brick spans only one column, use all the column Ys
32856 // how many different places could this brick fit horizontally
32857 var groupCount = this.cols + 1 - colSpan;
32858 // for each group potential horizontal position
32859 for ( var i = 0; i < groupCount; i++ ) {
32860 // make an array of colY values for that one group
32861 var groupColYs = this.colYs.slice( i, i + colSpan );
32862 // and get the max value of the array
32863 colGroup[i] = Math.max.apply( Math, groupColYs );
32868 _manageStamp : function( stamp )
32870 var stampSize = stamp.getSize();
32871 var offset = stamp.getBox();
32872 // get the columns that this stamp affects
32873 var firstX = this.isOriginLeft ? offset.x : offset.right;
32874 var lastX = firstX + stampSize.width;
32875 var firstCol = Math.floor( firstX / this.columnWidth );
32876 firstCol = Math.max( 0, firstCol );
32878 var lastCol = Math.floor( lastX / this.columnWidth );
32879 // lastCol should not go over if multiple of columnWidth #425
32880 lastCol -= lastX % this.columnWidth ? 0 : 1;
32881 lastCol = Math.min( this.cols - 1, lastCol );
32883 // set colYs to bottom of the stamp
32884 var stampMaxY = ( this.isOriginTop ? offset.y : offset.bottom ) +
32887 for ( var i = firstCol; i <= lastCol; i++ ) {
32888 this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );
32893 _getContainerSize : function()
32895 this.maxY = Math.max.apply( Math, this.colYs );
32900 if ( this.isFitWidth ) {
32901 size.width = this._getContainerFitWidth();
32907 _getContainerFitWidth : function()
32909 var unusedCols = 0;
32910 // count unused columns
32913 if ( this.colYs[i] !== 0 ) {
32918 // fit container to columns that have been used
32919 return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;
32922 needsResizeLayout : function()
32924 var previousWidth = this.containerWidth;
32925 this.getContainerWidth();
32926 return previousWidth !== this.containerWidth;
32941 * @class Roo.bootstrap.MasonryBrick
32942 * @extends Roo.bootstrap.Component
32943 * Bootstrap MasonryBrick class
32946 * Create a new MasonryBrick
32947 * @param {Object} config The config object
32950 Roo.bootstrap.MasonryBrick = function(config){
32952 Roo.bootstrap.MasonryBrick.superclass.constructor.call(this, config);
32954 Roo.bootstrap.MasonryBrick.register(this);
32960 * When a MasonryBrick is clcik
32961 * @param {Roo.bootstrap.MasonryBrick} this
32962 * @param {Roo.EventObject} e
32968 Roo.extend(Roo.bootstrap.MasonryBrick, Roo.bootstrap.Component, {
32971 * @cfg {String} title
32975 * @cfg {String} html
32979 * @cfg {String} bgimage
32983 * @cfg {String} videourl
32987 * @cfg {String} cls
32991 * @cfg {String} href
32995 * @cfg {String} size (xs|sm|md|md-left|md-right|tall|wide)
33000 * @cfg {String} placetitle (center|bottom)
33005 * @cfg {Boolean} isFitContainer defalut true
33007 isFitContainer : true,
33010 * @cfg {Boolean} preventDefault defalut false
33012 preventDefault : false,
33015 * @cfg {Boolean} inverse defalut false
33017 maskInverse : false,
33019 getAutoCreate : function()
33021 if(!this.isFitContainer){
33022 return this.getSplitAutoCreate();
33025 var cls = 'masonry-brick masonry-brick-full';
33027 if(this.href.length){
33028 cls += ' masonry-brick-link';
33031 if(this.bgimage.length){
33032 cls += ' masonry-brick-image';
33035 if(this.maskInverse){
33036 cls += ' mask-inverse';
33039 if(!this.html.length && !this.maskInverse && !this.videourl.length){
33040 cls += ' enable-mask';
33044 cls += ' masonry-' + this.size + '-brick';
33047 if(this.placetitle.length){
33049 switch (this.placetitle) {
33051 cls += ' masonry-center-title';
33054 cls += ' masonry-bottom-title';
33061 if(!this.html.length && !this.bgimage.length){
33062 cls += ' masonry-center-title';
33065 if(!this.html.length && this.bgimage.length){
33066 cls += ' masonry-bottom-title';
33071 cls += ' ' + this.cls;
33075 tag: (this.href.length) ? 'a' : 'div',
33080 cls: 'masonry-brick-mask'
33084 cls: 'masonry-brick-paragraph',
33090 if(this.href.length){
33091 cfg.href = this.href;
33094 var cn = cfg.cn[1].cn;
33096 if(this.title.length){
33099 cls: 'masonry-brick-title',
33104 if(this.html.length){
33107 cls: 'masonry-brick-text',
33112 if (!this.title.length && !this.html.length) {
33113 cfg.cn[1].cls += ' hide';
33116 if(this.bgimage.length){
33119 cls: 'masonry-brick-image-view',
33124 if(this.videourl.length){
33125 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33126 // youtube support only?
33129 cls: 'masonry-brick-image-view',
33132 allowfullscreen : true
33140 getSplitAutoCreate : function()
33142 var cls = 'masonry-brick masonry-brick-split';
33144 if(this.href.length){
33145 cls += ' masonry-brick-link';
33148 if(this.bgimage.length){
33149 cls += ' masonry-brick-image';
33153 cls += ' masonry-' + this.size + '-brick';
33156 switch (this.placetitle) {
33158 cls += ' masonry-center-title';
33161 cls += ' masonry-bottom-title';
33164 if(!this.bgimage.length){
33165 cls += ' masonry-center-title';
33168 if(this.bgimage.length){
33169 cls += ' masonry-bottom-title';
33175 cls += ' ' + this.cls;
33179 tag: (this.href.length) ? 'a' : 'div',
33184 cls: 'masonry-brick-split-head',
33188 cls: 'masonry-brick-paragraph',
33195 cls: 'masonry-brick-split-body',
33201 if(this.href.length){
33202 cfg.href = this.href;
33205 if(this.title.length){
33206 cfg.cn[0].cn[0].cn.push({
33208 cls: 'masonry-brick-title',
33213 if(this.html.length){
33214 cfg.cn[1].cn.push({
33216 cls: 'masonry-brick-text',
33221 if(this.bgimage.length){
33222 cfg.cn[0].cn.push({
33224 cls: 'masonry-brick-image-view',
33229 if(this.videourl.length){
33230 var vurl = this.videourl.replace(/https:\/\/youtu\.be/, 'https://www.youtube.com/embed/');
33231 // youtube support only?
33232 cfg.cn[0].cn.cn.push({
33234 cls: 'masonry-brick-image-view',
33237 allowfullscreen : true
33244 initEvents: function()
33246 switch (this.size) {
33279 this.el.on('touchstart', this.onTouchStart, this);
33280 this.el.on('touchmove', this.onTouchMove, this);
33281 this.el.on('touchend', this.onTouchEnd, this);
33282 this.el.on('contextmenu', this.onContextMenu, this);
33284 this.el.on('mouseenter' ,this.enter, this);
33285 this.el.on('mouseleave', this.leave, this);
33286 this.el.on('click', this.onClick, this);
33289 if (typeof(this.parent().bricks) == 'object' && this.parent().bricks != null) {
33290 this.parent().bricks.push(this);
33295 onClick: function(e, el)
33297 var time = this.endTimer - this.startTimer;
33298 // Roo.log(e.preventDefault());
33301 e.preventDefault();
33306 if(!this.preventDefault){
33310 e.preventDefault();
33312 if (this.activeClass != '') {
33313 this.selectBrick();
33316 this.fireEvent('click', this, e);
33319 enter: function(e, el)
33321 e.preventDefault();
33323 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33327 if(this.bgimage.length && this.html.length){
33328 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33332 leave: function(e, el)
33334 e.preventDefault();
33336 if(!this.isFitContainer || this.maskInverse || this.videourl.length){
33340 if(this.bgimage.length && this.html.length){
33341 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33345 onTouchStart: function(e, el)
33347 // e.preventDefault();
33349 this.touchmoved = false;
33351 if(!this.isFitContainer){
33355 if(!this.bgimage.length || !this.html.length){
33359 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0.9, true);
33361 this.timer = new Date().getTime();
33365 onTouchMove: function(e, el)
33367 this.touchmoved = true;
33370 onContextMenu : function(e,el)
33372 e.preventDefault();
33373 e.stopPropagation();
33377 onTouchEnd: function(e, el)
33379 // e.preventDefault();
33381 if((new Date().getTime() - this.timer > 1000) || !this.href.length || this.touchmoved){
33388 if(!this.bgimage.length || !this.html.length){
33390 if(this.href.length){
33391 window.location.href = this.href;
33397 if(!this.isFitContainer){
33401 this.el.select('.masonry-brick-paragraph', true).first().setOpacity(0, true);
33403 window.location.href = this.href;
33406 //selection on single brick only
33407 selectBrick : function() {
33409 if (!this.parentId) {
33413 var m = Roo.bootstrap.LayoutMasonry.get(this.parentId);
33414 var index = m.selectedBrick.indexOf(this.id);
33417 m.selectedBrick.splice(index,1);
33418 this.el.removeClass(this.activeClass);
33422 for(var i = 0; i < m.selectedBrick.length; i++) {
33423 var b = Roo.bootstrap.MasonryBrick.get(m.selectedBrick[i]);
33424 b.el.removeClass(b.activeClass);
33427 m.selectedBrick = [];
33429 m.selectedBrick.push(this.id);
33430 this.el.addClass(this.activeClass);
33434 isSelected : function(){
33435 return this.el.hasClass(this.activeClass);
33440 Roo.apply(Roo.bootstrap.MasonryBrick, {
33443 groups : new Roo.util.MixedCollection(false, function(o) { return o.el.id; }),
33445 * register a Masonry Brick
33446 * @param {Roo.bootstrap.MasonryBrick} the masonry brick to add
33449 register : function(brick)
33451 //this.groups[brick.id] = brick;
33452 this.groups.add(brick.id, brick);
33455 * fetch a masonry brick based on the masonry brick ID
33456 * @param {string} the masonry brick to add
33457 * @returns {Roo.bootstrap.MasonryBrick} the masonry brick
33460 get: function(brick_id)
33462 // if (typeof(this.groups[brick_id]) == 'undefined') {
33465 // return this.groups[brick_id] ;
33467 if(this.groups.key(brick_id)) {
33468 return this.groups.key(brick_id);
33486 * @class Roo.bootstrap.Brick
33487 * @extends Roo.bootstrap.Component
33488 * Bootstrap Brick class
33491 * Create a new Brick
33492 * @param {Object} config The config object
33495 Roo.bootstrap.Brick = function(config){
33496 Roo.bootstrap.Brick.superclass.constructor.call(this, config);
33502 * When a Brick is click
33503 * @param {Roo.bootstrap.Brick} this
33504 * @param {Roo.EventObject} e
33510 Roo.extend(Roo.bootstrap.Brick, Roo.bootstrap.Component, {
33513 * @cfg {String} title
33517 * @cfg {String} html
33521 * @cfg {String} bgimage
33525 * @cfg {String} cls
33529 * @cfg {String} href
33533 * @cfg {String} video
33537 * @cfg {Boolean} square
33541 getAutoCreate : function()
33543 var cls = 'roo-brick';
33545 if(this.href.length){
33546 cls += ' roo-brick-link';
33549 if(this.bgimage.length){
33550 cls += ' roo-brick-image';
33553 if(!this.html.length && !this.bgimage.length){
33554 cls += ' roo-brick-center-title';
33557 if(!this.html.length && this.bgimage.length){
33558 cls += ' roo-brick-bottom-title';
33562 cls += ' ' + this.cls;
33566 tag: (this.href.length) ? 'a' : 'div',
33571 cls: 'roo-brick-paragraph',
33577 if(this.href.length){
33578 cfg.href = this.href;
33581 var cn = cfg.cn[0].cn;
33583 if(this.title.length){
33586 cls: 'roo-brick-title',
33591 if(this.html.length){
33594 cls: 'roo-brick-text',
33601 if(this.bgimage.length){
33604 cls: 'roo-brick-image-view',
33612 initEvents: function()
33614 if(this.title.length || this.html.length){
33615 this.el.on('mouseenter' ,this.enter, this);
33616 this.el.on('mouseleave', this.leave, this);
33619 Roo.EventManager.onWindowResize(this.resize, this);
33621 if(this.bgimage.length){
33622 this.imageEl = this.el.select('.roo-brick-image-view', true).first();
33623 this.imageEl.on('load', this.onImageLoad, this);
33630 onImageLoad : function()
33635 resize : function()
33637 var paragraph = this.el.select('.roo-brick-paragraph', true).first();
33639 paragraph.setHeight(paragraph.getWidth() + paragraph.getPadding('tb'));
33641 if(this.bgimage.length){
33642 var image = this.el.select('.roo-brick-image-view', true).first();
33644 image.setWidth(paragraph.getWidth());
33647 image.setHeight(paragraph.getWidth());
33650 this.el.setHeight(image.getHeight());
33651 paragraph.setHeight(image.getHeight());
33657 enter: function(e, el)
33659 e.preventDefault();
33661 if(this.bgimage.length){
33662 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0.9, true);
33663 this.el.select('.roo-brick-image-view', true).first().setOpacity(0.1, true);
33667 leave: function(e, el)
33669 e.preventDefault();
33671 if(this.bgimage.length){
33672 this.el.select('.roo-brick-paragraph', true).first().setOpacity(0, true);
33673 this.el.select('.roo-brick-image-view', true).first().setOpacity(1, true);
33688 * @class Roo.bootstrap.NumberField
33689 * @extends Roo.bootstrap.Input
33690 * Bootstrap NumberField class
33696 * Create a new NumberField
33697 * @param {Object} config The config object
33700 Roo.bootstrap.NumberField = function(config){
33701 Roo.bootstrap.NumberField.superclass.constructor.call(this, config);
33704 Roo.extend(Roo.bootstrap.NumberField, Roo.bootstrap.Input, {
33707 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
33709 allowDecimals : true,
33711 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
33713 decimalSeparator : ".",
33715 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
33717 decimalPrecision : 2,
33719 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
33721 allowNegative : true,
33724 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
33728 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
33730 minValue : Number.NEGATIVE_INFINITY,
33732 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
33734 maxValue : Number.MAX_VALUE,
33736 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
33738 minText : "The minimum value for this field is {0}",
33740 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
33742 maxText : "The maximum value for this field is {0}",
33744 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
33745 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
33747 nanText : "{0} is not a valid number",
33749 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
33751 thousandsDelimiter : false,
33753 * @cfg {String} valueAlign alignment of value
33755 valueAlign : "left",
33757 getAutoCreate : function()
33759 var hiddenInput = {
33763 cls: 'hidden-number-input'
33767 hiddenInput.name = this.name;
33772 var cfg = Roo.bootstrap.NumberField.superclass.getAutoCreate.call(this);
33774 this.name = hiddenInput.name;
33776 if(cfg.cn.length > 0) {
33777 cfg.cn.push(hiddenInput);
33784 initEvents : function()
33786 Roo.bootstrap.NumberField.superclass.initEvents.call(this);
33788 var allowed = "0123456789";
33790 if(this.allowDecimals){
33791 allowed += this.decimalSeparator;
33794 if(this.allowNegative){
33798 if(this.thousandsDelimiter) {
33802 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
33804 var keyPress = function(e){
33806 var k = e.getKey();
33808 var c = e.getCharCode();
33811 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
33812 allowed.indexOf(String.fromCharCode(c)) === -1
33818 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
33822 if(allowed.indexOf(String.fromCharCode(c)) === -1){
33827 this.el.on("keypress", keyPress, this);
33830 validateValue : function(value)
33833 if(!Roo.bootstrap.NumberField.superclass.validateValue.call(this, value)){
33837 var num = this.parseValue(value);
33840 this.markInvalid(String.format(this.nanText, value));
33844 if(num < this.minValue){
33845 this.markInvalid(String.format(this.minText, this.minValue));
33849 if(num > this.maxValue){
33850 this.markInvalid(String.format(this.maxText, this.maxValue));
33857 getValue : function()
33859 var v = this.hiddenEl().getValue();
33861 return this.fixPrecision(this.parseValue(v));
33864 parseValue : function(value)
33866 if(this.thousandsDelimiter) {
33868 r = new RegExp(",", "g");
33869 value = value.replace(r, "");
33872 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
33873 return isNaN(value) ? '' : value;
33876 fixPrecision : function(value)
33878 if(this.thousandsDelimiter) {
33880 r = new RegExp(",", "g");
33881 value = value.replace(r, "");
33884 var nan = isNaN(value);
33886 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
33887 return nan ? '' : value;
33889 return parseFloat(value).toFixed(this.decimalPrecision);
33892 setValue : function(v)
33894 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
33900 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
33902 this.inputEl().dom.value = (v == '') ? '' :
33903 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
33905 if(!this.allowZero && v === '0') {
33906 this.hiddenEl().dom.value = '';
33907 this.inputEl().dom.value = '';
33914 decimalPrecisionFcn : function(v)
33916 return Math.floor(v);
33919 beforeBlur : function()
33921 var v = this.parseValue(this.getRawValue());
33923 if(v || v === 0 || v === ''){
33928 hiddenEl : function()
33930 return this.el.select('input.hidden-number-input',true).first();
33942 * @class Roo.bootstrap.DocumentSlider
33943 * @extends Roo.bootstrap.Component
33944 * Bootstrap DocumentSlider class
33947 * Create a new DocumentViewer
33948 * @param {Object} config The config object
33951 Roo.bootstrap.DocumentSlider = function(config){
33952 Roo.bootstrap.DocumentSlider.superclass.constructor.call(this, config);
33959 * Fire after initEvent
33960 * @param {Roo.bootstrap.DocumentSlider} this
33965 * Fire after update
33966 * @param {Roo.bootstrap.DocumentSlider} this
33972 * @param {Roo.bootstrap.DocumentSlider} this
33978 Roo.extend(Roo.bootstrap.DocumentSlider, Roo.bootstrap.Component, {
33984 getAutoCreate : function()
33988 cls : 'roo-document-slider',
33992 cls : 'roo-document-slider-header',
33996 cls : 'roo-document-slider-header-title'
34002 cls : 'roo-document-slider-body',
34006 cls : 'roo-document-slider-prev',
34010 cls : 'fa fa-chevron-left'
34016 cls : 'roo-document-slider-thumb',
34020 cls : 'roo-document-slider-image'
34026 cls : 'roo-document-slider-next',
34030 cls : 'fa fa-chevron-right'
34042 initEvents : function()
34044 this.headerEl = this.el.select('.roo-document-slider-header', true).first();
34045 this.headerEl.setVisibilityMode(Roo.Element.DISPLAY);
34047 this.titleEl = this.el.select('.roo-document-slider-header .roo-document-slider-header-title', true).first();
34048 this.titleEl.setVisibilityMode(Roo.Element.DISPLAY);
34050 this.bodyEl = this.el.select('.roo-document-slider-body', true).first();
34051 this.bodyEl.setVisibilityMode(Roo.Element.DISPLAY);
34053 this.thumbEl = this.el.select('.roo-document-slider-thumb', true).first();
34054 this.thumbEl.setVisibilityMode(Roo.Element.DISPLAY);
34056 this.imageEl = this.el.select('.roo-document-slider-image', true).first();
34057 this.imageEl.setVisibilityMode(Roo.Element.DISPLAY);
34059 this.prevIndicator = this.el.select('.roo-document-slider-prev i', true).first();
34060 this.prevIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34062 this.nextIndicator = this.el.select('.roo-document-slider-next i', true).first();
34063 this.nextIndicator.setVisibilityMode(Roo.Element.DISPLAY);
34065 this.thumbEl.on('click', this.onClick, this);
34067 this.prevIndicator.on('click', this.prev, this);
34069 this.nextIndicator.on('click', this.next, this);
34073 initial : function()
34075 if(this.files.length){
34076 this.indicator = 1;
34080 this.fireEvent('initial', this);
34083 update : function()
34085 this.imageEl.attr('src', this.files[this.indicator - 1]);
34087 this.titleEl.dom.innerHTML = String.format('{0} / {1}', this.indicator, this.files.length);
34089 this.prevIndicator.show();
34091 if(this.indicator == 1){
34092 this.prevIndicator.hide();
34095 this.nextIndicator.show();
34097 if(this.indicator == this.files.length){
34098 this.nextIndicator.hide();
34101 this.thumbEl.scrollTo('top');
34103 this.fireEvent('update', this);
34106 onClick : function(e)
34108 e.preventDefault();
34110 this.fireEvent('click', this);
34115 e.preventDefault();
34117 this.indicator = Math.max(1, this.indicator - 1);
34124 e.preventDefault();
34126 this.indicator = Math.min(this.files.length, this.indicator + 1);
34140 * @class Roo.bootstrap.RadioSet
34141 * @extends Roo.bootstrap.Input
34142 * Bootstrap RadioSet class
34143 * @cfg {String} indicatorpos (left|right) default left
34144 * @cfg {Boolean} inline (true|false) inline the element (default true)
34145 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the radio
34147 * Create a new RadioSet
34148 * @param {Object} config The config object
34151 Roo.bootstrap.RadioSet = function(config){
34153 Roo.bootstrap.RadioSet.superclass.constructor.call(this, config);
34157 Roo.bootstrap.RadioSet.register(this);
34162 * Fires when the element is checked or unchecked.
34163 * @param {Roo.bootstrap.RadioSet} this This radio
34164 * @param {Roo.bootstrap.Radio} item The checked item
34169 * Fires when the element is click.
34170 * @param {Roo.bootstrap.RadioSet} this This radio set
34171 * @param {Roo.bootstrap.Radio} item The checked item
34172 * @param {Roo.EventObject} e The event object
34179 Roo.extend(Roo.bootstrap.RadioSet, Roo.bootstrap.Input, {
34187 indicatorpos : 'left',
34189 getAutoCreate : function()
34193 cls : 'roo-radio-set-label',
34197 html : this.fieldLabel
34201 if (Roo.bootstrap.version == 3) {
34204 if(this.indicatorpos == 'left'){
34207 cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star',
34208 tooltip : 'This field is required'
34213 cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star',
34214 tooltip : 'This field is required'
34220 cls : 'roo-radio-set-items'
34223 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
34225 if (align === 'left' && this.fieldLabel.length) {
34228 cls : "roo-radio-set-right",
34234 if(this.labelWidth > 12){
34235 label.style = "width: " + this.labelWidth + 'px';
34238 if(this.labelWidth < 13 && this.labelmd == 0){
34239 this.labelmd = this.labelWidth;
34242 if(this.labellg > 0){
34243 label.cls += ' col-lg-' + this.labellg;
34244 items.cls += ' col-lg-' + (12 - this.labellg);
34247 if(this.labelmd > 0){
34248 label.cls += ' col-md-' + this.labelmd;
34249 items.cls += ' col-md-' + (12 - this.labelmd);
34252 if(this.labelsm > 0){
34253 label.cls += ' col-sm-' + this.labelsm;
34254 items.cls += ' col-sm-' + (12 - this.labelsm);
34257 if(this.labelxs > 0){
34258 label.cls += ' col-xs-' + this.labelxs;
34259 items.cls += ' col-xs-' + (12 - this.labelxs);
34265 cls : 'roo-radio-set',
34269 cls : 'roo-radio-set-input',
34272 value : this.value ? this.value : ''
34279 if(this.weight.length){
34280 cfg.cls += ' roo-radio-' + this.weight;
34284 cfg.cls += ' roo-radio-set-inline';
34288 ['xs','sm','md','lg'].map(function(size){
34289 if (settings[size]) {
34290 cfg.cls += ' col-' + size + '-' + settings[size];
34298 initEvents : function()
34300 this.labelEl = this.el.select('.roo-radio-set-label', true).first();
34301 this.labelEl.setVisibilityMode(Roo.Element.DISPLAY);
34303 if(!this.fieldLabel.length){
34304 this.labelEl.hide();
34307 this.itemsEl = this.el.select('.roo-radio-set-items', true).first();
34308 this.itemsEl.setVisibilityMode(Roo.Element.DISPLAY);
34310 this.indicator = this.indicatorEl();
34312 if(this.indicator){
34313 this.indicator.addClass('invisible');
34316 this.originalValue = this.getValue();
34320 inputEl: function ()
34322 return this.el.select('.roo-radio-set-input', true).first();
34325 getChildContainer : function()
34327 return this.itemsEl;
34330 register : function(item)
34332 this.radioes.push(item);
34336 validate : function()
34338 if(this.getVisibilityEl().hasClass('hidden')){
34344 Roo.each(this.radioes, function(i){
34353 if(this.allowBlank) {
34357 if(this.disabled || valid){
34362 this.markInvalid();
34367 markValid : function()
34369 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34370 this.indicatorEl().removeClass('visible');
34371 this.indicatorEl().addClass('invisible');
34375 if (Roo.bootstrap.version == 3) {
34376 this.el.removeClass([this.invalidClass, this.validClass]);
34377 this.el.addClass(this.validClass);
34379 this.el.removeClass(['is-invalid','is-valid']);
34380 this.el.addClass(['is-valid']);
34382 this.fireEvent('valid', this);
34385 markInvalid : function(msg)
34387 if(this.allowBlank || this.disabled){
34391 if(this.labelEl.isVisible(true) && this.indicatorEl()){
34392 this.indicatorEl().removeClass('invisible');
34393 this.indicatorEl().addClass('visible');
34395 if (Roo.bootstrap.version == 3) {
34396 this.el.removeClass([this.invalidClass, this.validClass]);
34397 this.el.addClass(this.invalidClass);
34399 this.el.removeClass(['is-invalid','is-valid']);
34400 this.el.addClass(['is-invalid']);
34403 this.fireEvent('invalid', this, msg);
34407 setValue : function(v, suppressEvent)
34409 if(this.value === v){
34416 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
34419 Roo.each(this.radioes, function(i){
34421 i.el.removeClass('checked');
34424 Roo.each(this.radioes, function(i){
34426 if(i.value === v || i.value.toString() === v.toString()){
34428 i.el.addClass('checked');
34430 if(suppressEvent !== true){
34431 this.fireEvent('check', this, i);
34442 clearInvalid : function(){
34444 if(!this.el || this.preventMark){
34448 this.el.removeClass([this.invalidClass]);
34450 this.fireEvent('valid', this);
34455 Roo.apply(Roo.bootstrap.RadioSet, {
34459 register : function(set)
34461 this.groups[set.name] = set;
34464 get: function(name)
34466 if (typeof(this.groups[name]) == 'undefined') {
34470 return this.groups[name] ;
34476 * Ext JS Library 1.1.1
34477 * Copyright(c) 2006-2007, Ext JS, LLC.
34479 * Originally Released Under LGPL - original licence link has changed is not relivant.
34482 * <script type="text/javascript">
34487 * @class Roo.bootstrap.SplitBar
34488 * @extends Roo.util.Observable
34489 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
34493 var split = new Roo.bootstrap.SplitBar("elementToDrag", "elementToSize",
34494 Roo.bootstrap.SplitBar.HORIZONTAL, Roo.bootstrap.SplitBar.LEFT);
34495 split.setAdapter(new Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter("container"));
34496 split.minSize = 100;
34497 split.maxSize = 600;
34498 split.animate = true;
34499 split.on('moved', splitterMoved);
34502 * Create a new SplitBar
34503 * @config {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
34504 * @config {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
34505 * @config {Number} orientation (optional) Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34506 * @config {Number} placement (optional) Either Roo.bootstrap.SplitBar.LEFT or Roo.bootstrap.SplitBar.RIGHT for horizontal or
34507 Roo.bootstrap.SplitBar.TOP or Roo.bootstrap.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
34508 position of the SplitBar).
34510 Roo.bootstrap.SplitBar = function(cfg){
34515 // dragElement : elm
34516 // resizingElement: el,
34518 // orientation : Either Roo.bootstrap.SplitBar.HORIZONTAL
34519 // placement : Roo.bootstrap.SplitBar.LEFT ,
34520 // existingProxy ???
34523 this.el = Roo.get(cfg.dragElement, true);
34524 this.el.dom.unselectable = "on";
34526 this.resizingEl = Roo.get(cfg.resizingElement, true);
34530 * The orientation of the split. Either Roo.bootstrap.SplitBar.HORIZONTAL or Roo.bootstrap.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
34531 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
34534 this.orientation = cfg.orientation || Roo.bootstrap.SplitBar.HORIZONTAL;
34537 * The minimum size of the resizing element. (Defaults to 0)
34543 * The maximum size of the resizing element. (Defaults to 2000)
34546 this.maxSize = 2000;
34549 * Whether to animate the transition to the new size
34552 this.animate = false;
34555 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
34558 this.useShim = false;
34563 if(!cfg.existingProxy){
34565 this.proxy = Roo.bootstrap.SplitBar.createProxy(this.orientation);
34567 this.proxy = Roo.get(cfg.existingProxy).dom;
34570 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
34573 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
34576 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
34579 this.dragSpecs = {};
34582 * @private The adapter to use to positon and resize elements
34584 this.adapter = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34585 this.adapter.init(this);
34587 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34589 this.placement = cfg.placement || (this.el.getX() > this.resizingEl.getX() ? Roo.bootstrap.SplitBar.LEFT : Roo.bootstrap.SplitBar.RIGHT);
34590 this.el.addClass("roo-splitbar-h");
34593 this.placement = cfg.placement || (this.el.getY() > this.resizingEl.getY() ? Roo.bootstrap.SplitBar.TOP : Roo.bootstrap.SplitBar.BOTTOM);
34594 this.el.addClass("roo-splitbar-v");
34600 * Fires when the splitter is moved (alias for {@link #event-moved})
34601 * @param {Roo.bootstrap.SplitBar} this
34602 * @param {Number} newSize the new width or height
34607 * Fires when the splitter is moved
34608 * @param {Roo.bootstrap.SplitBar} this
34609 * @param {Number} newSize the new width or height
34613 * @event beforeresize
34614 * Fires before the splitter is dragged
34615 * @param {Roo.bootstrap.SplitBar} this
34617 "beforeresize" : true,
34619 "beforeapply" : true
34622 Roo.util.Observable.call(this);
34625 Roo.extend(Roo.bootstrap.SplitBar, Roo.util.Observable, {
34626 onStartProxyDrag : function(x, y){
34627 this.fireEvent("beforeresize", this);
34629 var o = Roo.DomHelper.insertFirst(document.body, {cls: "roo-drag-overlay", html: " "}, true);
34631 o.enableDisplayMode("block");
34632 // all splitbars share the same overlay
34633 Roo.bootstrap.SplitBar.prototype.overlay = o;
34635 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
34636 this.overlay.show();
34637 Roo.get(this.proxy).setDisplayed("block");
34638 var size = this.adapter.getElementSize(this);
34639 this.activeMinSize = this.getMinimumSize();;
34640 this.activeMaxSize = this.getMaximumSize();;
34641 var c1 = size - this.activeMinSize;
34642 var c2 = Math.max(this.activeMaxSize - size, 0);
34643 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34644 this.dd.resetConstraints();
34645 this.dd.setXConstraint(
34646 this.placement == Roo.bootstrap.SplitBar.LEFT ? c1 : c2,
34647 this.placement == Roo.bootstrap.SplitBar.LEFT ? c2 : c1
34649 this.dd.setYConstraint(0, 0);
34651 this.dd.resetConstraints();
34652 this.dd.setXConstraint(0, 0);
34653 this.dd.setYConstraint(
34654 this.placement == Roo.bootstrap.SplitBar.TOP ? c1 : c2,
34655 this.placement == Roo.bootstrap.SplitBar.TOP ? c2 : c1
34658 this.dragSpecs.startSize = size;
34659 this.dragSpecs.startPoint = [x, y];
34660 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
34664 * @private Called after the drag operation by the DDProxy
34666 onEndProxyDrag : function(e){
34667 Roo.get(this.proxy).setDisplayed(false);
34668 var endPoint = Roo.lib.Event.getXY(e);
34670 this.overlay.hide();
34673 if(this.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34674 newSize = this.dragSpecs.startSize +
34675 (this.placement == Roo.bootstrap.SplitBar.LEFT ?
34676 endPoint[0] - this.dragSpecs.startPoint[0] :
34677 this.dragSpecs.startPoint[0] - endPoint[0]
34680 newSize = this.dragSpecs.startSize +
34681 (this.placement == Roo.bootstrap.SplitBar.TOP ?
34682 endPoint[1] - this.dragSpecs.startPoint[1] :
34683 this.dragSpecs.startPoint[1] - endPoint[1]
34686 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
34687 if(newSize != this.dragSpecs.startSize){
34688 if(this.fireEvent('beforeapply', this, newSize) !== false){
34689 this.adapter.setElementSize(this, newSize);
34690 this.fireEvent("moved", this, newSize);
34691 this.fireEvent("resize", this, newSize);
34697 * Get the adapter this SplitBar uses
34698 * @return The adapter object
34700 getAdapter : function(){
34701 return this.adapter;
34705 * Set the adapter this SplitBar uses
34706 * @param {Object} adapter A SplitBar adapter object
34708 setAdapter : function(adapter){
34709 this.adapter = adapter;
34710 this.adapter.init(this);
34714 * Gets the minimum size for the resizing element
34715 * @return {Number} The minimum size
34717 getMinimumSize : function(){
34718 return this.minSize;
34722 * Sets the minimum size for the resizing element
34723 * @param {Number} minSize The minimum size
34725 setMinimumSize : function(minSize){
34726 this.minSize = minSize;
34730 * Gets the maximum size for the resizing element
34731 * @return {Number} The maximum size
34733 getMaximumSize : function(){
34734 return this.maxSize;
34738 * Sets the maximum size for the resizing element
34739 * @param {Number} maxSize The maximum size
34741 setMaximumSize : function(maxSize){
34742 this.maxSize = maxSize;
34746 * Sets the initialize size for the resizing element
34747 * @param {Number} size The initial size
34749 setCurrentSize : function(size){
34750 var oldAnimate = this.animate;
34751 this.animate = false;
34752 this.adapter.setElementSize(this, size);
34753 this.animate = oldAnimate;
34757 * Destroy this splitbar.
34758 * @param {Boolean} removeEl True to remove the element
34760 destroy : function(removeEl){
34762 this.shim.remove();
34765 this.proxy.parentNode.removeChild(this.proxy);
34773 * @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.
34775 Roo.bootstrap.SplitBar.createProxy = function(dir){
34776 var proxy = new Roo.Element(document.createElement("div"));
34777 proxy.unselectable();
34778 var cls = 'roo-splitbar-proxy';
34779 proxy.addClass(cls + ' ' + (dir == Roo.bootstrap.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
34780 document.body.appendChild(proxy.dom);
34785 * @class Roo.bootstrap.SplitBar.BasicLayoutAdapter
34786 * Default Adapter. It assumes the splitter and resizing element are not positioned
34787 * elements and only gets/sets the width of the element. Generally used for table based layouts.
34789 Roo.bootstrap.SplitBar.BasicLayoutAdapter = function(){
34792 Roo.bootstrap.SplitBar.BasicLayoutAdapter.prototype = {
34793 // do nothing for now
34794 init : function(s){
34798 * Called before drag operations to get the current size of the resizing element.
34799 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34801 getElementSize : function(s){
34802 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34803 return s.resizingEl.getWidth();
34805 return s.resizingEl.getHeight();
34810 * Called after drag operations to set the size of the resizing element.
34811 * @param {Roo.bootstrap.SplitBar} s The SplitBar using this adapter
34812 * @param {Number} newSize The new size to set
34813 * @param {Function} onComplete A function to be invoked when resizing is complete
34815 setElementSize : function(s, newSize, onComplete){
34816 if(s.orientation == Roo.bootstrap.SplitBar.HORIZONTAL){
34818 s.resizingEl.setWidth(newSize);
34820 onComplete(s, newSize);
34823 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
34828 s.resizingEl.setHeight(newSize);
34830 onComplete(s, newSize);
34833 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
34840 *@class Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter
34841 * @extends Roo.bootstrap.SplitBar.BasicLayoutAdapter
34842 * Adapter that moves the splitter element to align with the resized sizing element.
34843 * Used with an absolute positioned SplitBar.
34844 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
34845 * document.body, make sure you assign an id to the body element.
34847 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter = function(container){
34848 this.basic = new Roo.bootstrap.SplitBar.BasicLayoutAdapter();
34849 this.container = Roo.get(container);
34852 Roo.bootstrap.SplitBar.AbsoluteLayoutAdapter.prototype = {
34853 init : function(s){
34854 this.basic.init(s);
34857 getElementSize : function(s){
34858 return this.basic.getElementSize(s);
34861 setElementSize : function(s, newSize, onComplete){
34862 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
34865 moveSplitter : function(s){
34866 var yes = Roo.bootstrap.SplitBar;
34867 switch(s.placement){
34869 s.el.setX(s.resizingEl.getRight());
34872 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
34875 s.el.setY(s.resizingEl.getBottom());
34878 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
34885 * Orientation constant - Create a vertical SplitBar
34889 Roo.bootstrap.SplitBar.VERTICAL = 1;
34892 * Orientation constant - Create a horizontal SplitBar
34896 Roo.bootstrap.SplitBar.HORIZONTAL = 2;
34899 * Placement constant - The resizing element is to the left of the splitter element
34903 Roo.bootstrap.SplitBar.LEFT = 1;
34906 * Placement constant - The resizing element is to the right of the splitter element
34910 Roo.bootstrap.SplitBar.RIGHT = 2;
34913 * Placement constant - The resizing element is positioned above the splitter element
34917 Roo.bootstrap.SplitBar.TOP = 3;
34920 * Placement constant - The resizing element is positioned under splitter element
34924 Roo.bootstrap.SplitBar.BOTTOM = 4;
34925 Roo.namespace("Roo.bootstrap.layout");/*
34927 * Ext JS Library 1.1.1
34928 * Copyright(c) 2006-2007, Ext JS, LLC.
34930 * Originally Released Under LGPL - original licence link has changed is not relivant.
34933 * <script type="text/javascript">
34937 * @class Roo.bootstrap.layout.Manager
34938 * @extends Roo.bootstrap.Component
34939 * Base class for layout managers.
34941 Roo.bootstrap.layout.Manager = function(config)
34943 Roo.bootstrap.layout.Manager.superclass.constructor.call(this,config);
34949 /** false to disable window resize monitoring @type Boolean */
34950 this.monitorWindowResize = true;
34955 * Fires when a layout is performed.
34956 * @param {Roo.LayoutManager} this
34960 * @event regionresized
34961 * Fires when the user resizes a region.
34962 * @param {Roo.LayoutRegion} region The resized region
34963 * @param {Number} newSize The new size (width for east/west, height for north/south)
34965 "regionresized" : true,
34967 * @event regioncollapsed
34968 * Fires when a region is collapsed.
34969 * @param {Roo.LayoutRegion} region The collapsed region
34971 "regioncollapsed" : true,
34973 * @event regionexpanded
34974 * Fires when a region is expanded.
34975 * @param {Roo.LayoutRegion} region The expanded region
34977 "regionexpanded" : true
34979 this.updating = false;
34982 this.el = Roo.get(config.el);
34988 Roo.extend(Roo.bootstrap.layout.Manager, Roo.bootstrap.Component, {
34993 monitorWindowResize : true,
34999 onRender : function(ct, position)
35002 this.el = Roo.get(ct);
35005 //this.fireEvent('render',this);
35009 initEvents: function()
35013 // ie scrollbar fix
35014 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
35015 document.body.scroll = "no";
35016 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
35017 this.el.position('relative');
35019 this.id = this.el.id;
35020 this.el.addClass("roo-layout-container");
35021 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
35022 if(this.el.dom != document.body ) {
35023 this.el.on('resize', this.layout,this);
35024 this.el.on('show', this.layout,this);
35030 * Returns true if this layout is currently being updated
35031 * @return {Boolean}
35033 isUpdating : function(){
35034 return this.updating;
35038 * Suspend the LayoutManager from doing auto-layouts while
35039 * making multiple add or remove calls
35041 beginUpdate : function(){
35042 this.updating = true;
35046 * Restore auto-layouts and optionally disable the manager from performing a layout
35047 * @param {Boolean} noLayout true to disable a layout update
35049 endUpdate : function(noLayout){
35050 this.updating = false;
35056 layout: function(){
35060 onRegionResized : function(region, newSize){
35061 this.fireEvent("regionresized", region, newSize);
35065 onRegionCollapsed : function(region){
35066 this.fireEvent("regioncollapsed", region);
35069 onRegionExpanded : function(region){
35070 this.fireEvent("regionexpanded", region);
35074 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
35075 * performs box-model adjustments.
35076 * @return {Object} The size as an object {width: (the width), height: (the height)}
35078 getViewSize : function()
35081 if(this.el.dom != document.body){
35082 size = this.el.getSize();
35084 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
35086 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
35087 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
35092 * Returns the Element this layout is bound to.
35093 * @return {Roo.Element}
35095 getEl : function(){
35100 * Returns the specified region.
35101 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
35102 * @return {Roo.LayoutRegion}
35104 getRegion : function(target){
35105 return this.regions[target.toLowerCase()];
35108 onWindowResize : function(){
35109 if(this.monitorWindowResize){
35116 * Ext JS Library 1.1.1
35117 * Copyright(c) 2006-2007, Ext JS, LLC.
35119 * Originally Released Under LGPL - original licence link has changed is not relivant.
35122 * <script type="text/javascript">
35125 * @class Roo.bootstrap.layout.Border
35126 * @extends Roo.bootstrap.layout.Manager
35127 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
35128 * please see: examples/bootstrap/nested.html<br><br>
35130 <b>The container the layout is rendered into can be either the body element or any other element.
35131 If it is not the body element, the container needs to either be an absolute positioned element,
35132 or you will need to add "position:relative" to the css of the container. You will also need to specify
35133 the container size if it is not the body element.</b>
35136 * Create a new Border
35137 * @param {Object} config Configuration options
35139 Roo.bootstrap.layout.Border = function(config){
35140 config = config || {};
35141 Roo.bootstrap.layout.Border.superclass.constructor.call(this, config);
35145 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35146 if(config[region]){
35147 config[region].region = region;
35148 this.addRegion(config[region]);
35154 Roo.bootstrap.layout.Border.regions = ["north","south","east","west","center"];
35156 Roo.extend(Roo.bootstrap.layout.Border, Roo.bootstrap.layout.Manager, {
35158 parent : false, // this might point to a 'nest' or a ???
35161 * Creates and adds a new region if it doesn't already exist.
35162 * @param {String} target The target region key (north, south, east, west or center).
35163 * @param {Object} config The regions config object
35164 * @return {BorderLayoutRegion} The new region
35166 addRegion : function(config)
35168 if(!this.regions[config.region]){
35169 var r = this.factory(config);
35170 this.bindRegion(r);
35172 return this.regions[config.region];
35176 bindRegion : function(r){
35177 this.regions[r.config.region] = r;
35179 r.on("visibilitychange", this.layout, this);
35180 r.on("paneladded", this.layout, this);
35181 r.on("panelremoved", this.layout, this);
35182 r.on("invalidated", this.layout, this);
35183 r.on("resized", this.onRegionResized, this);
35184 r.on("collapsed", this.onRegionCollapsed, this);
35185 r.on("expanded", this.onRegionExpanded, this);
35189 * Performs a layout update.
35191 layout : function()
35193 if(this.updating) {
35197 // render all the rebions if they have not been done alreayd?
35198 Roo.each(Roo.bootstrap.layout.Border.regions, function(region) {
35199 if(this.regions[region] && !this.regions[region].bodyEl){
35200 this.regions[region].onRender(this.el)
35204 var size = this.getViewSize();
35205 var w = size.width;
35206 var h = size.height;
35211 //var x = 0, y = 0;
35213 var rs = this.regions;
35214 var north = rs["north"];
35215 var south = rs["south"];
35216 var west = rs["west"];
35217 var east = rs["east"];
35218 var center = rs["center"];
35219 //if(this.hideOnLayout){ // not supported anymore
35220 //c.el.setStyle("display", "none");
35222 if(north && north.isVisible()){
35223 var b = north.getBox();
35224 var m = north.getMargins();
35225 b.width = w - (m.left+m.right);
35228 centerY = b.height + b.y + m.bottom;
35229 centerH -= centerY;
35230 north.updateBox(this.safeBox(b));
35232 if(south && south.isVisible()){
35233 var b = south.getBox();
35234 var m = south.getMargins();
35235 b.width = w - (m.left+m.right);
35237 var totalHeight = (b.height + m.top + m.bottom);
35238 b.y = h - totalHeight + m.top;
35239 centerH -= totalHeight;
35240 south.updateBox(this.safeBox(b));
35242 if(west && west.isVisible()){
35243 var b = west.getBox();
35244 var m = west.getMargins();
35245 b.height = centerH - (m.top+m.bottom);
35247 b.y = centerY + m.top;
35248 var totalWidth = (b.width + m.left + m.right);
35249 centerX += totalWidth;
35250 centerW -= totalWidth;
35251 west.updateBox(this.safeBox(b));
35253 if(east && east.isVisible()){
35254 var b = east.getBox();
35255 var m = east.getMargins();
35256 b.height = centerH - (m.top+m.bottom);
35257 var totalWidth = (b.width + m.left + m.right);
35258 b.x = w - totalWidth + m.left;
35259 b.y = centerY + m.top;
35260 centerW -= totalWidth;
35261 east.updateBox(this.safeBox(b));
35264 var m = center.getMargins();
35266 x: centerX + m.left,
35267 y: centerY + m.top,
35268 width: centerW - (m.left+m.right),
35269 height: centerH - (m.top+m.bottom)
35271 //if(this.hideOnLayout){
35272 //center.el.setStyle("display", "block");
35274 center.updateBox(this.safeBox(centerBox));
35277 this.fireEvent("layout", this);
35281 safeBox : function(box){
35282 box.width = Math.max(0, box.width);
35283 box.height = Math.max(0, box.height);
35288 * Adds a ContentPanel (or subclass) to this layout.
35289 * @param {String} target The target region key (north, south, east, west or center).
35290 * @param {Roo.ContentPanel} panel The panel to add
35291 * @return {Roo.ContentPanel} The added panel
35293 add : function(target, panel){
35295 target = target.toLowerCase();
35296 return this.regions[target].add(panel);
35300 * Remove a ContentPanel (or subclass) to this layout.
35301 * @param {String} target The target region key (north, south, east, west or center).
35302 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
35303 * @return {Roo.ContentPanel} The removed panel
35305 remove : function(target, panel){
35306 target = target.toLowerCase();
35307 return this.regions[target].remove(panel);
35311 * Searches all regions for a panel with the specified id
35312 * @param {String} panelId
35313 * @return {Roo.ContentPanel} The panel or null if it wasn't found
35315 findPanel : function(panelId){
35316 var rs = this.regions;
35317 for(var target in rs){
35318 if(typeof rs[target] != "function"){
35319 var p = rs[target].getPanel(panelId);
35329 * Searches all regions for a panel with the specified id and activates (shows) it.
35330 * @param {String/ContentPanel} panelId The panels id or the panel itself
35331 * @return {Roo.ContentPanel} The shown panel or null
35333 showPanel : function(panelId) {
35334 var rs = this.regions;
35335 for(var target in rs){
35336 var r = rs[target];
35337 if(typeof r != "function"){
35338 if(r.hasPanel(panelId)){
35339 return r.showPanel(panelId);
35347 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
35348 * @param {Roo.state.Provider} provider (optional) An alternate state provider
35351 restoreState : function(provider){
35353 provider = Roo.state.Manager;
35355 var sm = new Roo.LayoutStateManager();
35356 sm.init(this, provider);
35362 * Adds a xtype elements to the layout.
35366 xtype : 'ContentPanel',
35373 xtype : 'NestedLayoutPanel',
35379 items : [ ... list of content panels or nested layout panels.. ]
35383 * @param {Object} cfg Xtype definition of item to add.
35385 addxtype : function(cfg)
35387 // basically accepts a pannel...
35388 // can accept a layout region..!?!?
35389 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
35392 // theory? children can only be panels??
35394 //if (!cfg.xtype.match(/Panel$/)) {
35399 if (typeof(cfg.region) == 'undefined') {
35400 Roo.log("Failed to add Panel, region was not set");
35404 var region = cfg.region;
35410 xitems = cfg.items;
35415 if ( region == 'center') {
35416 Roo.log("Center: " + cfg.title);
35422 case 'Content': // ContentPanel (el, cfg)
35423 case 'Scroll': // ContentPanel (el, cfg)
35425 cfg.autoCreate = cfg.autoCreate || true;
35426 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35428 // var el = this.el.createChild();
35429 // ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
35432 this.add(region, ret);
35436 case 'TreePanel': // our new panel!
35437 cfg.el = this.el.createChild();
35438 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35439 this.add(region, ret);
35444 // create a new Layout (which is a Border Layout...
35446 var clayout = cfg.layout;
35447 clayout.el = this.el.createChild();
35448 clayout.items = clayout.items || [];
35452 // replace this exitems with the clayout ones..
35453 xitems = clayout.items;
35455 // force background off if it's in center...
35456 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
35457 cfg.background = false;
35459 cfg.layout = new Roo.bootstrap.layout.Border(clayout);
35462 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35463 //console.log('adding nested layout panel ' + cfg.toSource());
35464 this.add(region, ret);
35465 nb = {}; /// find first...
35470 // needs grid and region
35472 //var el = this.getRegion(region).el.createChild();
35474 *var el = this.el.createChild();
35475 // create the grid first...
35476 cfg.grid.container = el;
35477 cfg.grid = new cfg.grid.xns[cfg.grid.xtype](cfg.grid);
35480 if (region == 'center' && this.active ) {
35481 cfg.background = false;
35484 ret = new cfg.xns[cfg.xtype](cfg); // new panel!!!!!
35486 this.add(region, ret);
35488 if (cfg.background) {
35489 // render grid on panel activation (if panel background)
35490 ret.on('activate', function(gp) {
35491 if (!gp.grid.rendered) {
35492 // gp.grid.render(el);
35496 // cfg.grid.render(el);
35502 case 'Border': // it can get called on it'self... - might need to check if this is fixed?
35503 // it was the old xcomponent building that caused this before.
35504 // espeically if border is the top element in the tree.
35514 if (typeof(Roo[cfg.xtype]) != 'undefined') {
35516 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
35517 this.add(region, ret);
35521 throw "Can not add '" + cfg.xtype + "' to Border";
35527 this.beginUpdate();
35531 Roo.each(xitems, function(i) {
35532 region = nb && i.region ? i.region : false;
35534 var add = ret.addxtype(i);
35537 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
35538 if (!i.background) {
35539 abn[region] = nb[region] ;
35546 // make the last non-background panel active..
35547 //if (nb) { Roo.log(abn); }
35550 for(var r in abn) {
35551 region = this.getRegion(r);
35553 // tried using nb[r], but it does not work..
35555 region.showPanel(abn[r]);
35566 factory : function(cfg)
35569 var validRegions = Roo.bootstrap.layout.Border.regions;
35571 var target = cfg.region;
35574 var r = Roo.bootstrap.layout;
35578 return new r.North(cfg);
35580 return new r.South(cfg);
35582 return new r.East(cfg);
35584 return new r.West(cfg);
35586 return new r.Center(cfg);
35588 throw 'Layout region "'+target+'" not supported.';
35595 * Ext JS Library 1.1.1
35596 * Copyright(c) 2006-2007, Ext JS, LLC.
35598 * Originally Released Under LGPL - original licence link has changed is not relivant.
35601 * <script type="text/javascript">
35605 * @class Roo.bootstrap.layout.Basic
35606 * @extends Roo.util.Observable
35607 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
35608 * and does not have a titlebar, tabs or any other features. All it does is size and position
35609 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
35610 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35611 * @cfg {string} region the region that it inhabits..
35612 * @cfg {bool} skipConfig skip config?
35616 Roo.bootstrap.layout.Basic = function(config){
35618 this.mgr = config.mgr;
35620 this.position = config.region;
35622 var skipConfig = config.skipConfig;
35626 * @scope Roo.BasicLayoutRegion
35630 * @event beforeremove
35631 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
35632 * @param {Roo.LayoutRegion} this
35633 * @param {Roo.ContentPanel} panel The panel
35634 * @param {Object} e The cancel event object
35636 "beforeremove" : true,
35638 * @event invalidated
35639 * Fires when the layout for this region is changed.
35640 * @param {Roo.LayoutRegion} this
35642 "invalidated" : true,
35644 * @event visibilitychange
35645 * Fires when this region is shown or hidden
35646 * @param {Roo.LayoutRegion} this
35647 * @param {Boolean} visibility true or false
35649 "visibilitychange" : true,
35651 * @event paneladded
35652 * Fires when a panel is added.
35653 * @param {Roo.LayoutRegion} this
35654 * @param {Roo.ContentPanel} panel The panel
35656 "paneladded" : true,
35658 * @event panelremoved
35659 * Fires when a panel is removed.
35660 * @param {Roo.LayoutRegion} this
35661 * @param {Roo.ContentPanel} panel The panel
35663 "panelremoved" : true,
35665 * @event beforecollapse
35666 * Fires when this region before collapse.
35667 * @param {Roo.LayoutRegion} this
35669 "beforecollapse" : true,
35672 * Fires when this region is collapsed.
35673 * @param {Roo.LayoutRegion} this
35675 "collapsed" : true,
35678 * Fires when this region is expanded.
35679 * @param {Roo.LayoutRegion} this
35684 * Fires when this region is slid into view.
35685 * @param {Roo.LayoutRegion} this
35687 "slideshow" : true,
35690 * Fires when this region slides out of view.
35691 * @param {Roo.LayoutRegion} this
35693 "slidehide" : true,
35695 * @event panelactivated
35696 * Fires when a panel is activated.
35697 * @param {Roo.LayoutRegion} this
35698 * @param {Roo.ContentPanel} panel The activated panel
35700 "panelactivated" : true,
35703 * Fires when the user resizes this region.
35704 * @param {Roo.LayoutRegion} this
35705 * @param {Number} newSize The new size (width for east/west, height for north/south)
35709 /** A collection of panels in this region. @type Roo.util.MixedCollection */
35710 this.panels = new Roo.util.MixedCollection();
35711 this.panels.getKey = this.getPanelId.createDelegate(this);
35713 this.activePanel = null;
35714 // ensure listeners are added...
35716 if (config.listeners || config.events) {
35717 Roo.bootstrap.layout.Basic.superclass.constructor.call(this, {
35718 listeners : config.listeners || {},
35719 events : config.events || {}
35723 if(skipConfig !== true){
35724 this.applyConfig(config);
35728 Roo.extend(Roo.bootstrap.layout.Basic, Roo.util.Observable,
35730 getPanelId : function(p){
35734 applyConfig : function(config){
35735 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
35736 this.config = config;
35741 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
35742 * the width, for horizontal (north, south) the height.
35743 * @param {Number} newSize The new width or height
35745 resizeTo : function(newSize){
35746 var el = this.el ? this.el :
35747 (this.activePanel ? this.activePanel.getEl() : null);
35749 switch(this.position){
35752 el.setWidth(newSize);
35753 this.fireEvent("resized", this, newSize);
35757 el.setHeight(newSize);
35758 this.fireEvent("resized", this, newSize);
35764 getBox : function(){
35765 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
35768 getMargins : function(){
35769 return this.margins;
35772 updateBox : function(box){
35774 var el = this.activePanel.getEl();
35775 el.dom.style.left = box.x + "px";
35776 el.dom.style.top = box.y + "px";
35777 this.activePanel.setSize(box.width, box.height);
35781 * Returns the container element for this region.
35782 * @return {Roo.Element}
35784 getEl : function(){
35785 return this.activePanel;
35789 * Returns true if this region is currently visible.
35790 * @return {Boolean}
35792 isVisible : function(){
35793 return this.activePanel ? true : false;
35796 setActivePanel : function(panel){
35797 panel = this.getPanel(panel);
35798 if(this.activePanel && this.activePanel != panel){
35799 this.activePanel.setActiveState(false);
35800 this.activePanel.getEl().setLeftTop(-10000,-10000);
35802 this.activePanel = panel;
35803 panel.setActiveState(true);
35805 panel.setSize(this.box.width, this.box.height);
35807 this.fireEvent("panelactivated", this, panel);
35808 this.fireEvent("invalidated");
35812 * Show the specified panel.
35813 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
35814 * @return {Roo.ContentPanel} The shown panel or null
35816 showPanel : function(panel){
35817 panel = this.getPanel(panel);
35819 this.setActivePanel(panel);
35825 * Get the active panel for this region.
35826 * @return {Roo.ContentPanel} The active panel or null
35828 getActivePanel : function(){
35829 return this.activePanel;
35833 * Add the passed ContentPanel(s)
35834 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
35835 * @return {Roo.ContentPanel} The panel added (if only one was added)
35837 add : function(panel){
35838 if(arguments.length > 1){
35839 for(var i = 0, len = arguments.length; i < len; i++) {
35840 this.add(arguments[i]);
35844 if(this.hasPanel(panel)){
35845 this.showPanel(panel);
35848 var el = panel.getEl();
35849 if(el.dom.parentNode != this.mgr.el.dom){
35850 this.mgr.el.dom.appendChild(el.dom);
35852 if(panel.setRegion){
35853 panel.setRegion(this);
35855 this.panels.add(panel);
35856 el.setStyle("position", "absolute");
35857 if(!panel.background){
35858 this.setActivePanel(panel);
35859 if(this.config.initialSize && this.panels.getCount()==1){
35860 this.resizeTo(this.config.initialSize);
35863 this.fireEvent("paneladded", this, panel);
35868 * Returns true if the panel is in this region.
35869 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35870 * @return {Boolean}
35872 hasPanel : function(panel){
35873 if(typeof panel == "object"){ // must be panel obj
35874 panel = panel.getId();
35876 return this.getPanel(panel) ? true : false;
35880 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
35881 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35882 * @param {Boolean} preservePanel Overrides the config preservePanel option
35883 * @return {Roo.ContentPanel} The panel that was removed
35885 remove : function(panel, preservePanel){
35886 panel = this.getPanel(panel);
35891 this.fireEvent("beforeremove", this, panel, e);
35892 if(e.cancel === true){
35895 var panelId = panel.getId();
35896 this.panels.removeKey(panelId);
35901 * Returns the panel specified or null if it's not in this region.
35902 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
35903 * @return {Roo.ContentPanel}
35905 getPanel : function(id){
35906 if(typeof id == "object"){ // must be panel obj
35909 return this.panels.get(id);
35913 * Returns this regions position (north/south/east/west/center).
35916 getPosition: function(){
35917 return this.position;
35921 * Ext JS Library 1.1.1
35922 * Copyright(c) 2006-2007, Ext JS, LLC.
35924 * Originally Released Under LGPL - original licence link has changed is not relivant.
35927 * <script type="text/javascript">
35931 * @class Roo.bootstrap.layout.Region
35932 * @extends Roo.bootstrap.layout.Basic
35933 * This class represents a region in a layout manager.
35935 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
35936 * @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})
35937 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
35938 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
35939 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
35940 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
35941 * @cfg {String} title The title for the region (overrides panel titles)
35942 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
35943 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
35944 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
35945 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
35946 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
35947 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
35948 * the space available, similar to FireFox 1.5 tabs (defaults to false)
35949 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
35950 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
35951 * @cfg {String} overflow (hidden|visible) if you have menus in the region, then you need to set this to visible.
35953 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
35954 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
35955 * @cfg {Boolean} disableTabTips True to disable tab tooltips
35956 * @cfg {Number} width For East/West panels
35957 * @cfg {Number} height For North/South panels
35958 * @cfg {Boolean} split To show the splitter
35959 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
35961 * @cfg {string} cls Extra CSS classes to add to region
35963 * @cfg {Roo.bootstrap.layout.Manager} mgr The manager
35964 * @cfg {string} region the region that it inhabits..
35967 * @xxxcfg {Boolean} collapsible DISABLED False to disable collapsing (defaults to true)
35968 * @xxxcfg {Boolean} collapsed DISABLED True to set the initial display to collapsed (defaults to false)
35970 * @xxxcfg {String} collapsedTitle DISABLED Optional string message to display in the collapsed block of a north or south region
35971 * @xxxxcfg {Boolean} floatable DISABLED False to disable floating (defaults to true)
35972 * @xxxxcfg {Boolean} showPin True to show a pin button NOT SUPPORTED YET
35974 Roo.bootstrap.layout.Region = function(config)
35976 this.applyConfig(config);
35978 var mgr = config.mgr;
35979 var pos = config.region;
35980 config.skipConfig = true;
35981 Roo.bootstrap.layout.Region.superclass.constructor.call(this, config);
35984 this.onRender(mgr.el);
35987 this.visible = true;
35988 this.collapsed = false;
35989 this.unrendered_panels = [];
35992 Roo.extend(Roo.bootstrap.layout.Region, Roo.bootstrap.layout.Basic, {
35994 position: '', // set by wrapper (eg. north/south etc..)
35995 unrendered_panels : null, // unrendered panels.
35997 tabPosition : false,
35999 mgr: false, // points to 'Border'
36002 createBody : function(){
36003 /** This region's body element
36004 * @type Roo.Element */
36005 this.bodyEl = this.el.createChild({
36007 cls: "roo-layout-panel-body tab-content" // bootstrap added...
36011 onRender: function(ctr, pos)
36013 var dh = Roo.DomHelper;
36014 /** This region's container element
36015 * @type Roo.Element */
36016 this.el = dh.append(ctr.dom, {
36018 cls: (this.config.cls || '') + " roo-layout-region roo-layout-panel roo-layout-panel-" + this.position
36020 /** This region's title element
36021 * @type Roo.Element */
36023 this.titleEl = dh.append(this.el.dom, {
36025 unselectable: "on",
36026 cls: "roo-unselectable roo-layout-panel-hd breadcrumb roo-layout-title-" + this.position,
36028 {tag: "span", cls: "roo-unselectable roo-layout-panel-hd-text", unselectable: "on", html: " "},
36029 {tag: "div", cls: "roo-unselectable roo-layout-panel-hd-tools", unselectable: "on"}
36033 this.titleEl.enableDisplayMode();
36034 /** This region's title text element
36035 * @type HTMLElement */
36036 this.titleTextEl = this.titleEl.dom.firstChild;
36037 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
36039 this.closeBtn = this.createTool(this.tools.dom, "roo-layout-close");
36040 this.closeBtn.enableDisplayMode();
36041 this.closeBtn.on("click", this.closeClicked, this);
36042 this.closeBtn.hide();
36044 this.createBody(this.config);
36045 if(this.config.hideWhenEmpty){
36047 this.on("paneladded", this.validateVisibility, this);
36048 this.on("panelremoved", this.validateVisibility, this);
36050 if(this.autoScroll){
36051 this.bodyEl.setStyle("overflow", "auto");
36053 this.bodyEl.setStyle("overflow", this.config.overflow || 'hidden');
36055 //if(c.titlebar !== false){
36056 if((!this.config.titlebar && !this.config.title) || this.config.titlebar === false){
36057 this.titleEl.hide();
36059 this.titleEl.show();
36060 if(this.config.title){
36061 this.titleTextEl.innerHTML = this.config.title;
36065 if(this.config.collapsed){
36066 this.collapse(true);
36068 if(this.config.hidden){
36072 if (this.unrendered_panels && this.unrendered_panels.length) {
36073 for (var i =0;i< this.unrendered_panels.length; i++) {
36074 this.add(this.unrendered_panels[i]);
36076 this.unrendered_panels = null;
36082 applyConfig : function(c)
36085 *if(c.collapsible && this.position != "center" && !this.collapsedEl){
36086 var dh = Roo.DomHelper;
36087 if(c.titlebar !== false){
36088 this.collapseBtn = this.createTool(this.tools.dom, "roo-layout-collapse-"+this.position);
36089 this.collapseBtn.on("click", this.collapse, this);
36090 this.collapseBtn.enableDisplayMode();
36092 if(c.showPin === true || this.showPin){
36093 this.stickBtn = this.createTool(this.tools.dom, "roo-layout-stick");
36094 this.stickBtn.enableDisplayMode();
36095 this.stickBtn.on("click", this.expand, this);
36096 this.stickBtn.hide();
36101 /** This region's collapsed element
36102 * @type Roo.Element */
36105 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
36106 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
36109 if(c.floatable !== false){
36110 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
36111 this.collapsedEl.on("click", this.collapseClick, this);
36114 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
36115 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
36116 id: "message", unselectable: "on", style:{"float":"left"}});
36117 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
36119 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
36120 this.expandBtn.on("click", this.expand, this);
36124 if(this.collapseBtn){
36125 this.collapseBtn.setVisible(c.collapsible == true);
36128 this.cmargins = c.cmargins || this.cmargins ||
36129 (this.position == "west" || this.position == "east" ?
36130 {top: 0, left: 2, right:2, bottom: 0} :
36131 {top: 2, left: 0, right:0, bottom: 2});
36133 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
36136 this.tabPosition = [ 'top','bottom', 'west'].indexOf(c.tabPosition) > -1 ? c.tabPosition : "top";
36138 this.autoScroll = c.autoScroll || false;
36143 this.duration = c.duration || .30;
36144 this.slideDuration = c.slideDuration || .45;
36149 * Returns true if this region is currently visible.
36150 * @return {Boolean}
36152 isVisible : function(){
36153 return this.visible;
36157 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
36158 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
36160 //setCollapsedTitle : function(title){
36161 // title = title || " ";
36162 // if(this.collapsedTitleTextEl){
36163 // this.collapsedTitleTextEl.innerHTML = title;
36167 getBox : function(){
36169 // if(!this.collapsed){
36170 b = this.el.getBox(false, true);
36172 // b = this.collapsedEl.getBox(false, true);
36177 getMargins : function(){
36178 return this.margins;
36179 //return this.collapsed ? this.cmargins : this.margins;
36182 highlight : function(){
36183 this.el.addClass("x-layout-panel-dragover");
36186 unhighlight : function(){
36187 this.el.removeClass("x-layout-panel-dragover");
36190 updateBox : function(box)
36192 if (!this.bodyEl) {
36193 return; // not rendered yet..
36197 if(!this.collapsed){
36198 this.el.dom.style.left = box.x + "px";
36199 this.el.dom.style.top = box.y + "px";
36200 this.updateBody(box.width, box.height);
36202 this.collapsedEl.dom.style.left = box.x + "px";
36203 this.collapsedEl.dom.style.top = box.y + "px";
36204 this.collapsedEl.setSize(box.width, box.height);
36207 this.tabs.autoSizeTabs();
36211 updateBody : function(w, h)
36214 this.el.setWidth(w);
36215 w -= this.el.getBorderWidth("rl");
36216 if(this.config.adjustments){
36217 w += this.config.adjustments[0];
36220 if(h !== null && h > 0){
36221 this.el.setHeight(h);
36222 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
36223 h -= this.el.getBorderWidth("tb");
36224 if(this.config.adjustments){
36225 h += this.config.adjustments[1];
36227 this.bodyEl.setHeight(h);
36229 h = this.tabs.syncHeight(h);
36232 if(this.panelSize){
36233 w = w !== null ? w : this.panelSize.width;
36234 h = h !== null ? h : this.panelSize.height;
36236 if(this.activePanel){
36237 var el = this.activePanel.getEl();
36238 w = w !== null ? w : el.getWidth();
36239 h = h !== null ? h : el.getHeight();
36240 this.panelSize = {width: w, height: h};
36241 this.activePanel.setSize(w, h);
36243 if(Roo.isIE && this.tabs){
36244 this.tabs.el.repaint();
36249 * Returns the container element for this region.
36250 * @return {Roo.Element}
36252 getEl : function(){
36257 * Hides this region.
36260 //if(!this.collapsed){
36261 this.el.dom.style.left = "-2000px";
36264 // this.collapsedEl.dom.style.left = "-2000px";
36265 // this.collapsedEl.hide();
36267 this.visible = false;
36268 this.fireEvent("visibilitychange", this, false);
36272 * Shows this region if it was previously hidden.
36275 //if(!this.collapsed){
36278 // this.collapsedEl.show();
36280 this.visible = true;
36281 this.fireEvent("visibilitychange", this, true);
36284 closeClicked : function(){
36285 if(this.activePanel){
36286 this.remove(this.activePanel);
36290 collapseClick : function(e){
36292 e.stopPropagation();
36295 e.stopPropagation();
36301 * Collapses this region.
36302 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
36305 collapse : function(skipAnim, skipCheck = false){
36306 if(this.collapsed) {
36310 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
36312 this.collapsed = true;
36314 this.split.el.hide();
36316 if(this.config.animate && skipAnim !== true){
36317 this.fireEvent("invalidated", this);
36318 this.animateCollapse();
36320 this.el.setLocation(-20000,-20000);
36322 this.collapsedEl.show();
36323 this.fireEvent("collapsed", this);
36324 this.fireEvent("invalidated", this);
36330 animateCollapse : function(){
36335 * Expands this region if it was previously collapsed.
36336 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
36337 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
36340 expand : function(e, skipAnim){
36342 e.stopPropagation();
36344 if(!this.collapsed || this.el.hasActiveFx()) {
36348 this.afterSlideIn();
36351 this.collapsed = false;
36352 if(this.config.animate && skipAnim !== true){
36353 this.animateExpand();
36357 this.split.el.show();
36359 this.collapsedEl.setLocation(-2000,-2000);
36360 this.collapsedEl.hide();
36361 this.fireEvent("invalidated", this);
36362 this.fireEvent("expanded", this);
36366 animateExpand : function(){
36370 initTabs : function()
36372 //this.bodyEl.setStyle("overflow", "hidden"); -- this is set in render?
36374 var ts = new Roo.bootstrap.panel.Tabs({
36375 el: this.bodyEl.dom,
36377 tabPosition: this.tabPosition ? this.tabPosition : 'top',
36378 disableTooltips: this.config.disableTabTips,
36379 toolbar : this.config.toolbar
36382 if(this.config.hideTabs){
36383 ts.stripWrap.setDisplayed(false);
36386 ts.resizeTabs = this.config.resizeTabs === true;
36387 ts.minTabWidth = this.config.minTabWidth || 40;
36388 ts.maxTabWidth = this.config.maxTabWidth || 250;
36389 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
36390 ts.monitorResize = false;
36391 //ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden"); // this is set in render?
36392 ts.bodyEl.addClass('roo-layout-tabs-body');
36393 this.panels.each(this.initPanelAsTab, this);
36396 initPanelAsTab : function(panel){
36397 var ti = this.tabs.addTab(
36401 this.config.closeOnTab && panel.isClosable(),
36404 if(panel.tabTip !== undefined){
36405 ti.setTooltip(panel.tabTip);
36407 ti.on("activate", function(){
36408 this.setActivePanel(panel);
36411 if(this.config.closeOnTab){
36412 ti.on("beforeclose", function(t, e){
36414 this.remove(panel);
36418 panel.tabItem = ti;
36423 updatePanelTitle : function(panel, title)
36425 if(this.activePanel == panel){
36426 this.updateTitle(title);
36429 var ti = this.tabs.getTab(panel.getEl().id);
36431 if(panel.tabTip !== undefined){
36432 ti.setTooltip(panel.tabTip);
36437 updateTitle : function(title){
36438 if(this.titleTextEl && !this.config.title){
36439 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
36443 setActivePanel : function(panel)
36445 panel = this.getPanel(panel);
36446 if(this.activePanel && this.activePanel != panel){
36447 if(this.activePanel.setActiveState(false) === false){
36451 this.activePanel = panel;
36452 panel.setActiveState(true);
36453 if(this.panelSize){
36454 panel.setSize(this.panelSize.width, this.panelSize.height);
36457 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
36459 this.updateTitle(panel.getTitle());
36461 this.fireEvent("invalidated", this);
36463 this.fireEvent("panelactivated", this, panel);
36467 * Shows the specified panel.
36468 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
36469 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
36471 showPanel : function(panel)
36473 panel = this.getPanel(panel);
36476 var tab = this.tabs.getTab(panel.getEl().id);
36477 if(tab.isHidden()){
36478 this.tabs.unhideTab(tab.id);
36482 this.setActivePanel(panel);
36489 * Get the active panel for this region.
36490 * @return {Roo.ContentPanel} The active panel or null
36492 getActivePanel : function(){
36493 return this.activePanel;
36496 validateVisibility : function(){
36497 if(this.panels.getCount() < 1){
36498 this.updateTitle(" ");
36499 this.closeBtn.hide();
36502 if(!this.isVisible()){
36509 * Adds the passed ContentPanel(s) to this region.
36510 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
36511 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
36513 add : function(panel)
36515 if(arguments.length > 1){
36516 for(var i = 0, len = arguments.length; i < len; i++) {
36517 this.add(arguments[i]);
36522 // if we have not been rendered yet, then we can not really do much of this..
36523 if (!this.bodyEl) {
36524 this.unrendered_panels.push(panel);
36531 if(this.hasPanel(panel)){
36532 this.showPanel(panel);
36535 panel.setRegion(this);
36536 this.panels.add(panel);
36537 /* if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
36538 // sinle panel - no tab...?? would it not be better to render it with the tabs,
36539 // and hide them... ???
36540 this.bodyEl.dom.appendChild(panel.getEl().dom);
36541 if(panel.background !== true){
36542 this.setActivePanel(panel);
36544 this.fireEvent("paneladded", this, panel);
36551 this.initPanelAsTab(panel);
36555 if(panel.background !== true){
36556 this.tabs.activate(panel.getEl().id);
36558 this.fireEvent("paneladded", this, panel);
36563 * Hides the tab for the specified panel.
36564 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36566 hidePanel : function(panel){
36567 if(this.tabs && (panel = this.getPanel(panel))){
36568 this.tabs.hideTab(panel.getEl().id);
36573 * Unhides the tab for a previously hidden panel.
36574 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36576 unhidePanel : function(panel){
36577 if(this.tabs && (panel = this.getPanel(panel))){
36578 this.tabs.unhideTab(panel.getEl().id);
36582 clearPanels : function(){
36583 while(this.panels.getCount() > 0){
36584 this.remove(this.panels.first());
36589 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
36590 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
36591 * @param {Boolean} preservePanel Overrides the config preservePanel option
36592 * @return {Roo.ContentPanel} The panel that was removed
36594 remove : function(panel, preservePanel)
36596 panel = this.getPanel(panel);
36601 this.fireEvent("beforeremove", this, panel, e);
36602 if(e.cancel === true){
36605 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
36606 var panelId = panel.getId();
36607 this.panels.removeKey(panelId);
36609 document.body.appendChild(panel.getEl().dom);
36612 this.tabs.removeTab(panel.getEl().id);
36613 }else if (!preservePanel){
36614 this.bodyEl.dom.removeChild(panel.getEl().dom);
36616 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
36617 var p = this.panels.first();
36618 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
36619 tempEl.appendChild(p.getEl().dom);
36620 this.bodyEl.update("");
36621 this.bodyEl.dom.appendChild(p.getEl().dom);
36623 this.updateTitle(p.getTitle());
36625 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
36626 this.setActivePanel(p);
36628 panel.setRegion(null);
36629 if(this.activePanel == panel){
36630 this.activePanel = null;
36632 if(this.config.autoDestroy !== false && preservePanel !== true){
36633 try{panel.destroy();}catch(e){}
36635 this.fireEvent("panelremoved", this, panel);
36640 * Returns the TabPanel component used by this region
36641 * @return {Roo.TabPanel}
36643 getTabs : function(){
36647 createTool : function(parentEl, className){
36648 var btn = Roo.DomHelper.append(parentEl, {
36650 cls: "x-layout-tools-button",
36653 cls: "roo-layout-tools-button-inner " + className,
36657 btn.addClassOnOver("roo-layout-tools-button-over");
36662 * Ext JS Library 1.1.1
36663 * Copyright(c) 2006-2007, Ext JS, LLC.
36665 * Originally Released Under LGPL - original licence link has changed is not relivant.
36668 * <script type="text/javascript">
36674 * @class Roo.SplitLayoutRegion
36675 * @extends Roo.LayoutRegion
36676 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
36678 Roo.bootstrap.layout.Split = function(config){
36679 this.cursor = config.cursor;
36680 Roo.bootstrap.layout.Split.superclass.constructor.call(this, config);
36683 Roo.extend(Roo.bootstrap.layout.Split, Roo.bootstrap.layout.Region,
36685 splitTip : "Drag to resize.",
36686 collapsibleSplitTip : "Drag to resize. Double click to hide.",
36687 useSplitTips : false,
36689 applyConfig : function(config){
36690 Roo.bootstrap.layout.Split.superclass.applyConfig.call(this, config);
36693 onRender : function(ctr,pos) {
36695 Roo.bootstrap.layout.Split.superclass.onRender.call(this, ctr,pos);
36696 if(!this.config.split){
36701 var splitEl = Roo.DomHelper.append(ctr.dom, {
36703 id: this.el.id + "-split",
36704 cls: "roo-layout-split roo-layout-split-"+this.position,
36707 /** The SplitBar for this region
36708 * @type Roo.SplitBar */
36709 // does not exist yet...
36710 Roo.log([this.position, this.orientation]);
36712 this.split = new Roo.bootstrap.SplitBar({
36713 dragElement : splitEl,
36714 resizingElement: this.el,
36715 orientation : this.orientation
36718 this.split.on("moved", this.onSplitMove, this);
36719 this.split.useShim = this.config.useShim === true;
36720 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
36721 if(this.useSplitTips){
36722 this.split.el.dom.title = this.config.collapsible ? this.collapsibleSplitTip : this.splitTip;
36724 //if(config.collapsible){
36725 // this.split.el.on("dblclick", this.collapse, this);
36728 if(typeof this.config.minSize != "undefined"){
36729 this.split.minSize = this.config.minSize;
36731 if(typeof this.config.maxSize != "undefined"){
36732 this.split.maxSize = this.config.maxSize;
36734 if(this.config.hideWhenEmpty || this.config.hidden || this.config.collapsed){
36735 this.hideSplitter();
36740 getHMaxSize : function(){
36741 var cmax = this.config.maxSize || 10000;
36742 var center = this.mgr.getRegion("center");
36743 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
36746 getVMaxSize : function(){
36747 var cmax = this.config.maxSize || 10000;
36748 var center = this.mgr.getRegion("center");
36749 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
36752 onSplitMove : function(split, newSize){
36753 this.fireEvent("resized", this, newSize);
36757 * Returns the {@link Roo.SplitBar} for this region.
36758 * @return {Roo.SplitBar}
36760 getSplitBar : function(){
36765 this.hideSplitter();
36766 Roo.bootstrap.layout.Split.superclass.hide.call(this);
36769 hideSplitter : function(){
36771 this.split.el.setLocation(-2000,-2000);
36772 this.split.el.hide();
36778 this.split.el.show();
36780 Roo.bootstrap.layout.Split.superclass.show.call(this);
36783 beforeSlide: function(){
36784 if(Roo.isGecko){// firefox overflow auto bug workaround
36785 this.bodyEl.clip();
36787 this.tabs.bodyEl.clip();
36789 if(this.activePanel){
36790 this.activePanel.getEl().clip();
36792 if(this.activePanel.beforeSlide){
36793 this.activePanel.beforeSlide();
36799 afterSlide : function(){
36800 if(Roo.isGecko){// firefox overflow auto bug workaround
36801 this.bodyEl.unclip();
36803 this.tabs.bodyEl.unclip();
36805 if(this.activePanel){
36806 this.activePanel.getEl().unclip();
36807 if(this.activePanel.afterSlide){
36808 this.activePanel.afterSlide();
36814 initAutoHide : function(){
36815 if(this.autoHide !== false){
36816 if(!this.autoHideHd){
36817 var st = new Roo.util.DelayedTask(this.slideIn, this);
36818 this.autoHideHd = {
36819 "mouseout": function(e){
36820 if(!e.within(this.el, true)){
36824 "mouseover" : function(e){
36830 this.el.on(this.autoHideHd);
36834 clearAutoHide : function(){
36835 if(this.autoHide !== false){
36836 this.el.un("mouseout", this.autoHideHd.mouseout);
36837 this.el.un("mouseover", this.autoHideHd.mouseover);
36841 clearMonitor : function(){
36842 Roo.get(document).un("click", this.slideInIf, this);
36845 // these names are backwards but not changed for compat
36846 slideOut : function(){
36847 if(this.isSlid || this.el.hasActiveFx()){
36850 this.isSlid = true;
36851 if(this.collapseBtn){
36852 this.collapseBtn.hide();
36854 this.closeBtnState = this.closeBtn.getStyle('display');
36855 this.closeBtn.hide();
36857 this.stickBtn.show();
36860 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
36861 this.beforeSlide();
36862 this.el.setStyle("z-index", 10001);
36863 this.el.slideIn(this.getSlideAnchor(), {
36864 callback: function(){
36866 this.initAutoHide();
36867 Roo.get(document).on("click", this.slideInIf, this);
36868 this.fireEvent("slideshow", this);
36875 afterSlideIn : function(){
36876 this.clearAutoHide();
36877 this.isSlid = false;
36878 this.clearMonitor();
36879 this.el.setStyle("z-index", "");
36880 if(this.collapseBtn){
36881 this.collapseBtn.show();
36883 this.closeBtn.setStyle('display', this.closeBtnState);
36885 this.stickBtn.hide();
36887 this.fireEvent("slidehide", this);
36890 slideIn : function(cb){
36891 if(!this.isSlid || this.el.hasActiveFx()){
36895 this.isSlid = false;
36896 this.beforeSlide();
36897 this.el.slideOut(this.getSlideAnchor(), {
36898 callback: function(){
36899 this.el.setLeftTop(-10000, -10000);
36901 this.afterSlideIn();
36909 slideInIf : function(e){
36910 if(!e.within(this.el)){
36915 animateCollapse : function(){
36916 this.beforeSlide();
36917 this.el.setStyle("z-index", 20000);
36918 var anchor = this.getSlideAnchor();
36919 this.el.slideOut(anchor, {
36920 callback : function(){
36921 this.el.setStyle("z-index", "");
36922 this.collapsedEl.slideIn(anchor, {duration:.3});
36924 this.el.setLocation(-10000,-10000);
36926 this.fireEvent("collapsed", this);
36933 animateExpand : function(){
36934 this.beforeSlide();
36935 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
36936 this.el.setStyle("z-index", 20000);
36937 this.collapsedEl.hide({
36940 this.el.slideIn(this.getSlideAnchor(), {
36941 callback : function(){
36942 this.el.setStyle("z-index", "");
36945 this.split.el.show();
36947 this.fireEvent("invalidated", this);
36948 this.fireEvent("expanded", this);
36976 getAnchor : function(){
36977 return this.anchors[this.position];
36980 getCollapseAnchor : function(){
36981 return this.canchors[this.position];
36984 getSlideAnchor : function(){
36985 return this.sanchors[this.position];
36988 getAlignAdj : function(){
36989 var cm = this.cmargins;
36990 switch(this.position){
37006 getExpandAdj : function(){
37007 var c = this.collapsedEl, cm = this.cmargins;
37008 switch(this.position){
37010 return [-(cm.right+c.getWidth()+cm.left), 0];
37013 return [cm.right+c.getWidth()+cm.left, 0];
37016 return [0, -(cm.top+cm.bottom+c.getHeight())];
37019 return [0, cm.top+cm.bottom+c.getHeight()];
37025 * Ext JS Library 1.1.1
37026 * Copyright(c) 2006-2007, Ext JS, LLC.
37028 * Originally Released Under LGPL - original licence link has changed is not relivant.
37031 * <script type="text/javascript">
37034 * These classes are private internal classes
37036 Roo.bootstrap.layout.Center = function(config){
37037 config.region = "center";
37038 Roo.bootstrap.layout.Region.call(this, config);
37039 this.visible = true;
37040 this.minWidth = config.minWidth || 20;
37041 this.minHeight = config.minHeight || 20;
37044 Roo.extend(Roo.bootstrap.layout.Center, Roo.bootstrap.layout.Region, {
37046 // center panel can't be hidden
37050 // center panel can't be hidden
37053 getMinWidth: function(){
37054 return this.minWidth;
37057 getMinHeight: function(){
37058 return this.minHeight;
37072 Roo.bootstrap.layout.North = function(config)
37074 config.region = 'north';
37075 config.cursor = 'n-resize';
37077 Roo.bootstrap.layout.Split.call(this, config);
37081 this.split.placement = Roo.bootstrap.SplitBar.TOP;
37082 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37083 this.split.el.addClass("roo-layout-split-v");
37085 var size = config.initialSize || config.height;
37086 if(typeof size != "undefined"){
37087 this.el.setHeight(size);
37090 Roo.extend(Roo.bootstrap.layout.North, Roo.bootstrap.layout.Split,
37092 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37096 getBox : function(){
37097 if(this.collapsed){
37098 return this.collapsedEl.getBox();
37100 var box = this.el.getBox();
37102 box.height += this.split.el.getHeight();
37107 updateBox : function(box){
37108 if(this.split && !this.collapsed){
37109 box.height -= this.split.el.getHeight();
37110 this.split.el.setLeft(box.x);
37111 this.split.el.setTop(box.y+box.height);
37112 this.split.el.setWidth(box.width);
37114 if(this.collapsed){
37115 this.updateBody(box.width, null);
37117 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37125 Roo.bootstrap.layout.South = function(config){
37126 config.region = 'south';
37127 config.cursor = 's-resize';
37128 Roo.bootstrap.layout.Split.call(this, config);
37130 this.split.placement = Roo.bootstrap.SplitBar.BOTTOM;
37131 this.split.orientation = Roo.bootstrap.SplitBar.VERTICAL;
37132 this.split.el.addClass("roo-layout-split-v");
37134 var size = config.initialSize || config.height;
37135 if(typeof size != "undefined"){
37136 this.el.setHeight(size);
37140 Roo.extend(Roo.bootstrap.layout.South, Roo.bootstrap.layout.Split, {
37141 orientation: Roo.bootstrap.SplitBar.VERTICAL,
37142 getBox : function(){
37143 if(this.collapsed){
37144 return this.collapsedEl.getBox();
37146 var box = this.el.getBox();
37148 var sh = this.split.el.getHeight();
37155 updateBox : function(box){
37156 if(this.split && !this.collapsed){
37157 var sh = this.split.el.getHeight();
37160 this.split.el.setLeft(box.x);
37161 this.split.el.setTop(box.y-sh);
37162 this.split.el.setWidth(box.width);
37164 if(this.collapsed){
37165 this.updateBody(box.width, null);
37167 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37171 Roo.bootstrap.layout.East = function(config){
37172 config.region = "east";
37173 config.cursor = "e-resize";
37174 Roo.bootstrap.layout.Split.call(this, config);
37176 this.split.placement = Roo.bootstrap.SplitBar.RIGHT;
37177 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37178 this.split.el.addClass("roo-layout-split-h");
37180 var size = config.initialSize || config.width;
37181 if(typeof size != "undefined"){
37182 this.el.setWidth(size);
37185 Roo.extend(Roo.bootstrap.layout.East, Roo.bootstrap.layout.Split, {
37186 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37187 getBox : function(){
37188 if(this.collapsed){
37189 return this.collapsedEl.getBox();
37191 var box = this.el.getBox();
37193 var sw = this.split.el.getWidth();
37200 updateBox : function(box){
37201 if(this.split && !this.collapsed){
37202 var sw = this.split.el.getWidth();
37204 this.split.el.setLeft(box.x);
37205 this.split.el.setTop(box.y);
37206 this.split.el.setHeight(box.height);
37209 if(this.collapsed){
37210 this.updateBody(null, box.height);
37212 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37216 Roo.bootstrap.layout.West = function(config){
37217 config.region = "west";
37218 config.cursor = "w-resize";
37220 Roo.bootstrap.layout.Split.call(this, config);
37222 this.split.placement = Roo.bootstrap.SplitBar.LEFT;
37223 this.split.orientation = Roo.bootstrap.SplitBar.HORIZONTAL;
37224 this.split.el.addClass("roo-layout-split-h");
37228 Roo.extend(Roo.bootstrap.layout.West, Roo.bootstrap.layout.Split, {
37229 orientation: Roo.bootstrap.SplitBar.HORIZONTAL,
37231 onRender: function(ctr, pos)
37233 Roo.bootstrap.layout.West.superclass.onRender.call(this, ctr,pos);
37234 var size = this.config.initialSize || this.config.width;
37235 if(typeof size != "undefined"){
37236 this.el.setWidth(size);
37240 getBox : function(){
37241 if(this.collapsed){
37242 return this.collapsedEl.getBox();
37244 var box = this.el.getBox();
37246 box.width += this.split.el.getWidth();
37251 updateBox : function(box){
37252 if(this.split && !this.collapsed){
37253 var sw = this.split.el.getWidth();
37255 this.split.el.setLeft(box.x+box.width);
37256 this.split.el.setTop(box.y);
37257 this.split.el.setHeight(box.height);
37259 if(this.collapsed){
37260 this.updateBody(null, box.height);
37262 Roo.bootstrap.layout.Region.prototype.updateBox.call(this, box);
37264 });Roo.namespace("Roo.bootstrap.panel");/*
37266 * Ext JS Library 1.1.1
37267 * Copyright(c) 2006-2007, Ext JS, LLC.
37269 * Originally Released Under LGPL - original licence link has changed is not relivant.
37272 * <script type="text/javascript">
37275 * @class Roo.ContentPanel
37276 * @extends Roo.util.Observable
37277 * A basic ContentPanel element.
37278 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
37279 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
37280 * @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
37281 * @cfg {Boolean} closable True if the panel can be closed/removed
37282 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
37283 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
37284 * @cfg {Toolbar} toolbar A toolbar for this panel
37285 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
37286 * @cfg {String} title The title for this panel
37287 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
37288 * @cfg {String} url Calls {@link #setUrl} with this value
37289 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
37290 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
37291 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
37292 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
37293 * @cfg {Boolean} badges render the badges
37296 * Create a new ContentPanel.
37297 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
37298 * @param {String/Object} config A string to set only the title or a config object
37299 * @param {String} content (optional) Set the HTML content for this panel
37300 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
37302 Roo.bootstrap.panel.Content = function( config){
37304 this.tpl = config.tpl || false;
37306 var el = config.el;
37307 var content = config.content;
37309 if(config.autoCreate){ // xtype is available if this is called from factory
37312 this.el = Roo.get(el);
37313 if(!this.el && config && config.autoCreate){
37314 if(typeof config.autoCreate == "object"){
37315 if(!config.autoCreate.id){
37316 config.autoCreate.id = config.id||el;
37318 this.el = Roo.DomHelper.append(document.body,
37319 config.autoCreate, true);
37321 var elcfg = { tag: "div",
37322 cls: "roo-layout-inactive-content",
37326 elcfg.html = config.html;
37330 this.el = Roo.DomHelper.append(document.body, elcfg , true);
37333 this.closable = false;
37334 this.loaded = false;
37335 this.active = false;
37338 if (config.toolbar && !config.toolbar.el && config.toolbar.xtype) {
37340 this.toolbar = new config.toolbar.xns[config.toolbar.xtype](config.toolbar);
37342 this.wrapEl = this.el; //this.el.wrap();
37344 if (config.toolbar.items) {
37345 ti = config.toolbar.items ;
37346 delete config.toolbar.items ;
37350 this.toolbar.render(this.wrapEl, 'before');
37351 for(var i =0;i < ti.length;i++) {
37352 // Roo.log(['add child', items[i]]);
37353 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37355 this.toolbar.items = nitems;
37356 this.toolbar.el.insertBefore(this.wrapEl.dom.firstChild);
37357 delete config.toolbar;
37361 // xtype created footer. - not sure if will work as we normally have to render first..
37362 if (this.footer && !this.footer.el && this.footer.xtype) {
37363 if (!this.wrapEl) {
37364 this.wrapEl = this.el.wrap();
37367 this.footer.container = this.wrapEl.createChild();
37369 this.footer = Roo.factory(this.footer, Roo);
37374 if(typeof config == "string"){
37375 this.title = config;
37377 Roo.apply(this, config);
37381 this.resizeEl = Roo.get(this.resizeEl, true);
37383 this.resizeEl = this.el;
37385 // handle view.xtype
37393 * Fires when this panel is activated.
37394 * @param {Roo.ContentPanel} this
37398 * @event deactivate
37399 * Fires when this panel is activated.
37400 * @param {Roo.ContentPanel} this
37402 "deactivate" : true,
37406 * Fires when this panel is resized if fitToFrame is true.
37407 * @param {Roo.ContentPanel} this
37408 * @param {Number} width The width after any component adjustments
37409 * @param {Number} height The height after any component adjustments
37415 * Fires when this tab is created
37416 * @param {Roo.ContentPanel} this
37427 if(this.autoScroll){
37428 this.resizeEl.setStyle("overflow", "auto");
37430 // fix randome scrolling
37431 //this.el.on('scroll', function() {
37432 // Roo.log('fix random scolling');
37433 // this.scrollTo('top',0);
37436 content = content || this.content;
37438 this.setContent(content);
37440 if(config && config.url){
37441 this.setUrl(this.url, this.params, this.loadOnce);
37446 Roo.bootstrap.panel.Content.superclass.constructor.call(this);
37448 if (this.view && typeof(this.view.xtype) != 'undefined') {
37449 this.view.el = this.el.appendChild(document.createElement("div"));
37450 this.view = Roo.factory(this.view);
37451 this.view.render && this.view.render(false, '');
37455 this.fireEvent('render', this);
37458 Roo.extend(Roo.bootstrap.panel.Content, Roo.bootstrap.Component, {
37462 setRegion : function(region){
37463 this.region = region;
37464 this.setActiveClass(region && !this.background);
37468 setActiveClass: function(state)
37471 this.el.replaceClass("roo-layout-inactive-content", "roo-layout-active-content");
37472 this.el.setStyle('position','relative');
37474 this.el.replaceClass("roo-layout-active-content", "roo-layout-inactive-content");
37475 this.el.setStyle('position', 'absolute');
37480 * Returns the toolbar for this Panel if one was configured.
37481 * @return {Roo.Toolbar}
37483 getToolbar : function(){
37484 return this.toolbar;
37487 setActiveState : function(active)
37489 this.active = active;
37490 this.setActiveClass(active);
37492 if(this.fireEvent("deactivate", this) === false){
37497 this.fireEvent("activate", this);
37501 * Updates this panel's element
37502 * @param {String} content The new content
37503 * @param {Boolean} loadScripts (optional) true to look for and process scripts
37505 setContent : function(content, loadScripts){
37506 this.el.update(content, loadScripts);
37509 ignoreResize : function(w, h){
37510 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
37513 this.lastSize = {width: w, height: h};
37518 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
37519 * @return {Roo.UpdateManager} The UpdateManager
37521 getUpdateManager : function(){
37522 return this.el.getUpdateManager();
37525 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
37526 * @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:
37529 url: "your-url.php",
37530 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
37531 callback: yourFunction,
37532 scope: yourObject, //(optional scope)
37535 text: "Loading...",
37540 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
37541 * 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.
37542 * @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}
37543 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
37544 * @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.
37545 * @return {Roo.ContentPanel} this
37548 var um = this.el.getUpdateManager();
37549 um.update.apply(um, arguments);
37555 * 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.
37556 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
37557 * @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)
37558 * @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)
37559 * @return {Roo.UpdateManager} The UpdateManager
37561 setUrl : function(url, params, loadOnce){
37562 if(this.refreshDelegate){
37563 this.removeListener("activate", this.refreshDelegate);
37565 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
37566 this.on("activate", this.refreshDelegate);
37567 return this.el.getUpdateManager();
37570 _handleRefresh : function(url, params, loadOnce){
37571 if(!loadOnce || !this.loaded){
37572 var updater = this.el.getUpdateManager();
37573 updater.update(url, params, this._setLoaded.createDelegate(this));
37577 _setLoaded : function(){
37578 this.loaded = true;
37582 * Returns this panel's id
37585 getId : function(){
37590 * Returns this panel's element - used by regiosn to add.
37591 * @return {Roo.Element}
37593 getEl : function(){
37594 return this.wrapEl || this.el;
37599 adjustForComponents : function(width, height)
37601 //Roo.log('adjustForComponents ');
37602 if(this.resizeEl != this.el){
37603 width -= this.el.getFrameWidth('lr');
37604 height -= this.el.getFrameWidth('tb');
37607 var te = this.toolbar.getEl();
37608 te.setWidth(width);
37609 height -= te.getHeight();
37612 var te = this.footer.getEl();
37613 te.setWidth(width);
37614 height -= te.getHeight();
37618 if(this.adjustments){
37619 width += this.adjustments[0];
37620 height += this.adjustments[1];
37622 return {"width": width, "height": height};
37625 setSize : function(width, height){
37626 if(this.fitToFrame && !this.ignoreResize(width, height)){
37627 if(this.fitContainer && this.resizeEl != this.el){
37628 this.el.setSize(width, height);
37630 var size = this.adjustForComponents(width, height);
37631 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
37632 this.fireEvent('resize', this, size.width, size.height);
37637 * Returns this panel's title
37640 getTitle : function(){
37642 if (typeof(this.title) != 'object') {
37647 for (var k in this.title) {
37648 if (!this.title.hasOwnProperty(k)) {
37652 if (k.indexOf('-') >= 0) {
37653 var s = k.split('-');
37654 for (var i = 0; i<s.length; i++) {
37655 t += "<span class='visible-"+s[i]+"'>"+this.title[k]+"</span>";
37658 t += "<span class='visible-"+k+"'>"+this.title[k]+"</span>";
37665 * Set this panel's title
37666 * @param {String} title
37668 setTitle : function(title){
37669 this.title = title;
37671 this.region.updatePanelTitle(this, title);
37676 * Returns true is this panel was configured to be closable
37677 * @return {Boolean}
37679 isClosable : function(){
37680 return this.closable;
37683 beforeSlide : function(){
37685 this.resizeEl.clip();
37688 afterSlide : function(){
37690 this.resizeEl.unclip();
37694 * Force a content refresh from the URL specified in the {@link #setUrl} method.
37695 * Will fail silently if the {@link #setUrl} method has not been called.
37696 * This does not activate the panel, just updates its content.
37698 refresh : function(){
37699 if(this.refreshDelegate){
37700 this.loaded = false;
37701 this.refreshDelegate();
37706 * Destroys this panel
37708 destroy : function(){
37709 this.el.removeAllListeners();
37710 var tempEl = document.createElement("span");
37711 tempEl.appendChild(this.el.dom);
37712 tempEl.innerHTML = "";
37718 * form - if the content panel contains a form - this is a reference to it.
37719 * @type {Roo.form.Form}
37723 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
37724 * This contains a reference to it.
37730 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
37740 * @param {Object} cfg Xtype definition of item to add.
37744 getChildContainer: function () {
37745 return this.getEl();
37750 var ret = new Roo.factory(cfg);
37755 if (cfg.xtype.match(/^Form$/)) {
37758 //if (this.footer) {
37759 // el = this.footer.container.insertSibling(false, 'before');
37761 el = this.el.createChild();
37764 this.form = new Roo.form.Form(cfg);
37767 if ( this.form.allItems.length) {
37768 this.form.render(el.dom);
37772 // should only have one of theses..
37773 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
37774 // views.. should not be just added - used named prop 'view''
37776 cfg.el = this.el.appendChild(document.createElement("div"));
37779 var ret = new Roo.factory(cfg);
37781 ret.render && ret.render(false, ''); // render blank..
37791 * @class Roo.bootstrap.panel.Grid
37792 * @extends Roo.bootstrap.panel.Content
37794 * Create a new GridPanel.
37795 * @cfg {Roo.bootstrap.Table} grid The grid for this panel
37796 * @param {Object} config A the config object
37802 Roo.bootstrap.panel.Grid = function(config)
37806 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
37807 {tag: "div", cls: "roo-layout-grid-wrapper roo-layout-inactive-content"}, true);
37809 config.el = this.wrapper;
37810 //this.el = this.wrapper;
37812 if (config.container) {
37813 // ctor'ed from a Border/panel.grid
37816 this.wrapper.setStyle("overflow", "hidden");
37817 this.wrapper.addClass('roo-grid-container');
37822 if(config.toolbar){
37823 var tool_el = this.wrapper.createChild();
37824 this.toolbar = Roo.factory(config.toolbar);
37826 if (config.toolbar.items) {
37827 ti = config.toolbar.items ;
37828 delete config.toolbar.items ;
37832 this.toolbar.render(tool_el);
37833 for(var i =0;i < ti.length;i++) {
37834 // Roo.log(['add child', items[i]]);
37835 nitems.push(this.toolbar.addxtype(Roo.apply({}, ti[i])));
37837 this.toolbar.items = nitems;
37839 delete config.toolbar;
37842 Roo.bootstrap.panel.Grid.superclass.constructor.call(this, config);
37843 config.grid.scrollBody = true;;
37844 config.grid.monitorWindowResize = false; // turn off autosizing
37845 config.grid.autoHeight = false;
37846 config.grid.autoWidth = false;
37848 this.grid = new config.grid.xns[config.grid.xtype](config.grid);
37850 if (config.background) {
37851 // render grid on panel activation (if panel background)
37852 this.on('activate', function(gp) {
37853 if (!gp.grid.rendered) {
37854 gp.grid.render(this.wrapper);
37855 gp.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37860 this.grid.render(this.wrapper);
37861 this.grid.getGridEl().replaceClass("roo-layout-inactive-content", "roo-layout-component-panel");
37864 //this.wrapper.dom.appendChild(config.grid.getGridEl().dom);
37865 // ??? needed ??? config.el = this.wrapper;
37870 // xtype created footer. - not sure if will work as we normally have to render first..
37871 if (this.footer && !this.footer.el && this.footer.xtype) {
37873 var ctr = this.grid.getView().getFooterPanel(true);
37874 this.footer.dataSource = this.grid.dataSource;
37875 this.footer = Roo.factory(this.footer, Roo);
37876 this.footer.render(ctr);
37886 Roo.extend(Roo.bootstrap.panel.Grid, Roo.bootstrap.panel.Content, {
37887 getId : function(){
37888 return this.grid.id;
37892 * Returns the grid for this panel
37893 * @return {Roo.bootstrap.Table}
37895 getGrid : function(){
37899 setSize : function(width, height){
37900 if(!this.ignoreResize(width, height)){
37901 var grid = this.grid;
37902 var size = this.adjustForComponents(width, height);
37903 var gridel = grid.getGridEl();
37904 gridel.setSize(size.width, size.height);
37906 var thd = grid.getGridEl().select('thead',true).first();
37907 var tbd = grid.getGridEl().select('tbody', true).first();
37909 tbd.setSize(width, height - thd.getHeight());
37918 beforeSlide : function(){
37919 this.grid.getView().scroller.clip();
37922 afterSlide : function(){
37923 this.grid.getView().scroller.unclip();
37926 destroy : function(){
37927 this.grid.destroy();
37929 Roo.bootstrap.panel.Grid.superclass.destroy.call(this);
37934 * @class Roo.bootstrap.panel.Nest
37935 * @extends Roo.bootstrap.panel.Content
37937 * Create a new Panel, that can contain a layout.Border.
37940 * @param {Roo.BorderLayout} layout The layout for this panel
37941 * @param {String/Object} config A string to set only the title or a config object
37943 Roo.bootstrap.panel.Nest = function(config)
37945 // construct with only one argument..
37946 /* FIXME - implement nicer consturctors
37947 if (layout.layout) {
37949 layout = config.layout;
37950 delete config.layout;
37952 if (layout.xtype && !layout.getEl) {
37953 // then layout needs constructing..
37954 layout = Roo.factory(layout, Roo);
37958 config.el = config.layout.getEl();
37960 Roo.bootstrap.panel.Nest.superclass.constructor.call(this, config);
37962 config.layout.monitorWindowResize = false; // turn off autosizing
37963 this.layout = config.layout;
37964 this.layout.getEl().addClass("roo-layout-nested-layout");
37965 this.layout.parent = this;
37972 Roo.extend(Roo.bootstrap.panel.Nest, Roo.bootstrap.panel.Content, {
37974 setSize : function(width, height){
37975 if(!this.ignoreResize(width, height)){
37976 var size = this.adjustForComponents(width, height);
37977 var el = this.layout.getEl();
37978 if (size.height < 1) {
37979 el.setWidth(size.width);
37981 el.setSize(size.width, size.height);
37983 var touch = el.dom.offsetWidth;
37984 this.layout.layout();
37985 // ie requires a double layout on the first pass
37986 if(Roo.isIE && !this.initialized){
37987 this.initialized = true;
37988 this.layout.layout();
37993 // activate all subpanels if not currently active..
37995 setActiveState : function(active){
37996 this.active = active;
37997 this.setActiveClass(active);
38000 this.fireEvent("deactivate", this);
38004 this.fireEvent("activate", this);
38005 // not sure if this should happen before or after..
38006 if (!this.layout) {
38007 return; // should not happen..
38010 for (var r in this.layout.regions) {
38011 reg = this.layout.getRegion(r);
38012 if (reg.getActivePanel()) {
38013 //reg.showPanel(reg.getActivePanel()); // force it to activate..
38014 reg.setActivePanel(reg.getActivePanel());
38017 if (!reg.panels.length) {
38020 reg.showPanel(reg.getPanel(0));
38029 * Returns the nested BorderLayout for this panel
38030 * @return {Roo.BorderLayout}
38032 getLayout : function(){
38033 return this.layout;
38037 * Adds a xtype elements to the layout of the nested panel
38041 xtype : 'ContentPanel',
38048 xtype : 'NestedLayoutPanel',
38054 items : [ ... list of content panels or nested layout panels.. ]
38058 * @param {Object} cfg Xtype definition of item to add.
38060 addxtype : function(cfg) {
38061 return this.layout.addxtype(cfg);
38066 * Ext JS Library 1.1.1
38067 * Copyright(c) 2006-2007, Ext JS, LLC.
38069 * Originally Released Under LGPL - original licence link has changed is not relivant.
38072 * <script type="text/javascript">
38075 * @class Roo.TabPanel
38076 * @extends Roo.util.Observable
38077 * A lightweight tab container.
38081 // basic tabs 1, built from existing content
38082 var tabs = new Roo.TabPanel("tabs1");
38083 tabs.addTab("script", "View Script");
38084 tabs.addTab("markup", "View Markup");
38085 tabs.activate("script");
38087 // more advanced tabs, built from javascript
38088 var jtabs = new Roo.TabPanel("jtabs");
38089 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
38091 // set up the UpdateManager
38092 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
38093 var updater = tab2.getUpdateManager();
38094 updater.setDefaultUrl("ajax1.htm");
38095 tab2.on('activate', updater.refresh, updater, true);
38097 // Use setUrl for Ajax loading
38098 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
38099 tab3.setUrl("ajax2.htm", null, true);
38102 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
38105 jtabs.activate("jtabs-1");
38108 * Create a new TabPanel.
38109 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
38110 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
38112 Roo.bootstrap.panel.Tabs = function(config){
38114 * The container element for this TabPanel.
38115 * @type Roo.Element
38117 this.el = Roo.get(config.el);
38120 if(typeof config == "boolean"){
38121 this.tabPosition = config ? "bottom" : "top";
38123 Roo.apply(this, config);
38127 if(this.tabPosition == "bottom"){
38128 // if tabs are at the bottom = create the body first.
38129 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38130 this.el.addClass("roo-tabs-bottom");
38132 // next create the tabs holders
38134 if (this.tabPosition == "west"){
38136 var reg = this.region; // fake it..
38138 if (!reg.mgr.parent) {
38141 reg = reg.mgr.parent.region;
38143 Roo.log("got nest?");
38145 if (reg.mgr.getRegion('west')) {
38146 var ctrdom = reg.mgr.getRegion('west').bodyEl.dom;
38147 this.stripWrap = Roo.get(this.createStrip(ctrdom ), true);
38148 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38149 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38150 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38158 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
38159 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
38160 this.stripEl.setVisibilityMode(Roo.Element.DISPLAY);
38161 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
38166 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
38169 // finally - if tabs are at the top, then create the body last..
38170 if(this.tabPosition != "bottom"){
38171 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
38172 * @type Roo.Element
38174 this.bodyEl = Roo.get(this.createBody(this.el.dom));
38175 this.el.addClass("roo-tabs-top");
38179 this.bodyEl.setStyle("position", "relative");
38181 this.active = null;
38182 this.activateDelegate = this.activate.createDelegate(this);
38187 * Fires when the active tab changes
38188 * @param {Roo.TabPanel} this
38189 * @param {Roo.TabPanelItem} activePanel The new active tab
38193 * @event beforetabchange
38194 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
38195 * @param {Roo.TabPanel} this
38196 * @param {Object} e Set cancel to true on this object to cancel the tab change
38197 * @param {Roo.TabPanelItem} tab The tab being changed to
38199 "beforetabchange" : true
38202 Roo.EventManager.onWindowResize(this.onResize, this);
38203 this.cpad = this.el.getPadding("lr");
38204 this.hiddenCount = 0;
38207 // toolbar on the tabbar support...
38208 if (this.toolbar) {
38209 alert("no toolbar support yet");
38210 this.toolbar = false;
38212 var tcfg = this.toolbar;
38213 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
38214 this.toolbar = new Roo.Toolbar(tcfg);
38215 if (Roo.isSafari) {
38216 var tbl = tcfg.container.child('table', true);
38217 tbl.setAttribute('width', '100%');
38225 Roo.bootstrap.panel.Tabs.superclass.constructor.call(this);
38228 Roo.extend(Roo.bootstrap.panel.Tabs, Roo.util.Observable, {
38230 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
38232 tabPosition : "top",
38234 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
38236 currentTabWidth : 0,
38238 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
38242 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
38246 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
38248 preferredTabWidth : 175,
38250 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
38252 resizeTabs : false,
38254 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
38256 monitorResize : true,
38258 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
38260 toolbar : false, // set by caller..
38262 region : false, /// set by caller
38264 disableTooltips : true, // not used yet...
38267 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
38268 * @param {String} id The id of the div to use <b>or create</b>
38269 * @param {String} text The text for the tab
38270 * @param {String} content (optional) Content to put in the TabPanelItem body
38271 * @param {Boolean} closable (optional) True to create a close icon on the tab
38272 * @return {Roo.TabPanelItem} The created TabPanelItem
38274 addTab : function(id, text, content, closable, tpl)
38276 var item = new Roo.bootstrap.panel.TabItem({
38280 closable : closable,
38283 this.addTabItem(item);
38285 item.setContent(content);
38291 * Returns the {@link Roo.TabPanelItem} with the specified id/index
38292 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
38293 * @return {Roo.TabPanelItem}
38295 getTab : function(id){
38296 return this.items[id];
38300 * Hides the {@link Roo.TabPanelItem} with the specified id/index
38301 * @param {String/Number} id The id or index of the TabPanelItem to hide.
38303 hideTab : function(id){
38304 var t = this.items[id];
38307 this.hiddenCount++;
38308 this.autoSizeTabs();
38313 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
38314 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
38316 unhideTab : function(id){
38317 var t = this.items[id];
38319 t.setHidden(false);
38320 this.hiddenCount--;
38321 this.autoSizeTabs();
38326 * Adds an existing {@link Roo.TabPanelItem}.
38327 * @param {Roo.TabPanelItem} item The TabPanelItem to add
38329 addTabItem : function(item)
38331 this.items[item.id] = item;
38332 this.items.push(item);
38333 this.autoSizeTabs();
38334 // if(this.resizeTabs){
38335 // item.setWidth(this.currentTabWidth || this.preferredTabWidth);
38336 // this.autoSizeTabs();
38338 // item.autoSize();
38343 * Removes a {@link Roo.TabPanelItem}.
38344 * @param {String/Number} id The id or index of the TabPanelItem to remove.
38346 removeTab : function(id){
38347 var items = this.items;
38348 var tab = items[id];
38349 if(!tab) { return; }
38350 var index = items.indexOf(tab);
38351 if(this.active == tab && items.length > 1){
38352 var newTab = this.getNextAvailable(index);
38357 this.stripEl.dom.removeChild(tab.pnode.dom);
38358 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
38359 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
38361 items.splice(index, 1);
38362 delete this.items[tab.id];
38363 tab.fireEvent("close", tab);
38364 tab.purgeListeners();
38365 this.autoSizeTabs();
38368 getNextAvailable : function(start){
38369 var items = this.items;
38371 // look for a next tab that will slide over to
38372 // replace the one being removed
38373 while(index < items.length){
38374 var item = items[++index];
38375 if(item && !item.isHidden()){
38379 // if one isn't found select the previous tab (on the left)
38382 var item = items[--index];
38383 if(item && !item.isHidden()){
38391 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
38392 * @param {String/Number} id The id or index of the TabPanelItem to disable.
38394 disableTab : function(id){
38395 var tab = this.items[id];
38396 if(tab && this.active != tab){
38402 * Enables a {@link Roo.TabPanelItem} that is disabled.
38403 * @param {String/Number} id The id or index of the TabPanelItem to enable.
38405 enableTab : function(id){
38406 var tab = this.items[id];
38411 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
38412 * @param {String/Number} id The id or index of the TabPanelItem to activate.
38413 * @return {Roo.TabPanelItem} The TabPanelItem.
38415 activate : function(id)
38417 //Roo.log('activite:' + id);
38419 var tab = this.items[id];
38423 if(tab == this.active || tab.disabled){
38427 this.fireEvent("beforetabchange", this, e, tab);
38428 if(e.cancel !== true && !tab.disabled){
38430 this.active.hide();
38432 this.active = this.items[id];
38433 this.active.show();
38434 this.fireEvent("tabchange", this, this.active);
38440 * Gets the active {@link Roo.TabPanelItem}.
38441 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
38443 getActiveTab : function(){
38444 return this.active;
38448 * Updates the tab body element to fit the height of the container element
38449 * for overflow scrolling
38450 * @param {Number} targetHeight (optional) Override the starting height from the elements height
38452 syncHeight : function(targetHeight){
38453 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
38454 var bm = this.bodyEl.getMargins();
38455 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
38456 this.bodyEl.setHeight(newHeight);
38460 onResize : function(){
38461 if(this.monitorResize){
38462 this.autoSizeTabs();
38467 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
38469 beginUpdate : function(){
38470 this.updating = true;
38474 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
38476 endUpdate : function(){
38477 this.updating = false;
38478 this.autoSizeTabs();
38482 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
38484 autoSizeTabs : function()
38486 var count = this.items.length;
38487 var vcount = count - this.hiddenCount;
38490 this.stripEl.hide();
38492 this.stripEl.show();
38495 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
38500 var w = Math.max(this.el.getWidth() - this.cpad, 10);
38501 var availWidth = Math.floor(w / vcount);
38502 var b = this.stripBody;
38503 if(b.getWidth() > w){
38504 var tabs = this.items;
38505 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
38506 if(availWidth < this.minTabWidth){
38507 /*if(!this.sleft){ // incomplete scrolling code
38508 this.createScrollButtons();
38511 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
38514 if(this.currentTabWidth < this.preferredTabWidth){
38515 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
38521 * Returns the number of tabs in this TabPanel.
38524 getCount : function(){
38525 return this.items.length;
38529 * Resizes all the tabs to the passed width
38530 * @param {Number} The new width
38532 setTabWidth : function(width){
38533 this.currentTabWidth = width;
38534 for(var i = 0, len = this.items.length; i < len; i++) {
38535 if(!this.items[i].isHidden()) {
38536 this.items[i].setWidth(width);
38542 * Destroys this TabPanel
38543 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
38545 destroy : function(removeEl){
38546 Roo.EventManager.removeResizeListener(this.onResize, this);
38547 for(var i = 0, len = this.items.length; i < len; i++){
38548 this.items[i].purgeListeners();
38550 if(removeEl === true){
38551 this.el.update("");
38556 createStrip : function(container)
38558 var strip = document.createElement("nav");
38559 strip.className = Roo.bootstrap.version == 4 ?
38560 "navbar-light bg-light" :
38561 "navbar navbar-default"; //"x-tabs-wrap";
38562 container.appendChild(strip);
38566 createStripList : function(strip)
38568 // div wrapper for retard IE
38569 // returns the "tr" element.
38570 strip.innerHTML = '<ul class="nav nav-tabs" role="tablist"></ul>';
38571 //'<div class="x-tabs-strip-wrap">'+
38572 // '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
38573 // '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
38574 return strip.firstChild; //.firstChild.firstChild.firstChild;
38576 createBody : function(container)
38578 var body = document.createElement("div");
38579 Roo.id(body, "tab-body");
38580 //Roo.fly(body).addClass("x-tabs-body");
38581 Roo.fly(body).addClass("tab-content");
38582 container.appendChild(body);
38585 createItemBody :function(bodyEl, id){
38586 var body = Roo.getDom(id);
38588 body = document.createElement("div");
38591 //Roo.fly(body).addClass("x-tabs-item-body");
38592 Roo.fly(body).addClass("tab-pane");
38593 bodyEl.insertBefore(body, bodyEl.firstChild);
38597 createStripElements : function(stripEl, text, closable, tpl)
38599 var td = document.createElement("li"); // was td..
38600 td.className = 'nav-item';
38602 //stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
38605 stripEl.appendChild(td);
38607 td.className = "x-tabs-closable";
38608 if(!this.closeTpl){
38609 this.closeTpl = new Roo.Template(
38610 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38611 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
38612 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
38615 var el = this.closeTpl.overwrite(td, {"text": text});
38616 var close = el.getElementsByTagName("div")[0];
38617 var inner = el.getElementsByTagName("em")[0];
38618 return {"el": el, "close": close, "inner": inner};
38621 // not sure what this is..
38622 // if(!this.tabTpl){
38623 //this.tabTpl = new Roo.Template(
38624 // '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
38625 // '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
38627 // this.tabTpl = new Roo.Template(
38628 // '<a href="#">' +
38629 // '<span unselectable="on"' +
38630 // (this.disableTooltips ? '' : ' title="{text}"') +
38631 // ' >{text}</span></a>'
38637 var template = tpl || this.tabTpl || false;
38640 template = new Roo.Template(
38641 Roo.bootstrap.version == 4 ?
38643 '<a class="nav-link" href="#" unselectable="on"' +
38644 (this.disableTooltips ? '' : ' title="{text}"') +
38647 '<a class="nav-link" href="#">' +
38648 '<span unselectable="on"' +
38649 (this.disableTooltips ? '' : ' title="{text}"') +
38650 ' >{text}</span></a>'
38655 switch (typeof(template)) {
38659 template = new Roo.Template(template);
38665 var el = template.overwrite(td, {"text": text});
38667 var inner = el.getElementsByTagName("span")[0];
38669 return {"el": el, "inner": inner};
38677 * @class Roo.TabPanelItem
38678 * @extends Roo.util.Observable
38679 * Represents an individual item (tab plus body) in a TabPanel.
38680 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
38681 * @param {String} id The id of this TabPanelItem
38682 * @param {String} text The text for the tab of this TabPanelItem
38683 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
38685 Roo.bootstrap.panel.TabItem = function(config){
38687 * The {@link Roo.TabPanel} this TabPanelItem belongs to
38688 * @type Roo.TabPanel
38690 this.tabPanel = config.panel;
38692 * The id for this TabPanelItem
38695 this.id = config.id;
38697 this.disabled = false;
38699 this.text = config.text;
38701 this.loaded = false;
38702 this.closable = config.closable;
38705 * The body element for this TabPanelItem.
38706 * @type Roo.Element
38708 this.bodyEl = Roo.get(this.tabPanel.createItemBody(this.tabPanel.bodyEl.dom, config.id));
38709 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
38710 this.bodyEl.setStyle("display", "block");
38711 this.bodyEl.setStyle("zoom", "1");
38712 //this.hideAction();
38714 var els = this.tabPanel.createStripElements(this.tabPanel.stripEl.dom, config.text, config.closable, config.tpl);
38716 this.el = Roo.get(els.el);
38717 this.inner = Roo.get(els.inner, true);
38718 this.textEl = Roo.bootstrap.version == 4 ?
38719 this.el : Roo.get(this.el.dom.firstChild, true);
38721 this.pnode = this.linode = Roo.get(els.el.parentNode, true);
38722 this.status_node = Roo.bootstrap.version == 4 ? this.el : this.linode;
38725 // this.el.on("mousedown", this.onTabMouseDown, this);
38726 this.el.on("click", this.onTabClick, this);
38728 if(config.closable){
38729 var c = Roo.get(els.close, true);
38730 c.dom.title = this.closeText;
38731 c.addClassOnOver("close-over");
38732 c.on("click", this.closeClick, this);
38738 * Fires when this tab becomes the active tab.
38739 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38740 * @param {Roo.TabPanelItem} this
38744 * @event beforeclose
38745 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
38746 * @param {Roo.TabPanelItem} this
38747 * @param {Object} e Set cancel to true on this object to cancel the close.
38749 "beforeclose": true,
38752 * Fires when this tab is closed.
38753 * @param {Roo.TabPanelItem} this
38757 * @event deactivate
38758 * Fires when this tab is no longer the active tab.
38759 * @param {Roo.TabPanel} tabPanel The parent TabPanel
38760 * @param {Roo.TabPanelItem} this
38762 "deactivate" : true
38764 this.hidden = false;
38766 Roo.bootstrap.panel.TabItem.superclass.constructor.call(this);
38769 Roo.extend(Roo.bootstrap.panel.TabItem, Roo.util.Observable,
38771 purgeListeners : function(){
38772 Roo.util.Observable.prototype.purgeListeners.call(this);
38773 this.el.removeAllListeners();
38776 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
38779 this.status_node.addClass("active");
38782 this.tabPanel.stripWrap.repaint();
38784 this.fireEvent("activate", this.tabPanel, this);
38788 * Returns true if this tab is the active tab.
38789 * @return {Boolean}
38791 isActive : function(){
38792 return this.tabPanel.getActiveTab() == this;
38796 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
38799 this.status_node.removeClass("active");
38801 this.fireEvent("deactivate", this.tabPanel, this);
38804 hideAction : function(){
38805 this.bodyEl.hide();
38806 this.bodyEl.setStyle("position", "absolute");
38807 this.bodyEl.setLeft("-20000px");
38808 this.bodyEl.setTop("-20000px");
38811 showAction : function(){
38812 this.bodyEl.setStyle("position", "relative");
38813 this.bodyEl.setTop("");
38814 this.bodyEl.setLeft("");
38815 this.bodyEl.show();
38819 * Set the tooltip for the tab.
38820 * @param {String} tooltip The tab's tooltip
38822 setTooltip : function(text){
38823 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
38824 this.textEl.dom.qtip = text;
38825 this.textEl.dom.removeAttribute('title');
38827 this.textEl.dom.title = text;
38831 onTabClick : function(e){
38832 e.preventDefault();
38833 this.tabPanel.activate(this.id);
38836 onTabMouseDown : function(e){
38837 e.preventDefault();
38838 this.tabPanel.activate(this.id);
38841 getWidth : function(){
38842 return this.inner.getWidth();
38845 setWidth : function(width){
38846 var iwidth = width - this.linode.getPadding("lr");
38847 this.inner.setWidth(iwidth);
38848 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
38849 this.linode.setWidth(width);
38853 * Show or hide the tab
38854 * @param {Boolean} hidden True to hide or false to show.
38856 setHidden : function(hidden){
38857 this.hidden = hidden;
38858 this.linode.setStyle("display", hidden ? "none" : "");
38862 * Returns true if this tab is "hidden"
38863 * @return {Boolean}
38865 isHidden : function(){
38866 return this.hidden;
38870 * Returns the text for this tab
38873 getText : function(){
38877 autoSize : function(){
38878 //this.el.beginMeasure();
38879 this.textEl.setWidth(1);
38881 * #2804 [new] Tabs in Roojs
38882 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
38884 //this.setWidth(this.textEl.dom.scrollWidth+this.linode.getPadding("lr")+this.inner.getPadding("lr") + 2);
38885 //this.el.endMeasure();
38889 * Sets the text for the tab (Note: this also sets the tooltip text)
38890 * @param {String} text The tab's text and tooltip
38892 setText : function(text){
38894 this.textEl.update(text);
38895 this.setTooltip(text);
38896 //if(!this.tabPanel.resizeTabs){
38897 // this.autoSize();
38901 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
38903 activate : function(){
38904 this.tabPanel.activate(this.id);
38908 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
38910 disable : function(){
38911 if(this.tabPanel.active != this){
38912 this.disabled = true;
38913 this.status_node.addClass("disabled");
38918 * Enables this TabPanelItem if it was previously disabled.
38920 enable : function(){
38921 this.disabled = false;
38922 this.status_node.removeClass("disabled");
38926 * Sets the content for this TabPanelItem.
38927 * @param {String} content The content
38928 * @param {Boolean} loadScripts true to look for and load scripts
38930 setContent : function(content, loadScripts){
38931 this.bodyEl.update(content, loadScripts);
38935 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
38936 * @return {Roo.UpdateManager} The UpdateManager
38938 getUpdateManager : function(){
38939 return this.bodyEl.getUpdateManager();
38943 * Set a URL to be used to load the content for this TabPanelItem.
38944 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
38945 * @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)
38946 * @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)
38947 * @return {Roo.UpdateManager} The UpdateManager
38949 setUrl : function(url, params, loadOnce){
38950 if(this.refreshDelegate){
38951 this.un('activate', this.refreshDelegate);
38953 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
38954 this.on("activate", this.refreshDelegate);
38955 return this.bodyEl.getUpdateManager();
38959 _handleRefresh : function(url, params, loadOnce){
38960 if(!loadOnce || !this.loaded){
38961 var updater = this.bodyEl.getUpdateManager();
38962 updater.update(url, params, this._setLoaded.createDelegate(this));
38967 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
38968 * Will fail silently if the setUrl method has not been called.
38969 * This does not activate the panel, just updates its content.
38971 refresh : function(){
38972 if(this.refreshDelegate){
38973 this.loaded = false;
38974 this.refreshDelegate();
38979 _setLoaded : function(){
38980 this.loaded = true;
38984 closeClick : function(e){
38987 this.fireEvent("beforeclose", this, o);
38988 if(o.cancel !== true){
38989 this.tabPanel.removeTab(this.id);
38993 * The text displayed in the tooltip for the close icon.
38996 closeText : "Close this tab"
38999 * This script refer to:
39000 * Title: International Telephone Input
39001 * Author: Jack O'Connor
39002 * Code version: v12.1.12
39003 * Availability: https://github.com/jackocnr/intl-tel-input.git
39006 Roo.bootstrap.PhoneInputData = function() {
39009 "Afghanistan (افغانستان)",
39014 "Albania (Shqipëri)",
39019 "Algeria (الجزائر)",
39044 "Antigua and Barbuda",
39054 "Armenia (Հայաստան)",
39070 "Austria (Österreich)",
39075 "Azerbaijan (Azərbaycan)",
39085 "Bahrain (البحرين)",
39090 "Bangladesh (বাংলাদেশ)",
39100 "Belarus (Беларусь)",
39105 "Belgium (België)",
39135 "Bosnia and Herzegovina (Босна и Херцеговина)",
39150 "British Indian Ocean Territory",
39155 "British Virgin Islands",
39165 "Bulgaria (България)",
39175 "Burundi (Uburundi)",
39180 "Cambodia (កម្ពុជា)",
39185 "Cameroon (Cameroun)",
39194 ["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"]
39197 "Cape Verde (Kabu Verdi)",
39202 "Caribbean Netherlands",
39213 "Central African Republic (République centrafricaine)",
39233 "Christmas Island",
39239 "Cocos (Keeling) Islands",
39250 "Comoros (جزر القمر)",
39255 "Congo (DRC) (Jamhuri ya Kidemokrasia ya Kongo)",
39260 "Congo (Republic) (Congo-Brazzaville)",
39280 "Croatia (Hrvatska)",
39301 "Czech Republic (Česká republika)",
39306 "Denmark (Danmark)",
39321 "Dominican Republic (República Dominicana)",
39325 ["809", "829", "849"]
39343 "Equatorial Guinea (Guinea Ecuatorial)",
39363 "Falkland Islands (Islas Malvinas)",
39368 "Faroe Islands (Føroyar)",
39389 "French Guiana (Guyane française)",
39394 "French Polynesia (Polynésie française)",
39409 "Georgia (საქართველო)",
39414 "Germany (Deutschland)",
39434 "Greenland (Kalaallit Nunaat)",
39471 "Guinea-Bissau (Guiné Bissau)",
39496 "Hungary (Magyarország)",
39501 "Iceland (Ísland)",
39521 "Iraq (العراق)",
39537 "Israel (ישראל)",
39564 "Jordan (الأردن)",
39569 "Kazakhstan (Казахстан)",
39590 "Kuwait (الكويت)",
39595 "Kyrgyzstan (Кыргызстан)",
39605 "Latvia (Latvija)",
39610 "Lebanon (لبنان)",
39625 "Libya (ليبيا)",
39635 "Lithuania (Lietuva)",
39650 "Macedonia (FYROM) (Македонија)",
39655 "Madagascar (Madagasikara)",
39685 "Marshall Islands",
39695 "Mauritania (موريتانيا)",
39700 "Mauritius (Moris)",
39721 "Moldova (Republica Moldova)",
39731 "Mongolia (Монгол)",
39736 "Montenegro (Crna Gora)",
39746 "Morocco (المغرب)",
39752 "Mozambique (Moçambique)",
39757 "Myanmar (Burma) (မြန်မာ)",
39762 "Namibia (Namibië)",
39777 "Netherlands (Nederland)",
39782 "New Caledonia (Nouvelle-Calédonie)",
39817 "North Korea (조선 민주주의 인민 공화국)",
39822 "Northern Mariana Islands",
39838 "Pakistan (پاکستان)",
39848 "Palestine (فلسطين)",
39858 "Papua New Guinea",
39900 "Réunion (La Réunion)",
39906 "Romania (România)",
39922 "Saint Barthélemy",
39933 "Saint Kitts and Nevis",
39943 "Saint Martin (Saint-Martin (partie française))",
39949 "Saint Pierre and Miquelon (Saint-Pierre-et-Miquelon)",
39954 "Saint Vincent and the Grenadines",
39969 "São Tomé and Príncipe (São Tomé e Príncipe)",
39974 "Saudi Arabia (المملكة العربية السعودية)",
39979 "Senegal (Sénégal)",
40009 "Slovakia (Slovensko)",
40014 "Slovenia (Slovenija)",
40024 "Somalia (Soomaaliya)",
40034 "South Korea (대한민국)",
40039 "South Sudan (جنوب السودان)",
40049 "Sri Lanka (ශ්රී ලංකාව)",
40054 "Sudan (السودان)",
40064 "Svalbard and Jan Mayen",
40075 "Sweden (Sverige)",
40080 "Switzerland (Schweiz)",
40085 "Syria (سوريا)",
40130 "Trinidad and Tobago",
40135 "Tunisia (تونس)",
40140 "Turkey (Türkiye)",
40150 "Turks and Caicos Islands",
40160 "U.S. Virgin Islands",
40170 "Ukraine (Україна)",
40175 "United Arab Emirates (الإمارات العربية المتحدة)",
40197 "Uzbekistan (Oʻzbekiston)",
40207 "Vatican City (Città del Vaticano)",
40218 "Vietnam (Việt Nam)",
40223 "Wallis and Futuna (Wallis-et-Futuna)",
40228 "Western Sahara (الصحراء الغربية)",
40234 "Yemen (اليمن)",
40258 * This script refer to:
40259 * Title: International Telephone Input
40260 * Author: Jack O'Connor
40261 * Code version: v12.1.12
40262 * Availability: https://github.com/jackocnr/intl-tel-input.git
40266 * @class Roo.bootstrap.PhoneInput
40267 * @extends Roo.bootstrap.TriggerField
40268 * An input with International dial-code selection
40270 * @cfg {String} defaultDialCode default '+852'
40271 * @cfg {Array} preferedCountries default []
40274 * Create a new PhoneInput.
40275 * @param {Object} config Configuration options
40278 Roo.bootstrap.PhoneInput = function(config) {
40279 Roo.bootstrap.PhoneInput.superclass.constructor.call(this, config);
40282 Roo.extend(Roo.bootstrap.PhoneInput, Roo.bootstrap.TriggerField, {
40284 listWidth: undefined,
40286 selectedClass: 'active',
40288 invalidClass : "has-warning",
40290 validClass: 'has-success',
40292 allowed: '0123456789',
40297 * @cfg {String} defaultDialCode The default dial code when initializing the input
40299 defaultDialCode: '+852',
40302 * @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
40304 preferedCountries: false,
40306 getAutoCreate : function()
40308 var data = Roo.bootstrap.PhoneInputData();
40309 var align = this.labelAlign || this.parentLabelAlign();
40312 this.allCountries = [];
40313 this.dialCodeMapping = [];
40315 for (var i = 0; i < data.length; i++) {
40317 this.allCountries[i] = {
40321 priority: c[3] || 0,
40322 areaCodes: c[4] || null
40324 this.dialCodeMapping[c[2]] = {
40327 priority: c[3] || 0,
40328 areaCodes: c[4] || null
40340 // type: 'number', -- do not use number - we get the flaky up/down arrows.
40341 maxlength: this.max_length,
40342 cls : 'form-control tel-input',
40343 autocomplete: 'new-password'
40346 var hiddenInput = {
40349 cls: 'hidden-tel-input'
40353 hiddenInput.name = this.name;
40356 if (this.disabled) {
40357 input.disabled = true;
40360 var flag_container = {
40377 cls: this.hasFeedback ? 'has-feedback' : '',
40383 cls: 'dial-code-holder',
40390 cls: 'roo-select2-container input-group',
40397 if (this.fieldLabel.length) {
40400 tooltip: 'This field is required'
40406 cls: 'control-label',
40412 html: this.fieldLabel
40415 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
40421 if(this.indicatorpos == 'right') {
40422 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
40429 if(align == 'left') {
40437 if(this.labelWidth > 12){
40438 label.style = "width: " + this.labelWidth + 'px';
40440 if(this.labelWidth < 13 && this.labelmd == 0){
40441 this.labelmd = this.labelWidth;
40443 if(this.labellg > 0){
40444 label.cls += ' col-lg-' + this.labellg;
40445 input.cls += ' col-lg-' + (12 - this.labellg);
40447 if(this.labelmd > 0){
40448 label.cls += ' col-md-' + this.labelmd;
40449 container.cls += ' col-md-' + (12 - this.labelmd);
40451 if(this.labelsm > 0){
40452 label.cls += ' col-sm-' + this.labelsm;
40453 container.cls += ' col-sm-' + (12 - this.labelsm);
40455 if(this.labelxs > 0){
40456 label.cls += ' col-xs-' + this.labelxs;
40457 container.cls += ' col-xs-' + (12 - this.labelxs);
40467 var settings = this;
40469 ['xs','sm','md','lg'].map(function(size){
40470 if (settings[size]) {
40471 cfg.cls += ' col-' + size + '-' + settings[size];
40475 this.store = new Roo.data.Store({
40476 proxy : new Roo.data.MemoryProxy({}),
40477 reader : new Roo.data.JsonReader({
40488 'name' : 'dialCode',
40492 'name' : 'priority',
40496 'name' : 'areaCodes',
40503 if(!this.preferedCountries) {
40504 this.preferedCountries = [
40511 var p = this.preferedCountries.reverse();
40514 for (var i = 0; i < p.length; i++) {
40515 for (var j = 0; j < this.allCountries.length; j++) {
40516 if(this.allCountries[j].iso2 == p[i]) {
40517 var t = this.allCountries[j];
40518 this.allCountries.splice(j,1);
40519 this.allCountries.unshift(t);
40525 this.store.proxy.data = {
40527 data: this.allCountries
40533 initEvents : function()
40536 Roo.bootstrap.PhoneInput.superclass.initEvents.call(this);
40538 this.indicator = this.indicatorEl();
40539 this.flag = this.flagEl();
40540 this.dialCodeHolder = this.dialCodeHolderEl();
40542 this.trigger = this.el.select('div.flag-box',true).first();
40543 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40548 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
40549 _this.list.setWidth(lw);
40552 this.list.on('mouseover', this.onViewOver, this);
40553 this.list.on('mousemove', this.onViewMove, this);
40554 this.inputEl().on("keyup", this.onKeyUp, this);
40555 this.inputEl().on("keypress", this.onKeyPress, this);
40557 this.tpl = '<li><a href="#"><div class="flag {iso2}"></div>{name} <span class="dial-code">+{dialCode}</span></a></li>';
40559 this.view = new Roo.View(this.list, this.tpl, {
40560 singleSelect:true, store: this.store, selectedClass: this.selectedClass
40563 this.view.on('click', this.onViewClick, this);
40564 this.setValue(this.defaultDialCode);
40567 onTriggerClick : function(e)
40569 Roo.log('trigger click');
40574 if(this.isExpanded()){
40576 this.hasFocus = false;
40578 this.store.load({});
40579 this.hasFocus = true;
40584 isExpanded : function()
40586 return this.list.isVisible();
40589 collapse : function()
40591 if(!this.isExpanded()){
40595 Roo.get(document).un('mousedown', this.collapseIf, this);
40596 Roo.get(document).un('mousewheel', this.collapseIf, this);
40597 this.fireEvent('collapse', this);
40601 expand : function()
40605 if(this.isExpanded() || !this.hasFocus){
40609 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
40610 this.list.setWidth(lw);
40613 this.restrictHeight();
40615 Roo.get(document).on('mousedown', this.collapseIf, this);
40616 Roo.get(document).on('mousewheel', this.collapseIf, this);
40618 this.fireEvent('expand', this);
40621 restrictHeight : function()
40623 this.list.alignTo(this.inputEl(), this.listAlign);
40624 this.list.alignTo(this.inputEl(), this.listAlign);
40627 onViewOver : function(e, t)
40629 if(this.inKeyMode){
40632 var item = this.view.findItemFromChild(t);
40635 var index = this.view.indexOf(item);
40636 this.select(index, false);
40641 onViewClick : function(view, doFocus, el, e)
40643 var index = this.view.getSelectedIndexes()[0];
40645 var r = this.store.getAt(index);
40648 this.onSelect(r, index);
40650 if(doFocus !== false && !this.blockFocus){
40651 this.inputEl().focus();
40655 onViewMove : function(e, t)
40657 this.inKeyMode = false;
40660 select : function(index, scrollIntoView)
40662 this.selectedIndex = index;
40663 this.view.select(index);
40664 if(scrollIntoView !== false){
40665 var el = this.view.getNode(index);
40667 this.list.scrollChildIntoView(el, false);
40672 createList : function()
40674 this.list = Roo.get(document.body).createChild({
40676 cls: 'typeahead typeahead-long dropdown-menu tel-list',
40677 style: 'display:none'
40680 this.list.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
40683 collapseIf : function(e)
40685 var in_combo = e.within(this.el);
40686 var in_list = e.within(this.list);
40687 var is_list = (Roo.get(e.getTarget()).id == this.list.id) ? true : false;
40689 if (in_combo || in_list || is_list) {
40695 onSelect : function(record, index)
40697 if(this.fireEvent('beforeselect', this, record, index) !== false){
40699 this.setFlagClass(record.data.iso2);
40700 this.setDialCode(record.data.dialCode);
40701 this.hasFocus = false;
40703 this.fireEvent('select', this, record, index);
40707 flagEl : function()
40709 var flag = this.el.select('div.flag',true).first();
40716 dialCodeHolderEl : function()
40718 var d = this.el.select('input.dial-code-holder',true).first();
40725 setDialCode : function(v)
40727 this.dialCodeHolder.dom.value = '+'+v;
40730 setFlagClass : function(n)
40732 this.flag.dom.className = 'flag '+n;
40735 getValue : function()
40737 var v = this.inputEl().getValue();
40738 if(this.dialCodeHolder) {
40739 v = this.dialCodeHolder.dom.value+this.inputEl().getValue();
40744 setValue : function(v)
40746 var d = this.getDialCode(v);
40748 //invalid dial code
40749 if(v.length == 0 || !d || d.length == 0) {
40751 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
40752 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
40758 this.setFlagClass(this.dialCodeMapping[d].iso2);
40759 this.setDialCode(d);
40760 this.inputEl().dom.value = v.replace('+'+d,'');
40761 this.hiddenEl().dom.value = this.getValue();
40766 getDialCode : function(v)
40770 if (v.length == 0) {
40771 return this.dialCodeHolder.dom.value;
40775 if (v.charAt(0) != "+") {
40778 var numericChars = "";
40779 for (var i = 1; i < v.length; i++) {
40780 var c = v.charAt(i);
40783 if (this.dialCodeMapping[numericChars]) {
40784 dialCode = v.substr(1, i);
40786 if (numericChars.length == 4) {
40796 this.setValue(this.defaultDialCode);
40800 hiddenEl : function()
40802 return this.el.select('input.hidden-tel-input',true).first();
40805 // after setting val
40806 onKeyUp : function(e){
40807 this.setValue(this.getValue());
40810 onKeyPress : function(e){
40811 if(this.allowed.indexOf(String.fromCharCode(e.getCharCode())) === -1){
40818 * @class Roo.bootstrap.MoneyField
40819 * @extends Roo.bootstrap.ComboBox
40820 * Bootstrap MoneyField class
40823 * Create a new MoneyField.
40824 * @param {Object} config Configuration options
40827 Roo.bootstrap.MoneyField = function(config) {
40829 Roo.bootstrap.MoneyField.superclass.constructor.call(this, config);
40833 Roo.extend(Roo.bootstrap.MoneyField, Roo.bootstrap.ComboBox, {
40836 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40838 allowDecimals : true,
40840 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40842 decimalSeparator : ".",
40844 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40846 decimalPrecision : 0,
40848 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40850 allowNegative : true,
40852 * @cfg {Boolean} allowZero False to blank out if the user enters '0' (defaults to true)
40856 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40858 minValue : Number.NEGATIVE_INFINITY,
40860 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40862 maxValue : Number.MAX_VALUE,
40864 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40866 minText : "The minimum value for this field is {0}",
40868 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40870 maxText : "The maximum value for this field is {0}",
40872 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40873 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40875 nanText : "{0} is not a valid number",
40877 * @cfg {Boolean} castInt (true|false) cast int if true (defalut true)
40881 * @cfg {String} defaults currency of the MoneyField
40882 * value should be in lkey
40884 defaultCurrency : false,
40886 * @cfg {String} thousandsDelimiter Symbol of thousandsDelimiter
40888 thousandsDelimiter : false,
40890 * @cfg {Number} max_length Maximum input field length allowed (defaults to Number.MAX_VALUE)
40901 getAutoCreate : function()
40903 var align = this.labelAlign || this.parentLabelAlign();
40915 cls : 'form-control roo-money-amount-input',
40916 autocomplete: 'new-password'
40919 var hiddenInput = {
40923 cls: 'hidden-number-input'
40926 if(this.max_length) {
40927 input.maxlength = this.max_length;
40931 hiddenInput.name = this.name;
40934 if (this.disabled) {
40935 input.disabled = true;
40938 var clg = 12 - this.inputlg;
40939 var cmd = 12 - this.inputmd;
40940 var csm = 12 - this.inputsm;
40941 var cxs = 12 - this.inputxs;
40945 cls : 'row roo-money-field',
40949 cls : 'roo-money-currency column col-lg-' + clg + ' col-md-' + cmd + ' col-sm-' + csm + ' col-xs-' + cxs,
40953 cls: 'roo-select2-container input-group',
40957 cls : 'form-control roo-money-currency-input',
40958 autocomplete: 'new-password',
40960 name : this.currencyName
40964 cls : 'input-group-addon',
40978 cls : 'roo-money-amount column col-lg-' + this.inputlg + ' col-md-' + this.inputmd + ' col-sm-' + this.inputsm + ' col-xs-' + this.inputxs,
40982 cls: this.hasFeedback ? 'has-feedback' : '',
40993 if (this.fieldLabel.length) {
40996 tooltip: 'This field is required'
41002 cls: 'control-label',
41008 html: this.fieldLabel
41011 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star left-indicator';
41017 if(this.indicatorpos == 'right') {
41018 indicator.cls = 'roo-required-indicator text-danger fa fa-lg fa-star right-indicator';
41025 if(align == 'left') {
41033 if(this.labelWidth > 12){
41034 label.style = "width: " + this.labelWidth + 'px';
41036 if(this.labelWidth < 13 && this.labelmd == 0){
41037 this.labelmd = this.labelWidth;
41039 if(this.labellg > 0){
41040 label.cls += ' col-lg-' + this.labellg;
41041 input.cls += ' col-lg-' + (12 - this.labellg);
41043 if(this.labelmd > 0){
41044 label.cls += ' col-md-' + this.labelmd;
41045 container.cls += ' col-md-' + (12 - this.labelmd);
41047 if(this.labelsm > 0){
41048 label.cls += ' col-sm-' + this.labelsm;
41049 container.cls += ' col-sm-' + (12 - this.labelsm);
41051 if(this.labelxs > 0){
41052 label.cls += ' col-xs-' + this.labelxs;
41053 container.cls += ' col-xs-' + (12 - this.labelxs);
41064 var settings = this;
41066 ['xs','sm','md','lg'].map(function(size){
41067 if (settings[size]) {
41068 cfg.cls += ' col-' + size + '-' + settings[size];
41075 initEvents : function()
41077 this.indicator = this.indicatorEl();
41079 this.initCurrencyEvent();
41081 this.initNumberEvent();
41084 initCurrencyEvent : function()
41087 throw "can not find store for combo";
41090 this.store = Roo.factory(this.store, Roo.data);
41091 this.store.parent = this;
41095 this.triggerEl = this.el.select('.input-group-addon', true).first();
41097 this.triggerEl.on("click", this.onTriggerClick, this, { preventDefault : true });
41102 var lw = _this.listWidth || Math.max(_this.inputEl().getWidth(), _this.minListWidth);
41103 _this.list.setWidth(lw);
41106 this.list.on('mouseover', this.onViewOver, this);
41107 this.list.on('mousemove', this.onViewMove, this);
41108 this.list.on('scroll', this.onViewScroll, this);
41111 this.tpl = '<li><a href="#">{' + this.currencyField + '}</a></li>';
41114 this.view = new Roo.View(this.list, this.tpl, {
41115 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41118 this.view.on('click', this.onViewClick, this);
41120 this.store.on('beforeload', this.onBeforeLoad, this);
41121 this.store.on('load', this.onLoad, this);
41122 this.store.on('loadexception', this.onLoadException, this);
41124 this.keyNav = new Roo.KeyNav(this.currencyEl(), {
41125 "up" : function(e){
41126 this.inKeyMode = true;
41130 "down" : function(e){
41131 if(!this.isExpanded()){
41132 this.onTriggerClick();
41134 this.inKeyMode = true;
41139 "enter" : function(e){
41142 if(this.fireEvent("specialkey", this, e)){
41143 this.onViewClick(false);
41149 "esc" : function(e){
41153 "tab" : function(e){
41156 if(this.fireEvent("specialkey", this, e)){
41157 this.onViewClick(false);
41165 doRelay : function(foo, bar, hname){
41166 if(hname == 'down' || this.scope.isExpanded()){
41167 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41175 this.currencyEl().on("click", this.onTriggerClick, this, { preventDefault : true });
41179 initNumberEvent : function(e)
41181 this.inputEl().on("keydown" , this.fireKey, this);
41182 this.inputEl().on("focus", this.onFocus, this);
41183 this.inputEl().on("blur", this.onBlur, this);
41185 this.inputEl().relayEvent('keyup', this);
41187 if(this.indicator){
41188 this.indicator.addClass('invisible');
41191 this.originalValue = this.getValue();
41193 if(this.validationEvent == 'keyup'){
41194 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
41195 this.inputEl().on('keyup', this.filterValidation, this);
41197 else if(this.validationEvent !== false){
41198 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
41201 if(this.selectOnFocus){
41202 this.on("focus", this.preFocus, this);
41205 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
41206 this.inputEl().on("keypress", this.filterKeys, this);
41208 this.inputEl().relayEvent('keypress', this);
41211 var allowed = "0123456789";
41213 if(this.allowDecimals){
41214 allowed += this.decimalSeparator;
41217 if(this.allowNegative){
41221 if(this.thousandsDelimiter) {
41225 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
41227 var keyPress = function(e){
41229 var k = e.getKey();
41231 var c = e.getCharCode();
41234 (String.fromCharCode(c) == '.' || String.fromCharCode(c) == '-') &&
41235 allowed.indexOf(String.fromCharCode(c)) === -1
41241 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
41245 if(allowed.indexOf(String.fromCharCode(c)) === -1){
41250 this.inputEl().on("keypress", keyPress, this);
41254 onTriggerClick : function(e)
41261 this.loadNext = false;
41263 if(this.isExpanded()){
41268 this.hasFocus = true;
41270 if(this.triggerAction == 'all') {
41271 this.doQuery(this.allQuery, true);
41275 this.doQuery(this.getRawValue());
41278 getCurrency : function()
41280 var v = this.currencyEl().getValue();
41285 restrictHeight : function()
41287 this.list.alignTo(this.currencyEl(), this.listAlign);
41288 this.list.alignTo(this.currencyEl(), this.listAlign);
41291 onViewClick : function(view, doFocus, el, e)
41293 var index = this.view.getSelectedIndexes()[0];
41295 var r = this.store.getAt(index);
41298 this.onSelect(r, index);
41302 onSelect : function(record, index){
41304 if(this.fireEvent('beforeselect', this, record, index) !== false){
41306 this.setFromCurrencyData(index > -1 ? record.data : false);
41310 this.fireEvent('select', this, record, index);
41314 setFromCurrencyData : function(o)
41318 this.lastCurrency = o;
41320 if (this.currencyField) {
41321 currency = !o || typeof(o[this.currencyField]) == 'undefined' ? '' : o[this.currencyField];
41323 Roo.log('no currencyField value set for '+ (this.name ? this.name : this.id));
41326 this.lastSelectionText = currency;
41328 //setting default currency
41329 if(o[this.currencyField] * 1 == 0 && this.defaultCurrency) {
41330 this.setCurrency(this.defaultCurrency);
41334 this.setCurrency(currency);
41337 setFromData : function(o)
41341 c[this.currencyField] = !o || typeof(o[this.currencyName]) == 'undefined' ? '' : o[this.currencyName];
41343 this.setFromCurrencyData(c);
41348 value = !o || typeof(o[this.name]) == 'undefined' ? '' : o[this.name];
41350 Roo.log('no value set for '+ (this.name ? this.name : this.id));
41353 this.setValue(value);
41357 setCurrency : function(v)
41359 this.currencyValue = v;
41362 this.currencyEl().dom.value = (v === null || v === undefined ? '' : v);
41367 setValue : function(v)
41369 v = String(this.fixPrecision(v)).replace(".", this.decimalSeparator);
41375 this.hiddenEl().dom.value = (v === null || v === undefined ? '' : v);
41377 this.inputEl().dom.value = (v == '') ? '' :
41378 Roo.util.Format.number(v, this.decimalPrecision, this.thousandsDelimiter || '');
41380 if(!this.allowZero && v === '0') {
41381 this.hiddenEl().dom.value = '';
41382 this.inputEl().dom.value = '';
41389 getRawValue : function()
41391 var v = this.inputEl().getValue();
41396 getValue : function()
41398 return this.fixPrecision(this.parseValue(this.getRawValue()));
41401 parseValue : function(value)
41403 if(this.thousandsDelimiter) {
41405 r = new RegExp(",", "g");
41406 value = value.replace(r, "");
41409 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
41410 return isNaN(value) ? '' : value;
41414 fixPrecision : function(value)
41416 if(this.thousandsDelimiter) {
41418 r = new RegExp(",", "g");
41419 value = value.replace(r, "");
41422 var nan = isNaN(value);
41424 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
41425 return nan ? '' : value;
41427 return parseFloat(value).toFixed(this.decimalPrecision);
41430 decimalPrecisionFcn : function(v)
41432 return Math.floor(v);
41435 validateValue : function(value)
41437 if(!Roo.bootstrap.MoneyField.superclass.validateValue.call(this, value)){
41441 var num = this.parseValue(value);
41444 this.markInvalid(String.format(this.nanText, value));
41448 if(num < this.minValue){
41449 this.markInvalid(String.format(this.minText, this.minValue));
41453 if(num > this.maxValue){
41454 this.markInvalid(String.format(this.maxText, this.maxValue));
41461 validate : function()
41463 if(this.disabled || this.allowBlank){
41468 var currency = this.getCurrency();
41470 if(this.validateValue(this.getRawValue()) && currency.length){
41475 this.markInvalid();
41479 getName: function()
41484 beforeBlur : function()
41490 var v = this.parseValue(this.getRawValue());
41497 onBlur : function()
41501 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
41502 //this.el.removeClass(this.focusClass);
41505 this.hasFocus = false;
41507 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
41511 var v = this.getValue();
41513 if(String(v) !== String(this.startValue)){
41514 this.fireEvent('change', this, v, this.startValue);
41517 this.fireEvent("blur", this);
41520 inputEl : function()
41522 return this.el.select('.roo-money-amount-input', true).first();
41525 currencyEl : function()
41527 return this.el.select('.roo-money-currency-input', true).first();
41530 hiddenEl : function()
41532 return this.el.select('input.hidden-number-input',true).first();
41536 * This script refer to:
41537 * Title: Signature Pad
41539 * Availability: https://github.com/szimek/signature_pad
41543 * @class Roo.bootstrap.BezierSignature
41544 * @extends Roo.bootstrap.Component
41545 * Bootstrap BezierSignature class
41548 * Create a new BezierSignature
41549 * @param {Object} config The config object
41552 Roo.bootstrap.BezierSignature = function(config){
41553 Roo.bootstrap.BezierSignature.superclass.constructor.call(this, config);
41559 Roo.extend(Roo.bootstrap.BezierSignature, Roo.bootstrap.Component, {
41565 mouse_btn_down: true,
41568 * @cfg(int) canvas height
41570 canvas_height: '200px',
41573 * @cfg(float or function) Radius of a single dot.
41578 * @cfg(float) Minimum width of a line. Defaults to 0.5.
41583 * @cfg(float) Maximum width of a line. Defaults to 2.5.
41588 * @cfg(integer) Draw the next point at most once per every x milliseconds. Set it to 0 to turn off throttling. Defaults to 16.
41593 * @cfg(integer) Add the next point only if the previous one is farther than x pixels. Defaults to 5.
41598 * @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.
41600 bg_color: 'rgba(0, 0, 0, 0)',
41603 * @cfg(string) Color used to draw the lines. Can be any color format accepted by context.fillStyle. Defaults to "black".
41605 dot_color: 'black',
41608 * @cfg(float) Weight used to modify new velocity based on the previous velocity. Defaults to 0.7.
41610 velocity_filter_weight: 0.7,
41613 * @cfg(function) Callback when stroke begin.
41618 * @cfg(function) Callback when stroke end.
41622 getAutoCreate : function()
41624 var cls = 'roo-signature column';
41627 cls += ' ' + this.cls;
41637 for(var i = 0; i < col_sizes.length; i++) {
41638 if(this[col_sizes[i]]) {
41639 cls += " col-"+col_sizes[i]+"-"+this[col_sizes[i]];
41649 cls: 'roo-signature-body',
41653 cls: 'roo-signature-body-canvas',
41654 height: this.canvas_height,
41655 width: this.canvas_width
41662 style: 'display: none'
41670 initEvents: function()
41672 Roo.bootstrap.BezierSignature.superclass.initEvents.call(this);
41674 var canvas = this.canvasEl();
41676 // mouse && touch event swapping...
41677 canvas.dom.style.touchAction = 'none';
41678 canvas.dom.style.msTouchAction = 'none';
41680 this.mouse_btn_down = false;
41681 canvas.on('mousedown', this._handleMouseDown, this);
41682 canvas.on('mousemove', this._handleMouseMove, this);
41683 Roo.select('html').first().on('mouseup', this._handleMouseUp, this);
41685 if (window.PointerEvent) {
41686 canvas.on('pointerdown', this._handleMouseDown, this);
41687 canvas.on('pointermove', this._handleMouseMove, this);
41688 Roo.select('html').first().on('pointerup', this._handleMouseUp, this);
41691 if ('ontouchstart' in window) {
41692 canvas.on('touchstart', this._handleTouchStart, this);
41693 canvas.on('touchmove', this._handleTouchMove, this);
41694 canvas.on('touchend', this._handleTouchEnd, this);
41697 Roo.EventManager.onWindowResize(this.resize, this, true);
41699 // file input event
41700 this.fileEl().on('change', this.uploadImage, this);
41707 resize: function(){
41709 var canvas = this.canvasEl().dom;
41710 var ctx = this.canvasElCtx();
41711 var img_data = ctx.getImageData(0, 0, canvas.width, canvas.height);
41713 // setting canvas width will clean img data
41716 var style = window.getComputedStyle ?
41717 getComputedStyle(this.el.dom, null) : this.el.dom.currentStyle;
41719 var padding_left = parseInt(style.paddingLeft) || 0;
41720 var padding_right = parseInt(style.paddingRight) || 0;
41722 canvas.width = this.el.dom.clientWidth - padding_left - padding_right;
41724 ctx.putImageData(img_data, 0, 0);
41727 _handleMouseDown: function(e)
41729 if (e.browserEvent.which === 1) {
41730 this.mouse_btn_down = true;
41731 this.strokeBegin(e);
41735 _handleMouseMove: function (e)
41737 if (this.mouse_btn_down) {
41738 this.strokeMoveUpdate(e);
41742 _handleMouseUp: function (e)
41744 if (e.browserEvent.which === 1 && this.mouse_btn_down) {
41745 this.mouse_btn_down = false;
41750 _handleTouchStart: function (e) {
41752 e.preventDefault();
41753 if (e.browserEvent.targetTouches.length === 1) {
41754 // var touch = e.browserEvent.changedTouches[0];
41755 // this.strokeBegin(touch);
41757 this.strokeBegin(e); // assume e catching the correct xy...
41761 _handleTouchMove: function (e) {
41762 e.preventDefault();
41763 // var touch = event.targetTouches[0];
41764 // _this._strokeMoveUpdate(touch);
41765 this.strokeMoveUpdate(e);
41768 _handleTouchEnd: function (e) {
41769 var wasCanvasTouched = e.target === this.canvasEl().dom;
41770 if (wasCanvasTouched) {
41771 e.preventDefault();
41772 // var touch = event.changedTouches[0];
41773 // _this._strokeEnd(touch);
41778 reset: function () {
41779 this._lastPoints = [];
41780 this._lastVelocity = 0;
41781 this._lastWidth = (this.min_width + this.max_width) / 2;
41782 this.canvasElCtx().fillStyle = this.dot_color;
41785 strokeMoveUpdate: function(e)
41787 this.strokeUpdate(e);
41789 if (this.throttle) {
41790 this.throttle(this.strokeUpdate, this.throttle);
41793 this.strokeUpdate(e);
41797 strokeBegin: function(e)
41799 var newPointGroup = {
41800 color: this.dot_color,
41804 if (typeof this.onBegin === 'function') {
41808 this.curve_data.push(newPointGroup);
41810 this.strokeUpdate(e);
41813 strokeUpdate: function(e)
41815 var rect = this.canvasEl().dom.getBoundingClientRect();
41816 var point = new this.Point(e.xy[0] - rect.left, e.xy[1] - rect.top, new Date().getTime());
41817 var lastPointGroup = this.curve_data[this.curve_data.length - 1];
41818 var lastPoints = lastPointGroup.points;
41819 var lastPoint = lastPoints.length > 0 && lastPoints[lastPoints.length - 1];
41820 var isLastPointTooClose = lastPoint
41821 ? point.distanceTo(lastPoint) <= this.min_distance
41823 var color = lastPointGroup.color;
41824 if (!lastPoint || !(lastPoint && isLastPointTooClose)) {
41825 var curve = this.addPoint(point);
41827 this.drawDot({color: color, point: point});
41830 this.drawCurve({color: color, curve: curve});
41840 strokeEnd: function(e)
41842 this.strokeUpdate(e);
41843 if (typeof this.onEnd === 'function') {
41848 addPoint: function (point) {
41849 var _lastPoints = this._lastPoints;
41850 _lastPoints.push(point);
41851 if (_lastPoints.length > 2) {
41852 if (_lastPoints.length === 3) {
41853 _lastPoints.unshift(_lastPoints[0]);
41855 var widths = this.calculateCurveWidths(_lastPoints[1], _lastPoints[2]);
41856 var curve = this.Bezier.fromPoints(_lastPoints, widths, this);
41857 _lastPoints.shift();
41863 calculateCurveWidths: function (startPoint, endPoint) {
41864 var velocity = this.velocity_filter_weight * endPoint.velocityFrom(startPoint) +
41865 (1 - this.velocity_filter_weight) * this._lastVelocity;
41867 var newWidth = Math.max(this.max_width / (velocity + 1), this.min_width);
41870 start: this._lastWidth
41873 this._lastVelocity = velocity;
41874 this._lastWidth = newWidth;
41878 drawDot: function (_a) {
41879 var color = _a.color, point = _a.point;
41880 var ctx = this.canvasElCtx();
41881 var width = typeof this.dot_size === 'function' ? this.dot_size() : this.dot_size;
41883 this.drawCurveSegment(point.x, point.y, width);
41885 ctx.fillStyle = color;
41889 drawCurve: function (_a) {
41890 var color = _a.color, curve = _a.curve;
41891 var ctx = this.canvasElCtx();
41892 var widthDelta = curve.endWidth - curve.startWidth;
41893 var drawSteps = Math.floor(curve.length()) * 2;
41895 ctx.fillStyle = color;
41896 for (var i = 0; i < drawSteps; i += 1) {
41897 var t = i / drawSteps;
41903 var x = uuu * curve.startPoint.x;
41904 x += 3 * uu * t * curve.control1.x;
41905 x += 3 * u * tt * curve.control2.x;
41906 x += ttt * curve.endPoint.x;
41907 var y = uuu * curve.startPoint.y;
41908 y += 3 * uu * t * curve.control1.y;
41909 y += 3 * u * tt * curve.control2.y;
41910 y += ttt * curve.endPoint.y;
41911 var width = curve.startWidth + ttt * widthDelta;
41912 this.drawCurveSegment(x, y, width);
41918 drawCurveSegment: function (x, y, width) {
41919 var ctx = this.canvasElCtx();
41921 ctx.arc(x, y, width, 0, 2 * Math.PI, false);
41922 this.is_empty = false;
41927 var ctx = this.canvasElCtx();
41928 var canvas = this.canvasEl().dom;
41929 ctx.fillStyle = this.bg_color;
41930 ctx.clearRect(0, 0, canvas.width, canvas.height);
41931 ctx.fillRect(0, 0, canvas.width, canvas.height);
41932 this.curve_data = [];
41934 this.is_empty = true;
41939 return this.el.select('input',true).first();
41942 canvasEl: function()
41944 return this.el.select('canvas',true).first();
41947 canvasElCtx: function()
41949 return this.el.select('canvas',true).first().dom.getContext('2d');
41952 getImage: function(type)
41954 if(this.is_empty) {
41959 return this.canvasEl().dom.toDataURL('image/'+type, 1);
41962 drawFromImage: function(img_src)
41964 var img = new Image();
41966 img.onload = function(){
41967 this.canvasElCtx().drawImage(img, 0, 0);
41972 this.is_empty = false;
41975 selectImage: function()
41977 this.fileEl().dom.click();
41980 uploadImage: function(e)
41982 var reader = new FileReader();
41984 reader.onload = function(e){
41985 var img = new Image();
41986 img.onload = function(){
41988 this.canvasElCtx().drawImage(img, 0, 0);
41990 img.src = e.target.result;
41993 reader.readAsDataURL(e.target.files[0]);
41996 // Bezier Point Constructor
41997 Point: (function () {
41998 function Point(x, y, time) {
42001 this.time = time || Date.now();
42003 Point.prototype.distanceTo = function (start) {
42004 return Math.sqrt(Math.pow(this.x - start.x, 2) + Math.pow(this.y - start.y, 2));
42006 Point.prototype.equals = function (other) {
42007 return this.x === other.x && this.y === other.y && this.time === other.time;
42009 Point.prototype.velocityFrom = function (start) {
42010 return this.time !== start.time
42011 ? this.distanceTo(start) / (this.time - start.time)
42018 // Bezier Constructor
42019 Bezier: (function () {
42020 function Bezier(startPoint, control2, control1, endPoint, startWidth, endWidth) {
42021 this.startPoint = startPoint;
42022 this.control2 = control2;
42023 this.control1 = control1;
42024 this.endPoint = endPoint;
42025 this.startWidth = startWidth;
42026 this.endWidth = endWidth;
42028 Bezier.fromPoints = function (points, widths, scope) {
42029 var c2 = this.calculateControlPoints(points[0], points[1], points[2], scope).c2;
42030 var c3 = this.calculateControlPoints(points[1], points[2], points[3], scope).c1;
42031 return new Bezier(points[1], c2, c3, points[2], widths.start, widths.end);
42033 Bezier.calculateControlPoints = function (s1, s2, s3, scope) {
42034 var dx1 = s1.x - s2.x;
42035 var dy1 = s1.y - s2.y;
42036 var dx2 = s2.x - s3.x;
42037 var dy2 = s2.y - s3.y;
42038 var m1 = { x: (s1.x + s2.x) / 2.0, y: (s1.y + s2.y) / 2.0 };
42039 var m2 = { x: (s2.x + s3.x) / 2.0, y: (s2.y + s3.y) / 2.0 };
42040 var l1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
42041 var l2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);
42042 var dxm = m1.x - m2.x;
42043 var dym = m1.y - m2.y;
42044 var k = l2 / (l1 + l2);
42045 var cm = { x: m2.x + dxm * k, y: m2.y + dym * k };
42046 var tx = s2.x - cm.x;
42047 var ty = s2.y - cm.y;
42049 c1: new scope.Point(m1.x + tx, m1.y + ty),
42050 c2: new scope.Point(m2.x + tx, m2.y + ty)
42053 Bezier.prototype.length = function () {
42058 for (var i = 0; i <= steps; i += 1) {
42060 var cx = this.point(t, this.startPoint.x, this.control1.x, this.control2.x, this.endPoint.x);
42061 var cy = this.point(t, this.startPoint.y, this.control1.y, this.control2.y, this.endPoint.y);
42063 var xdiff = cx - px;
42064 var ydiff = cy - py;
42065 length += Math.sqrt(xdiff * xdiff + ydiff * ydiff);
42072 Bezier.prototype.point = function (t, start, c1, c2, end) {
42073 return (start * (1.0 - t) * (1.0 - t) * (1.0 - t))
42074 + (3.0 * c1 * (1.0 - t) * (1.0 - t) * t)
42075 + (3.0 * c2 * (1.0 - t) * t * t)
42076 + (end * t * t * t);
42081 throttle: function(fn, wait) {
42082 if (wait === void 0) { wait = 250; }
42084 var timeout = null;
42088 var later = function () {
42089 previous = Date.now();
42091 result = fn.apply(storedContext, storedArgs);
42093 storedContext = null;
42097 return function wrapper() {
42099 for (var _i = 0; _i < arguments.length; _i++) {
42100 args[_i] = arguments[_i];
42102 var now = Date.now();
42103 var remaining = wait - (now - previous);
42104 storedContext = this;
42106 if (remaining <= 0 || remaining > wait) {
42108 clearTimeout(timeout);
42112 result = fn.apply(storedContext, storedArgs);
42114 storedContext = null;
42118 else if (!timeout) {
42119 timeout = window.setTimeout(later, remaining);